# HG changeset patch # User John W. Eaton # Date 1394215363 18000 # Node ID b83fca22bb4cd4dc052bac915069eed3327800d8 # Parent 2f5685c080e5c5591db55e58ff298a9254ab5ae9# Parent de76baa76aa199f6bc1378c86f3996b6168d942f maint: Periodic merge of gui-release to default. diff -r de76baa76aa1 -r b83fca22bb4c Makefile.am --- a/Makefile.am Fri Mar 07 12:54:16 2014 -0500 +++ b/Makefile.am Fri Mar 07 13:02:43 2014 -0500 @@ -129,6 +129,11 @@ check: all $(MAKE) -C test check +if AMCOND_HAVE_LLVM +check-jit: all + $(MAKE) -C test check-jit +endif + run-octave: run-octave.in Makefile @$(do_subst_script_vals) chmod a+rx "$@" diff -r de76baa76aa1 -r b83fca22bb4c NEWS --- a/NEWS Fri Mar 07 12:54:16 2014 -0500 +++ b/NEWS Fri Mar 07 13:02:43 2014 -0500 @@ -1,3 +1,47 @@ +Summary of important user-visible changes for version 4.2: +--------------------------------------------------------- + + ** Other new functions added in 4.2: + + dir_in_loadpath + numfields + + ** Deprecated functions. + + The following functions have been deprecated in Octave 4.2 and will + be removed from Octave 4.6 (or whatever version is the second major + release after 4.2): + + find_dir_in_path + nfields + + The following functions were deprecated in Octave 3.8 and have been + removed from Octave 4.2. + + default_save_options java_new + gen_doc_cache java_set + interp1q java_unsigned_conversion + isequalwithequalnans javafields + java_convert_matrix javamethods + java_debug re_read_readline_init_file + java_get read_readline_init_file + java_invoke saving_history + + The following keywords were deprecated in Octave 3.8 and have been + removed from Octave 4.2 + + static + + The following configuration variables were deprecated in Octave 3.8 + and have been removed from Octave 4.2 + + CC_VERSION (now GCC_VERSION) + CXX_VERSION (now GXX_VERSION) + + The internal class was deprecated in Octave 3.8 and has + been removed from Octave 4.2. Replacement classes are + (struct array) or for a single structure. + Summary of important user-visible changes for version 4.0: --------------------------------------------------------- @@ -23,7 +67,7 @@ ** Other new functions added in 4.0.0: - validateattributes + validateattributes ** Deprecated functions. diff -r de76baa76aa1 -r b83fca22bb4c build-aux/common.mk --- a/build-aux/common.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/build-aux/common.mk Fri Mar 07 13:02:43 2014 -0500 @@ -107,8 +107,6 @@ # C compiler flags. CC = @CC@ -## FIXME: CC_VERSION is deprecated and should be removed in version 3.12 -CC_VERSION = @CC_VERSION@ GCC_VERSION = @GCC_VERSION@ CPICFLAG = @CPICFLAG@ XTRA_CFLAGS = @XTRA_CFLAGS@ @@ -131,8 +129,6 @@ # C++ compiler flags. CXX = @CXX@ -## FIXME: CXX_VERSION is deprecated and should be removed in version 3.12 -CXX_VERSION = @CXX_VERSION@ GXX_VERSION = @GXX_VERSION@ CXXCPP = @CXXCPP@ CXXPICFLAG = @CXXPICFLAG@ @@ -518,7 +514,6 @@ -e "s|%OCTAVE_CONF_CANONICAL_HOST_TYPE%|\"${canonical_host_type}\"|" \ -e "s|%OCTAVE_CONF_CARBON_LIBS%|\"${CARBON_LIBS}\"|" \ -e "s|%OCTAVE_CONF_CC%|\"${CC}\"|" \ - -e "s|%OCTAVE_CONF_CC_VERSION%|\"${CC_VERSION}\"|" \ -e "s|%OCTAVE_CONF_CCOLAMD_CPPFLAGS%|\"${CCOLAMD_CPPFLAGS}\"|" \ -e "s|%OCTAVE_CONF_CCOLAMD_LDFLAGS%|\"${CCOLAMD_LDFLAGS}\"|" \ -e "s|%OCTAVE_CONF_CCOLAMD_LIBS%|\"${CCOLAMD_LIBS}\"|" \ diff -r de76baa76aa1 -r b83fca22bb4c configure.ac --- a/configure.ac Fri Mar 07 12:54:16 2014 -0500 +++ b/configure.ac Fri Mar 07 13:02:43 2014 -0500 @@ -19,13 +19,13 @@ ### . AC_PREREQ([2.62]) -AC_INIT([GNU Octave], [3.9.0+], [http://octave.org/bugs.html], [octave]) +AC_INIT([GNU Octave], [4.1.0+], [http://octave.org/bugs.html], [octave]) dnl Note that the version number is duplicated here and in AC_INIT dnl because AC_INIT requires it to be static, not computed from dnl shell variables. -OCTAVE_MAJOR_VERSION=3 -OCTAVE_MINOR_VERSION=9 +OCTAVE_MAJOR_VERSION=4 +OCTAVE_MINOR_VERSION=1 OCTAVE_PATCH_VERSION=0+ dnl PACKAGE_VERSION is set by the AC_INIT VERSION arg @@ -329,10 +329,6 @@ fi AC_SUBST(GXX_VERSION) -## FIXME: CXX_VERSION is deprecated and should be removed in Octave version 3.12 -CXX_VERSION=$gxx_version -AC_SUBST(CXX_VERSION) - ### Determine which C compiler to use (we expect to find gcc). AC_PROG_CC @@ -379,10 +375,6 @@ fi AC_SUBST(GCC_VERSION) -## FIXME: CC_VERSION is deprecated and should be removed in Octave version 3.12 -CC_VERSION=$GCC_VERSION -AC_SUBST(CC_VERSION) - ### Also check g++ version number, it might be different from the ## gcc version number. @@ -895,6 +887,7 @@ AC_SUBST(LLVM_CXXFLAGS) AC_SUBST(LLVM_LDFLAGS) AC_SUBST(LLVM_LIBS) +AM_CONDITIONAL([AMCOND_HAVE_LLVM], [test -z "$warn_llvm"]) ### Check for HDF5 library. @@ -2186,7 +2179,7 @@ AC_CHECK_FUNCS([log1p log1pf pipe]) AC_CHECK_FUNCS([realpath resolvepath roundl]) AC_CHECK_FUNCS([select setgrent setpwent siglongjmp strsignal]) -AC_CHECK_FUNCS([tcgetattr tcsetattr tempnam tgammaf toascii]) +AC_CHECK_FUNCS([tcgetattr tcsetattr tgammaf toascii]) AC_CHECK_FUNCS([umask waitpid]) AC_CHECK_FUNCS([_kbhit]) @@ -2845,7 +2838,8 @@ fi AM_CONDITIONAL([AMCOND_BUILD_GUI], [test $build_gui = yes]) -AM_CONDITIONAL([AMCOND_HAVE_QSCINTILLA], [test "$octave_cv_lib_qscintilla" = yes]) +AM_CONDITIONAL([AMCOND_HAVE_QSCINTILLA], + [test "$octave_cv_lib_qscintilla" = yes]) AM_CONDITIONAL([WIN32_TERMINAL], [test $win32_terminal = yes]) AC_SUBST(QT_CPPFLAGS) AC_SUBST(QT_LDFLAGS) diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/container.txi --- a/doc/interpreter/container.txi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/container.txi Fri Mar 07 13:02:43 2014 -0500 @@ -507,7 +507,7 @@ Other functions that can manipulate the fields of a structure are given below. -@DOCSTRING(nfields) +@DOCSTRING(numfields) @DOCSTRING(fieldnames) diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/contributors.in --- a/doc/interpreter/contributors.in Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/contributors.in Fri Mar 07 13:02:43 2014 -0500 @@ -14,6 +14,7 @@ Heinz Bauschke Julien Bect Roman Belov +Markus Bergholz Karl Berry David Billinghurst Don Bindner @@ -86,6 +87,7 @@ Tomislav Goles Keith Goodman Brian Gough +Michael C. Grant Steffen Groot Etienne Grossmann David Grundberg @@ -208,6 +210,7 @@ Michael O'Brien Peter O'Gorman Thorsten Ohl +Kai T. Ohlhus Arno Onken Valentin Ortega-Clavero Luis F. Ortiz @@ -264,6 +267,7 @@ Julian Schnidder Nicol N. Schraudolph Sebastian Schubert +Lasse Schuirmann Ludwig Schwardt Thomas L. Scofield Daniel J. Sebald @@ -280,6 +284,7 @@ Joerg Specht Quentin H. Spencer Christoph Spiel +David Spies Richard Stallman Russell Standish Brett Stewart @@ -323,6 +328,7 @@ Martin Weiser Michael Weitzel David Wells +Joachim Wiesemann Fook Fah Yap Sean Young Michael Zeising diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/func.txi --- a/doc/interpreter/func.txi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/func.txi Fri Mar 07 13:02:43 2014 -0500 @@ -802,7 +802,7 @@ @DOCSTRING(command_line_path) -@DOCSTRING(find_dir_in_path) +@DOCSTRING(dir_in_loadpath) @node Subfunctions @subsection Subfunctions diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/grammar.txi --- a/doc/interpreter/grammar.txi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/grammar.txi Fri Mar 07 13:02:43 2014 -0500 @@ -49,9 +49,8 @@ @item @code{function} @tab @code{global} @tab @code{if} @item @code{methods} @tab @code{otherwise} @tab @code{parfor} @item @code{persistent} @tab @code{properties} @tab @code{return} -@item @code{static} @tab @code{switch} @tab @code{try} -@item @code{until} @tab @code{unwind_protect} @tab @code{unwind_protect_cleanup} -@item @code{while} +@item @code{switch} @tab @code{try} @tab @code{until} +@item @code{unwind_protect} @tab @code{unwind_protect_cleanup} @tab @code{while} @end multitable The function @code{iskeyword} can be used to quickly check whether an diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/macros.texi --- a/doc/interpreter/macros.texi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/macros.texi Fri Mar 07 13:02:43 2014 -0500 @@ -28,14 +28,14 @@ @c which is `XXX'. This looks particularly bad when the macro body is @c single or double-quoted text, such as a property value `"position"' @ifinfo -@rmacro qcode{arg} +@macro qcode{arg} \arg\ -@end rmacro +@end macro @end ifinfo @ifnotinfo -@rmacro qcode{arg} +@macro qcode{arg} @code{\arg\} -@end rmacro +@end macro @end ifnotinfo @c The following macro is used for the on-line help system, but we don't diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/plot.txi --- a/doc/interpreter/plot.txi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/plot.txi Fri Mar 07 13:02:43 2014 -0500 @@ -1233,18 +1233,21 @@ @noindent sets the range of the x-axis for the current axes object in the current -figure to @samp{[-10, 10]}. Additionally, calling set with a graphics -object index as the only argument returns a structure containing the -default values for all the properties for the given object type. For -example, +figure to @samp{[-10, 10]}. + +Default property values can also be queried if the @code{set} function is +called without a value argument. When only one argument is given (a graphic +handle) then a structure with defaults for all properties of the given object +type is returned. For example, @example set (gca ()) @end example @noindent -returns a structure containing the default property values for axes -objects. +returns a structure containing the default property values for axes objects. +If @code{set} is called with two arguments (a graphic handle and a property +name) then only the defaults for the requested property are returned. @DOCSTRING(get) diff -r de76baa76aa1 -r b83fca22bb4c doc/interpreter/var.txi --- a/doc/interpreter/var.txi Fri Mar 07 12:54:16 2014 -0500 +++ b/doc/interpreter/var.txi Fri Mar 07 13:02:43 2014 -0500 @@ -221,8 +221,7 @@ @end example The behavior of persistent variables is equivalent to the behavior of -static variables in C@. The command @code{static} in Octave is also -recognized and is equivalent to @code{persistent}. +static variables in C@. Like global variables, a persistent variable may only be initialized once. For example, after executing the following code diff -r de76baa76aa1 -r b83fca22bb4c libgui/languages/pt_BR.ts diff -r de76baa76aa1 -r b83fca22bb4c libgui/src/m-editor/find-dialog.cc --- a/libgui/src/m-editor/find-dialog.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libgui/src/m-editor/find-dialog.cc Fri Mar 07 13:02:43 2014 -0500 @@ -211,7 +211,8 @@ void find_dialog::find (bool forward) { - int line = -1, col = -1; + int line, col; + line = col = -1; bool do_wrap = _wrap_check_box->isChecked (); bool do_forward = forward; diff -r de76baa76aa1 -r b83fca22bb4c libgui/src/qtinfo/parser.cc --- a/libgui/src/qtinfo/parser.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libgui/src/qtinfo/parser.cc Fri Mar 07 13:02:43 2014 -0500 @@ -501,7 +501,8 @@ void parser::real_position (int pos, QFileInfo & file_info, int & real_pos) { - int header = -1, sum = 0; + int header = -1; + int sum = 0; for (int i = 0; i < _info_file_real_size_list.size (); i++) { info_file_item item = _info_file_real_size_list.at (i); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/Makefile.am diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/__contourc__.cc --- a/libinterp/corefcn/__contourc__.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/__contourc__.cc Fri Mar 07 13:02:43 2014 -0500 @@ -307,10 +307,10 @@ if (args.length () == 4) { - RowVector X = args (0).row_vector_value (); - RowVector Y = args (1).row_vector_value (); - Matrix Z = args (2).matrix_value (); - RowVector L = args (3).row_vector_value (); + RowVector X = args(0).row_vector_value (); + RowVector Y = args(1).row_vector_value (); + Matrix Z = args(2).matrix_value (); + RowVector L = args(3).row_vector_value (); if (! error_state) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/__pchip_deriv__.cc --- a/libinterp/corefcn/__pchip_deriv__.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/__pchip_deriv__.cc Fri Mar 07 13:02:43 2014 -0500 @@ -59,7 +59,7 @@ octave_value retval; const int nargin = args.length (); - bool rows = (nargin == 3 && args (2).uint_value () == 2); + bool rows = (nargin == 3 && args(2).uint_value () == 2); if (nargin >= 2) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/balance.cc --- a/libinterp/corefcn/balance.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/balance.cc Fri Mar 07 13:02:43 2014 -0500 @@ -144,7 +144,8 @@ if (AEPcase) { // Algebraic eigenvalue problem. - bool noperm = false, noscal = false; + bool noperm = false; + bool noscal = false; if (nargin > 1) { std::string a1s = args(1).string_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/besselj.cc --- a/libinterp/corefcn/besselj.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/besselj.cc Fri Mar 07 13:02:43 2014 -0500 @@ -598,7 +598,7 @@ { int idx = nargin == 1 ? 0 : 1; - if (args (idx).is_single_type ()) + if (args(idx).is_single_type ()) { FloatComplexNDArray z = args(idx).float_complex_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/betainc.cc --- a/libinterp/corefcn/betainc.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/betainc.cc Fri Mar 07 13:02:43 2014 -0500 @@ -32,8 +32,6 @@ #include "oct-obj.h" #include "utils.h" -// FIXME: These functions do not need to be dynamically loaded. They should -// be placed elsewhere in the Octave code hierarchy. DEFUN (betainc, args, , "-*- texinfo -*-\n\ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/bsxfun.cc --- a/libinterp/corefcn/bsxfun.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/bsxfun.cc Fri Mar 07 13:02:43 2014 -0500 @@ -201,7 +201,8 @@ bsxfun_builtin_op op = bsxfun_builtin_lookup (name); if (op != bsxfun_builtin_unknown) { - builtin_type_t btyp_a = a.builtin_type (), btyp_b = b.builtin_type (); + builtin_type_t btyp_a = a.builtin_type (); + builtin_type_t btyp_b = b.builtin_type (); // Simplify single/double combinations. if (btyp_a == btyp_float && btyp_b == btyp_double) @@ -351,8 +352,8 @@ || args(0).is_inline_function ())) error ("bsxfun: F must be a string or function handle"); - const octave_value A = args (1); - const octave_value B = args (2); + const octave_value A = args(1); + const octave_value B = args(2); if (func.is_builtin_function () || (func.is_function_handle () diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/cellfun.cc --- a/libinterp/corefcn/cellfun.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/cellfun.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1783,7 +1783,8 @@ NDA parray = array.permute (perm); - octave_idx_type nela = arraydv.numel (), nelc = celldv.numel (); + octave_idx_type nela = arraydv.numel (); + octave_idx_type nelc = celldv.numel (); parray = parray.reshape (dim_vector (nela, nelc)); Cell retval (celldv); @@ -1901,7 +1902,7 @@ octave_value array = args(0); Array dimv; if (nargin > 1) - dimv = args (1).int_vector_value (true); + dimv = args(1).int_vector_value (true); if (error_state) ; @@ -2036,7 +2037,8 @@ if (ivec >= 0) { // Vector split. Use 1D indexing. - octave_idx_type l = 0, nidx = (ivec == 0 ? nridx : ncidx); + octave_idx_type l = 0; + octave_idx_type nidx = (ivec == 0 ? nridx : ncidx); for (octave_idx_type i = 0; i < nidx; i++) { octave_idx_type u = l + d[ivec](i); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/data.cc --- a/libinterp/corefcn/data.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/data.cc Fri Mar 07 13:02:43 2014 -0500 @@ -302,7 +302,8 @@ { octave_value retval; - octave_value arg0 = x, arg1 = y; + octave_value arg0 = x; + octave_value arg1 = y; if (! arg0.is_numeric_type ()) gripe_wrong_type_arg ("hypot", arg0); else if (! arg1.is_numeric_type ()) @@ -1353,6 +1354,11 @@ %!assert (diag ({1}, 2, 3), {1,[],[]; [],[],[]}); %!assert (diag ({1,2}, 3, 4), {1,[],[],[]; [],2,[],[]; [],[],[],[]}); +## Test out-of-range diagonals +%!assert (diag (ones (3,3), 4), zeros (0, 1)) +%!assert (diag (cell (3,3), 4), cell (0, 1)) +%!assert (diag (sparse (ones (3,3)), 4), sparse (zeros (0, 1))) + %% Test input validation %!error diag () %!error diag (1,2,3,4) @@ -1836,7 +1842,7 @@ // and then directly resize. However, for some types there might // be some additional setup needed, and so this should be avoided. - octave_value tmp = args (0); + octave_value tmp = args(0); tmp = tmp.resize (dim_vector (0,0)).resize (dv); if (error_state) @@ -1850,12 +1856,12 @@ // Can't fast return here to skip empty matrices as something // like cat (1,[],single ([])) must return an empty matrix of // the right type. - tmp = do_cat_op (tmp, args (j), ra_idx); + tmp = do_cat_op (tmp, args(j), ra_idx); if (error_state) return retval; - dim_vector dv_tmp = args (j).dims (); + dim_vector dv_tmp = args(j).dims (); if (dim >= dv_len) { @@ -6708,7 +6714,8 @@ if (! error_state) { - octave_value vals = args(1), zero = args (2); + octave_value vals = args(1); + octave_value zero = args(2); switch (vals.builtin_type ()) { @@ -6790,7 +6797,8 @@ else if (idx.extent (n) > n) error ("accumdim: index out of range"); - dim_vector vals_dim = vals.dims (), rdv = vals_dim; + dim_vector vals_dim = vals.dims (); + dim_vector rdv = vals_dim; if (dim < 0) dim = vals.dims ().first_non_singleton (); @@ -6869,7 +6877,8 @@ dim_vector dv = mask.dims (); NDT retval (dv); - bool tscl = tval.numel () == 1, fscl = fval.numel () == 1; + bool tscl = tval.numel () == 1; + bool fscl = fval.numel () == 1; if ((! tscl && tval.dims () != dv) || (! fscl && fval.dims () != dv)) @@ -6879,14 +6888,16 @@ T *rv = retval.fortran_vec (); octave_idx_type n = retval.numel (); - const T *tv = tval.data (), *fv = fval.data (); + const T *tv = tval.data (); + const T *fv = fval.data (); const bool *mv = mask.data (); if (tscl) { if (fscl) { - T ts = tv[0], fs = fv[0]; + T ts = tv[0]; + T fs = fv[0]; for (octave_idx_type i = 0; i < n; i++) rv[i] = mv[i] ? ts : fs; } @@ -6963,7 +6974,8 @@ else { boolNDArray mask = mask_val.bool_array_value (); - octave_value tval = args(1), fval = args(2); + octave_value tval = args(1); + octave_value fval = args(2); if (tval.is_double_type () && fval.is_double_type ()) { if (tval.is_complex_type () || fval.is_complex_type ()) @@ -7241,7 +7253,8 @@ assert (rep.ndims () == 2 && rep.rows () == 2); - octave_idx_type n = rep.columns (), l = 0; + octave_idx_type n = rep.columns (); + octave_idx_type l = 0; for (octave_idx_type i = 0; i < n; i++) { octave_idx_type k = rep(1, i); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/debug.cc --- a/libinterp/corefcn/debug.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/debug.cc Fri Mar 07 13:02:43 2014 -0500 @@ -85,7 +85,6 @@ if (file.eof ()) { // Expected to read the entire file. - retval = buf; } else @@ -99,8 +98,7 @@ static std::deque get_line_offsets (const std::string& buf) { - // This could maybe be smarter. Is deque the right thing to use - // here? + // This could maybe be smarter. Is deque the right thing to use here? std::deque offsets; @@ -207,28 +205,47 @@ if (args.length () == 0) return; - // If we are already in a debugging function. - if (octave_call_stack::caller_user_code ()) - { - idx = 0; - symbol_name = get_user_code ()->name (); - } + if (args(0).is_string ()) + { + // string could be function name or line number + int isint = atoi (args(0).string_value ().c_str ()); + + if (error_state) + return; + + if (isint == 0) + { + // It was a function name + symbol_name = args(0).string_value (); + if (error_state) + return; + idx = 1; + } + else + { + // It was a line number. Need to get function name from debugger. + if (Vdebugging) + { + symbol_name = get_user_code ()->name (); + idx = 0; + } + else + { + error ("%s: no function specified", who); + } + } + } else if (args(0).is_map ()) { - // Problem because parse_dbfunction_params() can only pass out a - // single function - } - else if (args(0).is_string ()) - { - symbol_name = args(0).string_value (); - if (error_state) - return; - idx = 1; + // This is a problem because parse_dbfunction_params() + // can only pass out a single function. + error ("%s: struct input not implemented", who); + return; } else error ("%s: invalid parameter specified", who); - for (int i = idx; i < nargin; i++ ) + for (int i = idx; i < nargin; i++) { if (args(i).is_string ()) { @@ -238,7 +255,7 @@ lines[list_idx++] = line; } else if (args(i).is_map ()) - octave_stdout << who << ": accepting a struct" << std::endl; + octave_stdout << who << ": skipping struct input" << std::endl; else { const NDArray arg = args(i).array_value (); @@ -356,7 +373,6 @@ return retval; } - int bp_table::do_remove_breakpoint_1 (octave_user_code *fcn, const std::string& fname, @@ -522,9 +538,12 @@ void bp_table::do_remove_all_breakpoints (void) { - for (const_bp_set_iterator it = bp_set.begin (); it != bp_set.end (); it++) - remove_all_breakpoints_in_file (*it); - + // Odd loop structure required because delete will invalidate bp_set iterators + for (const_bp_set_iterator it=bp_set.begin (), it_next=it; it != bp_set.end (); it=it_next) + { + ++it_next; + remove_all_breakpoints_in_file (*it); + } tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; } @@ -537,7 +556,7 @@ for (int i = 0; i < slist.length (); i++) { - if (slist (i).string_value () == match) + if (slist(i).string_value () == match) { retval = slist(i).string_value (); break; @@ -547,7 +566,6 @@ return retval; } - bp_table::fname_line_map bp_table::do_get_breakpoint_list (const octave_value_list& fname_list) { @@ -576,7 +594,7 @@ bp_table::intmap bkpts_vec; for (int i = 0; i < len; i++) - bkpts_vec[i] = bkpts (i).double_value (); + bkpts_vec[i] = bkpts(i).double_value (); std::string symbol_name = f->name (); @@ -615,31 +633,36 @@ DEFUN (dbstop, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\")\n\ +@deftypefn {Command} dbstop @var{func}\n\ +@deftypefnx {Command} dbstop @var{func} @var{line}\n\ +@deftypefnx {Command} dbstop @var{func} @var{line1} @var{line2} @dots{}\n\ +@deftypefnx {Command} {} dbstop @var{line} @dots{}\n\ +@deftypefnx {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\")\n\ @deftypefnx {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\", @var{line})\n\ @deftypefnx {Built-in Function} {@var{rline} =} dbstop (\"@var{func}\", @var{line1}, @var{line2}, @dots{})\n\ -Set a breakpoint in function @var{func}.\n\ +@deftypefnx {Built-in Function} {} dbstop (\"@var{func}\", [@var{line1}, @dots{}])\n\ +@deftypefnx {Built-in Function} {} dbstop (@var{line}, @dots{})\n\ +Set a breakpoint at line number @var{line} in function @var{func}.\n\ \n\ Arguments are\n\ \n\ @table @var\n\ @item func\n\ -Function name as a string variable. When already in debug\n\ -mode this should be left out and only the line should be given.\n\ +Function name as a string variable. When already in debug mode this argument\n\ +can be omitted and the current function will be used.\n\ \n\ @item line\n\ -Line number where the breakpoint should be set. Multiple\n\ -lines may be given as separate arguments or as a vector.\n\ +Line number where the breakpoint should be set. Multiple lines may be given\n\ +as separate arguments or as a vector.\n\ @end table\n\ \n\ -When called with a single argument @var{func}, the breakpoint\n\ -is set at the first executable line in the named function.\n\ +When called with a single argument @var{func}, the breakpoint is set at the\n\ +first executable line in the named function.\n\ \n\ -The optional output @var{rline} is the real line number where the\n\ -breakpoint was set. This can differ from specified line if\n\ -the line is not executable. For example, if a breakpoint attempted on a\n\ -blank line then Octave will set the real breakpoint at the\n\ -next executable line.\n\ +The optional output @var{rline} is the real line number where the breakpoint\n\ +was set. This can differ from the specified line if the line is not\n\ +executable. For example, if a breakpoint attempted on a blank line then\n\ +Octave will set the real breakpoint at the next executable line.\n\ @seealso{dbclear, dbstatus, dbstep, debug_on_error, debug_on_warning, debug_on_interrupt}\n\ @end deftypefn") { @@ -660,28 +683,38 @@ DEFUN (dbclear, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} dbclear (\"@var{func}\")\n\ -@deftypefnx {Built-in Function} {} dbclear (\"@var{func}\", @var{line}, @dots{})\n\ +@deftypefn {Command} {} dbclear @var{func}\n\ +@deftypefnx {Command} {} dbclear @var{func} @var{line}\n\ +@deftypefnx {Command} {} dbclear @var{func} @var{line1} @var{line2} @dots{}\n\ +@deftypefnx {Command} {} dbclear @var{line} @dots{}\n\ +@deftypefnx {Command} {} dbclear all\n\ +@deftypefnx {Built-in Function} {} dbclear (\"@var{func}\")\n\ +@deftypefnx {Built-in Function} {} dbclear (\"@var{func}\", @var{line})\n\ +@deftypefnx {Built-in Function} {} dbclear (\"@var{func}\", @var{line1}, @var{line2}, @dots{})\n\ +@deftypefnx {Built-in Function} {} dbclear (\"@var{func}\", [@var{line1}, @dots{}])\n\ @deftypefnx {Built-in Function} {} dbclear (@var{line}, @dots{})\n\ -Delete a breakpoint in the function @var{func}.\n\ +@deftypefnx {Built-in Function} {} dbclear (\"all\")\n\ +Delete a breakpoint at line number @var{line} in the function @var{func}.\n\ \n\ Arguments are\n\ \n\ @table @var\n\ @item func\n\ -Function name as a string variable. When already in debug\n\ -mode this argument should be omitted and only the line number should be\n\ -given.\n\ +Function name as a string variable. When already in debug mode this argument\n\ +can be omitted and the current function will be used.\n\ \n\ @item line\n\ -Line number from which to remove a breakpoint. Multiple\n\ -lines may be given as separate arguments or as a vector.\n\ +Line number from which to remove a breakpoint. Multiple lines may be given\n\ +as separate arguments or as a vector.\n\ @end table\n\ \n\ -When called without a line number specification all breakpoints\n\ -in the named function are cleared.\n\ +When called without a line number specification all breakpoints in the named\n\ +function are cleared.\n\ \n\ If the requested line is not a breakpoint no action is performed.\n\ +\n\ +The special keyword @qcode{\"all\"} will clear all breakpoints from all\n\ +files.\n\ @seealso{dbstop, dbstatus, dbwhere}\n\ @end deftypefn") { @@ -689,10 +722,17 @@ std::string symbol_name = ""; bp_table::intmap lines; + int nargin = args.length (); + parse_dbfunction_params ("dbclear", args, symbol_name, lines); - if (! error_state) - bp_table::remove_breakpoint (symbol_name, lines); + if (nargin == 1 && symbol_name == "all") + bp_table::remove_all_breakpoints (); + else + { + if (! error_state) + bp_table::remove_breakpoint (symbol_name, lines); + } return retval; } @@ -724,6 +764,9 @@ A line number, or vector of line numbers, with a breakpoint.\n\ @end table\n\ \n\ +Note: When @code{dbstatus} is called from the debug prompt within a function,\n\ +the list of breakpoints is automatically trimmed to the breakpoints in the\n\ +current function.\n\ @seealso{dbclear, dbwhere}\n\ @end deftypefn") { @@ -752,11 +795,14 @@ } else { - octave_user_code *dbg_fcn = get_user_code (); - if (dbg_fcn) + if (Vdebugging) { - symbol_name = dbg_fcn->name (); - fcn_list(0) = symbol_name; + octave_user_code *dbg_fcn = get_user_code (); + if (dbg_fcn) + { + symbol_name = dbg_fcn->name (); + fcn_list(0) = symbol_name; + } } bp_list = bp_table::get_breakpoint_list (fcn_list); @@ -844,7 +890,7 @@ if (l > 0) { - octave_stdout << " line " << l << std::endl; + octave_stdout << "line " << l << std::endl; if (have_file) { @@ -855,7 +901,7 @@ } } else - octave_stdout << " " << std::endl; + octave_stdout << "" << std::endl; } else error ("dbwhere: must be inside a user function to use dbwhere\n"); @@ -863,8 +909,6 @@ return retval; } -// Copied and modified from the do_type command in help.cc -// Maybe we could share some code? void do_dbtype (std::ostream& os, const std::string& name, int start, int end) { @@ -876,30 +920,16 @@ if (fs) { - char ch; int line = 1; - bool isnewline = true; + std::string text; - // FIXME: Why not use line-oriented input here [getline()]? - while (fs.get (ch) && line <= end) - { - if (isnewline && line >= start) - { - os << line << "\t"; - isnewline = false; - } - - if (line >= start) - { - os << ch; - } - - if (ch == '\n') - { - line++; - isnewline = true; - } - } + while (std::getline (fs, text) && line <= end) + { + if (line >= start) + os << line << "\t" << text << "\n"; + + line++; + } } else os << "dbtype: unable to open '" << ff << "' for reading!\n"; @@ -946,13 +976,14 @@ dbg_fcn = get_user_code (); if (dbg_fcn) - do_dbtype (octave_stdout, dbg_fcn->name (), 0, - std::numeric_limits::max ()); + do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), + 0, std::numeric_limits::max ()); else error ("dbtype: must be inside a user function to give no arguments to dbtype\n"); + break; - case 1: // (dbtype func) || (dbtype start:end) + case 1: // (dbtype start:end) || (dbtype func) || (dbtype lineno) { std::string arg = argv[1]; @@ -975,28 +1006,51 @@ end = atoi (end_str.c_str ()); if (std::min (start, end) <= 0) - error ("dbtype: start and end lines must be >= 1\n"); + { + error ("dbtype: start and end lines must be >= 1\n"); + break; + } if (start <= end) - do_dbtype (octave_stdout, dbg_fcn->name (), start, end); + do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), + start, end); else error ("dbtype: start line must be less than end line\n"); } } - else // (dbtype func) + else // (dbtype func) || (dbtype lineno) { - dbg_fcn = get_user_code (arg); + int line = atoi (arg.c_str ()); + + if (line == 0) // (dbtype func) + { + dbg_fcn = get_user_code (arg); - if (dbg_fcn) - do_dbtype (octave_stdout, dbg_fcn->name (), 0, - std::numeric_limits::max ()); - else - error ("dbtype: function <%s> not found\n", arg.c_str ()); + if (dbg_fcn) + do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), + 0, std::numeric_limits::max ()); + else + error ("dbtype: function <%s> not found\n", arg.c_str ()); + } + else // (dbtype lineno) + { + if (line <= 0) + { + error ("dbtype: start and end lines must be >= 1\n"); + break; + } + + dbg_fcn = get_user_code (); + + if (dbg_fcn) + do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), + line, line); + } } } break; - case 2: // (dbtype func start:end) , (dbtype func start) + case 2: // (dbtype func start:end) || (dbtype func start) dbg_fcn = get_user_code (argv[1]); if (dbg_fcn) @@ -1023,10 +1077,14 @@ } if (std::min (start, end) <= 0) - error ("dbtype: start and end lines must be >= 1\n"); + { + error ("dbtype: start and end lines must be >= 1\n"); + break; + } if (start <= end) - do_dbtype (octave_stdout, dbg_fcn->name (), start, end); + do_dbtype (octave_stdout, dbg_fcn->fcn_file_name (), + start, end); else error ("dbtype: start line must be less than end line\n"); } @@ -1096,13 +1154,13 @@ { int l_min = std::max (l - n/2, 0); int l_max = l + n/2; - do_dbtype (octave_stdout, dbg_fcn->name (), l_min, l-1); + do_dbtype (octave_stdout, name, l_min, l-1); std::string line = get_file_line (name, l); if (! line.empty ()) octave_stdout << l << "-->\t" << line << std::endl; - do_dbtype (octave_stdout, dbg_fcn->name (), l+1, l_max); + do_dbtype (octave_stdout, name, l+1, l_max); } } else @@ -1166,10 +1224,9 @@ if (! error_state) { - octave_map stk = octave_call_stack::backtrace (nskip, curr_frame); - if (nargout == 0) { + octave_map stk = octave_call_stack::backtrace (nskip, curr_frame); octave_idx_type nframes_to_display = stk.numel (); if (nframes_to_display > 0) @@ -1215,6 +1272,10 @@ } else { + octave_map stk = octave_call_stack::backtrace (nskip, + curr_frame, + false); + retval(1) = curr_frame < 0 ? 1 : curr_frame + 1; retval(0) = stk; } @@ -1309,8 +1370,8 @@ DEFUN (dbup, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} dbup\n\ -@deftypefnx {Built-in Function} {} dbup (@var{n})\n\ +@deftypefn {Command} {} dbup\n\ +@deftypefnx {Command} {} dbup @var{n}\n\ In debugging mode, move up the execution stack @var{n} frames.\n\ If @var{n} is omitted, move up one frame.\n\ @seealso{dbstack, dbdown}\n\ @@ -1325,8 +1386,8 @@ DEFUN (dbdown, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} dbdown\n\ -@deftypefnx {Built-in Function} {} dbdown (@var{n})\n\ +@deftypefn {Command} {} dbdown\n\ +@deftypefnx {Command} {} dbdown @var{n}\n\ In debugging mode, move down the execution stack @var{n} frames.\n\ If @var{n} is omitted, move down one frame.\n\ @seealso{dbstack, dbup}\n\ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/dlmread.cc --- a/libinterp/corefcn/dlmread.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/dlmread.cc Fri Mar 07 13:02:43 2014 -0500 @@ -264,12 +264,15 @@ } // Take a subset if a range was given. - octave_idx_type r0 = 0, c0 = 0, r1 = idx_max-1, c1 = idx_max-1; + octave_idx_type r0 = 0; + octave_idx_type c0 = 0; + octave_idx_type r1 = idx_max-1; + octave_idx_type c1 = idx_max-1; if (nargin > 2) { if (nargin == 3) { - if (!parse_range_spec (args (2), r0, c0, r1, c1)) + if (!parse_range_spec (args(2), r0, c0, r1, c1)) error ("dlmread: error parsing RANGE"); } else if (nargin == 4) @@ -287,7 +290,12 @@ if (!error_state) { - octave_idx_type i = 0, j = 0, r = 1, c = 1, rmax = 0, cmax = 0; + octave_idx_type i = 0; + octave_idx_type j = 0; + octave_idx_type r = 1; + octave_idx_type c = 1; + octave_idx_type rmax = 0; + octave_idx_type cmax = 0; Matrix rdata; ComplexMatrix cdata; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/dot.cc --- a/libinterp/corefcn/dot.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/dot.cc Fri Mar 07 13:02:43 2014 -0500 @@ -128,11 +128,13 @@ return retval; } - octave_value argx = args(0), argy = args(1); + octave_value argx = args(0); + octave_value argy = args(1); if (argx.is_numeric_type () && argy.is_numeric_type ()) { - dim_vector dimx = argx.dims (), dimy = argy.dims (); + dim_vector dimx = argx.dims (); + dim_vector dimy = argy.dims (); bool match = dimx == dimy; if (! match && nargin == 2 && dimx.is_vector () && dimy.is_vector ()) @@ -291,13 +293,18 @@ return retval; } - octave_value argx = args(0), argy = args(1); + octave_value argx = args(0); + octave_value argy = args(1); if (argx.is_numeric_type () && argy.is_numeric_type ()) { - const dim_vector dimx = argx.dims (), dimy = argy.dims (); + const dim_vector dimx = argx.dims (); + const dim_vector dimy = argy.dims (); int nd = dimx.length (); - octave_idx_type m = dimx(0), k = dimx(1), n = dimy(1), np = 1; + octave_idx_type m = dimx(0); + octave_idx_type k = dimx(1); + octave_idx_type n = dimy(1); + octave_idx_type np = 1; bool match = dimy(0) == k && nd == dimy.length (); dim_vector dimz = dim_vector::alloc (nd); dimz(0) = m; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/eig.cc --- a/libinterp/corefcn/eig.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/eig.cc Fri Mar 07 13:02:43 2014 -0500 @@ -62,8 +62,8 @@ octave_value arg_a, arg_b; - octave_idx_type nr_a = 0, nr_b = 0; - octave_idx_type nc_a = 0, nc_b = 0; + octave_idx_type nr_a, nr_b, nc_a, nc_b; + nr_a = nr_b = nc_a = nc_b = 0; arg_a = args(0); nr_a = arg_a.rows (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/file-io.cc --- a/libinterp/corefcn/file-io.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/file-io.cc Fri Mar 07 13:02:43 2014 -0500 @@ -271,7 +271,7 @@ if (nargin == 1) { - int fid = octave_stream_list::get_file_number (args (0)); + int fid = octave_stream_list::get_file_number (args(0)); octave_stream os = octave_stream_list::lookup (fid, "fclear"); @@ -305,7 +305,7 @@ { // FIXME: any way to avoid special case for stdout? - int fid = octave_stream_list::get_file_number (args (0)); + int fid = octave_stream_list::get_file_number (args(0)); if (fid == 1) { @@ -1338,7 +1338,7 @@ tmp_args (0) = 0.0; for (int i = 0; i < nargin; i++) - tmp_args (i+1) = args (i); + tmp_args(i+1) = args(i); return Ffscanf (tmp_args, nargout); } @@ -1404,9 +1404,13 @@ DEFUN (fread, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} fread (@var{fid}, @var{size}, @var{precision}, @var{skip}, @var{arch})\n\ -Read binary data of type @var{precision} from the specified file ID\n\ -@var{fid}.\n\ +@deftypefn {Built-in Function} {@var{val} =} fread (@var{fid})\n\ +@deftypefnx {Built-in Function} {@var{val} =} fread (@var{fid}, @var{size})\n\ +@deftypefnx {Built-in Function} {@var{val} =} fread (@var{fid}, @var{size}, @var{precision})\n\ +@deftypefnx {Built-in Function} {@var{val} =} fread (@var{fid}, @var{size}, @var{precision}, @var{skip})\n\ +@deftypefnx {Built-in Function} {@var{val} =} fread (@var{fid}, @var{size}, @var{precision}, @var{skip}, @var{arch})\n\ +@deftypefnx {Built-in Function} {[@var{val}, @var{count}] =} fread (@dots{})\n\ +Read binary data from the specified file ID @var{fid}.\n\ \n\ The optional argument @var{size} specifies the amount of data to read\n\ and may be one of\n\ @@ -1559,8 +1563,8 @@ IEEE little endian.\n\ @end table\n\ \n\ -The data read from the file is returned in @var{val}, and the number of\n\ -values read is returned in @code{count}\n\ +The output argument @var{val} contains the data read from the file.\n\ +The optional return value @var{count} contains the number of elements read.\n\ @seealso{fwrite, fgets, fgetl, fscanf, fopen}\n\ @end deftypefn") { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/find.cc --- a/libinterp/corefcn/find.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/find.cc Fri Mar 07 13:02:43 2014 -0500 @@ -61,7 +61,8 @@ case 2: { Array jdx (idx.dims ()); - octave_idx_type n = idx.length (), nr = nda.rows (); + octave_idx_type n = idx.length (); + octave_idx_type nr = nda.rows (); for (octave_idx_type i = 0; i < n; i++) { jdx.xelem (i) = idx.xelem (i) / nr; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/gcd.cc --- a/libinterp/corefcn/gcd.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/gcd.cc Fri Mar 07 13:02:43 2014 -0500 @@ -125,8 +125,9 @@ double aa = fabs (a); double bb = fabs (b); - double xx = 0, yy = 1; - double lx = 1, ly = 0; + double xx, lx, yy, ly; + xx = 0, lx = 1; + yy = 1, ly = 0; while (bb != 0) { @@ -161,7 +162,8 @@ (*current_liboctave_error_handler) ("gcd: all complex parts must be integers"); - std::complex aa = a, bb = b; + std::complex aa = a; + std::complex bb = b; bool swapped = false; if (abs (aa) < abs (bb)) { @@ -169,8 +171,9 @@ swapped = true; } - std::complex xx = 0, lx = 1; - std::complex yy = 1, ly = 0; + std::complex xx, lx, yy, ly; + xx = 0, lx = 1; + yy = 1, ly = 0; while (abs(bb) != 0) { @@ -204,8 +207,9 @@ { T aa = a.abs ().value (); T bb = b.abs ().value (); - T xx = 0, lx = 1; - T yy = 1, ly = 0; + T xx, lx, yy, ly; + xx = 0, lx = 1; + yy = 1, ly = 0; while (bb != 0) { @@ -347,7 +351,8 @@ bool incb = bb.numel () != 1; T *gptr = gg.fortran_vec (); - T *xptr = xx.fortran_vec (), *yptr = yy.fortran_vec (); + T *xptr = xx.fortran_vec (); + T *yptr = yy.fortran_vec (); octave_idx_type n = gg.numel (); for (octave_idx_type i = 0; i < n; i++) diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/gl-render.cc --- a/libinterp/corefcn/gl-render.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/gl-render.cc Fri Mar 07 13:02:43 2014 -0500 @@ -147,7 +147,8 @@ { // FIXME: dim_vectors hold octave_idx_type values. // Should we check for dimensions larger than intmax? - int h = dv(0), w = dv(1), tw, th; + int h, w, tw, th; + h = dv(0), w = dv(1); GLuint id; bool ok = true; @@ -436,12 +437,11 @@ = reinterpret_cast (data); //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2)); - // FIXME: why did I need to keep the first vertex of the face - // in JHandles? I think it's related to the fact that the - // tessellation process might re-order the vertices, such that - // the first one you get here might not be the first one of the face; - // but I can't figure out the actual reason. - if (color_mode > 0 && (first || color_mode == 2)) + // NOTE: OpenGL can re-order vertices so "first" is basically meaningless + // in this callback routine. For "flat" coloring of FaceColor the first + // vertex must be identified in the draw_patch routine. + + if (color_mode == 2 || (color_mode == 1 && ! is_filled ())) { Matrix col = v->color; @@ -458,7 +458,7 @@ for (int k = 0; k < 3; k++) buf[k] = (v->diffuse * col(k)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf); } } } @@ -1002,7 +1002,8 @@ Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ()); string_vector xticklabels = props.get_xticklabel ().all_strings (); - int wmax = 0, hmax = 0; + int wmax = 0; + int hmax = 0; bool tick_along_z = nearhoriz || xisinf (fy); bool mirror = props.is_box () && xstate != AXE_ANY_DIR; @@ -1110,7 +1111,8 @@ Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ()); Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ()); string_vector yticklabels = props.get_yticklabel ().all_strings (); - int wmax = 0, hmax = 0; + int wmax = 0; + int hmax = 0; bool tick_along_z = nearhoriz || xisinf (fx); bool mirror = props.is_box () && ystate != AXE_ANY_DIR && (! props.has_property ("__plotyy_axes__")); @@ -1209,7 +1211,8 @@ Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ()); Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ()); string_vector zticklabels = props.get_zticklabel ().all_strings (); - int wmax = 0, hmax = 0; + int wmax = 0; + int hmax = 0; bool mirror = props.is_box () && zstate != AXE_ANY_DIR; set_color (props.get_zcolor_rgb ()); @@ -1562,7 +1565,8 @@ const Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); const Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); - int zr = z.rows (), zc = z.columns (); + int zr = z.rows (); + int zc = z.columns (); NDArray c; const NDArray n = props.get_vertexnormals ().array_value (); @@ -2332,13 +2336,44 @@ tess.begin_polygon (true); tess.begin_contour (); - for (int j = 0; j < count_f(i); j++) + // Add vertices in reverse order for Matlab compatibility + for (int j = count_f(i)-1; j > 0; j--) { vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); tess.add_vertex (vv->coords.fortran_vec (), vv); } + if (count_f(i) > 0) + { + vertex_data::vertex_data_rep *vv = vdata[i].get_rep (); + + if (fc_mode == 1) + { + // For "flat" shading, use color of 1st vertex. + Matrix col = vv->color; + + if (col.numel () == 3) + { + glColor3dv (col.data ()); + if (fl_mode > 0) + { + float cb[4] = { 0, 0, 0, 1 }; + + for (int k = 0; k < 3; k++) + cb[k] = (vv->ambient * col(k)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = (vv->diffuse * col(k)); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + } + + tess.add_vertex (vv->coords.fortran_vec (), vv); + } + tess.end_contour (); tess.end_polygon (); } @@ -2421,7 +2456,7 @@ tess.begin_polygon (false); tess.begin_contour (); - for (int j = 0; j < count_f(i); j++) + for (int j = count_f(i)-1; j >= 0; j--) { vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); @@ -2552,7 +2587,8 @@ { octave_value cdata = props.get_color_data (); dim_vector dv (cdata.dims ()); - int h = dv(0), w = dv(1); + int h = dv(0); + int w = dv(1); Matrix x = props.get_xdata ().matrix_value (); Matrix y = props.get_ydata ().matrix_value (); @@ -2610,8 +2646,9 @@ // viewport/clipping plane so we must do the clipping // ourselfes - only draw part of the image - int j0 = 0, j1 = w; - int i0 = 0, i1 = h; + int j0, j1, i0, i1; + j0 = 0, j1 = w; + i0 = 0, i1 = h; float im_xmin = x(0) - nor_dx/2; float im_xmax = x(1) + nor_dx/2; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/gl2ps-renderer.cc --- a/libinterp/corefcn/gl2ps-renderer.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/gl2ps-renderer.cc Fri Mar 07 13:02:43 2014 -0500 @@ -44,7 +44,8 @@ { in_draw = true; - GLint buffsize = 0, state = GL2PS_OVERFLOW; + GLint buffsize = 0; + GLint state = GL2PS_OVERFLOW; GLint viewport[4]; glGetIntegerv (GL_VIEWPORT, viewport); @@ -222,7 +223,8 @@ set_color (props.get_color_rgb ()); const Matrix pos = get_transform ().scale (props.get_data_position ()); - int halign = 0, valign = 0; + int halign = 0; + int valign = 0; if (props.horizontalalignment_is ("center")) halign = 1; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/graphics.cc --- a/libinterp/corefcn/graphics.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/graphics.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1012,7 +1012,7 @@ for (std::set::const_iterator it = possible_vals.begin (); it != possible_vals.end (); it++) { - if (retval == "") + if (retval.empty ()) { if (*it == default_value ()) retval = "{" + *it + "}"; @@ -1027,8 +1027,10 @@ retval += " | " + *it; } } - if (retval != "") + + if (! retval.empty ()) retval = "[ " + retval + " ]"; + return retval; } @@ -1044,10 +1046,13 @@ } bool -color_values::str2rgb (std::string str) -{ +color_values::str2rgb (const std::string& str_arg) +{ + bool retval = true; + double tmp_rgb[3] = {0, 0, 0}; - bool retval = true; + + std::string str = str_arg; unsigned int len = str.length (); std::transform (str.begin (), str.end (), str.begin (), tolower); @@ -2772,7 +2777,13 @@ // Remove child from current parent graphics_object old_parent_obj; old_parent_obj = gh_manager::get_object (get_parent ()); - old_parent_obj.remove_child (__myhandle__); + + + if (old_parent_obj.get_handle () != hnp) + old_parent_obj.remove_child (__myhandle__); + else + // Do nothing more + return; // Check new parent's parent is not this child to avoid recursion graphics_object new_parent_obj; @@ -2795,6 +2806,18 @@ error ("set: expecting parent to be a graphics handle"); } +/* +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! hax = gca (); +%! set (hax, "parent", gcf ()) +%! assert (gca (), hax) +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect +*/ + void base_properties::mark_modified (void) { @@ -2976,7 +2999,8 @@ } } } - if (retval != "") + + if (! retval.empty ()) retval += "\n"; } else @@ -2985,6 +3009,33 @@ return retval; } +std::string +base_graphics_object::value_as_string (const std::string& prop) +{ + std::string retval; + + if (valid_object ()) + { + if (prop != "children") + { + property p = get_properties ().get_property (prop); + + if (p.ok () && ! p.is_hidden ()) + { + if (p.is_radio ()) + retval += p.values_as_string (); + } + } + + if (! retval.empty ()) + retval += "\n"; + } + else + error ("base_graphics_object::value_as_string: invalid graphics object"); + + return retval; +} + octave_scalar_map base_graphics_object::values_as_struct (void) { @@ -4704,7 +4755,8 @@ if (camerapositionmode_is ("auto")) { Matrix tview = get_view ().matrix_value (); - double az = tview(0), el = tview(1); + double az = tview(0); + double el = tview(1); double d = 5 * sqrt (pb(0)*pb(0)+pb(1)*pb(1)+pb(2)*pb(2)); if (el == 90 || el == -90) @@ -4729,7 +4781,8 @@ if (cameraupvectormode_is ("auto")) { Matrix tview = get_view ().matrix_value (); - double az = tview(0), el = tview(1); + double az = tview(0); + double el = tview(1); if (el == 90 || el == -90) { @@ -4791,7 +4844,8 @@ translate (x_view, -0.5, -0.5, -0.5); Matrix x_cube = x_view * unit_cube (); - ColumnVector cmin = x_cube.row_min (), cmax = x_cube.row_max (); + ColumnVector cmin = x_cube.row_min (); + ColumnVector cmax = x_cube.row_max (); double xM = cmax(0)-cmin(0); double yM = cmax(1)-cmin(1); @@ -4897,9 +4951,11 @@ const Matrix xlims = xform.xscale (get_xlim ().matrix_value ()); const Matrix ylims = xform.yscale (get_ylim ().matrix_value ()); const Matrix zlims = xform.zscale (get_zlim ().matrix_value ()); - double x_min = xlims(0), x_max = xlims(1); - double y_min = ylims(0), y_max = ylims(1); - double z_min = zlims(0), z_max = zlims(1); + + double x_min, x_max, y_min, y_max, z_min, z_max; + x_min = xlims(0), x_max = xlims(1); + y_min = ylims(0), y_max = ylims(1); + z_min = zlims(0), z_max = zlims(1); ColumnVector p1, p2, dir (3); @@ -5139,7 +5195,9 @@ get_xticklabel ().all_strings (), get_xlim ().matrix_value ()); - double wmax = ext(0), hmax = ext(1), angle = 0; + double wmax = ext(0); + double hmax = ext(1); + double angle = 0; ColumnVector p = graphics_xform::xform_vector ((xpTickN+xpTick)/2, ypTick, zpTick); @@ -5240,7 +5298,9 @@ get_yticklabel ().all_strings (), get_ylim ().matrix_value ()); - double wmax = ext(0)+4, hmax = ext(1), angle = 0; + double wmax = ext(0)+4; + double hmax = ext(1); + double angle = 0; ColumnVector p = graphics_xform::xform_vector (xpTick, (ypTickN+ypTick)/2, zpTick); @@ -5333,7 +5393,9 @@ get_zticklabel ().all_strings (), get_zlim ().matrix_value ()); - double wmax = ext(0), hmax = ext(1), angle = 0; + double wmax = ext(0); + double hmax = ext(1); + double angle = 0; ColumnVector p; if (xySym) @@ -6402,7 +6464,8 @@ #endif Matrix ext (1, 2, 0.0); - double wmax = 0., hmax = 0.; + double wmax, hmax; + wmax = hmax = 0.; int n = std::min (ticklabels.numel (), ticks.numel ()); for (int i = 0; i < n; i++) { @@ -6878,14 +6941,14 @@ } inline -double force_in_range (const double x, const double lower, const double upper) +double force_in_range (double x, double lower, double upper) { if (x < lower) - { return lower; } + return lower; else if (x > upper) - { return upper; } + return upper; else - { return x; } + return x; } static Matrix @@ -7225,7 +7288,8 @@ { #ifdef HAVE_FREETYPE - int halign = 0, valign = 0; + int halign = 0; + int valign = 0; if (horizontalalignment_is ("center")) halign = 1; @@ -7368,9 +7432,11 @@ Matrix z = get_zdata ().matrix_value (); - int p = z.columns (), q = z.rows (); - int i1 = 0, i2 = 0, i3 = 0; - int j1 = 0, j2 = 0, j3 = 0; + int p = z.columns (); + int q = z.rows (); + int i1, i2, i3, j1, j2, j3; + i1 = i2 = i3 = 0; + j1 = j2 = j3 = 0; bool x_mat = (x.rows () == q); bool y_mat = (y.columns () == p); @@ -8144,9 +8210,9 @@ // No copying! - function_event (const function_event &); - - function_event & operator = (const function_event &); + function_event (const function_event&); + + function_event & operator = (const function_event&); }; class @@ -8348,7 +8414,7 @@ } void -gh_manager::do_post_callback (const graphics_handle& h, const std::string name, +gh_manager::do_post_callback (const graphics_handle& h, const std::string& name, const octave_value& data) { gh_manager::auto_lock guard; @@ -8398,7 +8464,7 @@ } void -gh_manager::do_post_set (const graphics_handle& h, const std::string name, +gh_manager::do_post_set (const graphics_handle& h, const std::string& name, const octave_value& value, bool notify_toolkit) { gh_manager::auto_lock guard; @@ -8706,6 +8772,29 @@ { obj.set (args(1).map_value ()); } + else if (nargin == 2 && args(1).is_string ()) + { + std::string property = args(1).string_value (); + + octave_map pmap = obj.values_as_struct (); + + if (pmap.isfield (property)) + { + if (nargout != 0) + retval = pmap.getfield (property)(0); + else + { + std::string s = obj.value_as_string (property); + if (! error_state) + octave_stdout << s; + } + } + else + { + error ("set: unknown property"); + break; + } + } else if (nargin == 1) { if (nargout != 0) @@ -8748,7 +8837,7 @@ } static std::string -get_graphics_object_type (const double val) +get_graphics_object_type (double val) { std::string retval; @@ -9379,7 +9468,7 @@ { graphics_handle h = octave_NaN; - const NDArray vals = args (0).array_value (); + const NDArray vals = args(0).array_value (); if (! error_state) { @@ -10178,7 +10267,7 @@ static bool compare_property_values (const octave_value& o1, const octave_value& o2) { - octave_value_list args (2); + octave_value_list args(2); args(0) = o1; args(1) = o2; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/graphics.in.h --- a/libinterp/corefcn/graphics.in.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/graphics.in.h Fri Mar 07 13:02:43 2014 -0500 @@ -296,7 +296,7 @@ graphics_handle get_parent (void) const { return parent; } - void set_parent (const graphics_handle &h) { parent = h; } + void set_parent (const graphics_handle& h) { parent = h; } bool is_hidden (void) const { return hidden; } @@ -1028,7 +1028,7 @@ validate (); } - color_values (std::string str) + color_values (const std::string& str) : xrgb (1, 3) { if (! str2rgb (str)) @@ -1076,7 +1076,7 @@ private: Matrix xrgb; - OCTINTERP_API bool str2rgb (std::string str); + OCTINTERP_API bool str2rgb (const std::string& str); }; class color_property : public base_property @@ -1631,7 +1631,7 @@ } children_property (const std::string& nm, const graphics_handle& h, - const Matrix &val) + const Matrix& val) : base_property (nm, h), children_list () { do_init_children (val); @@ -1651,12 +1651,12 @@ base_property* clone (void) const { return new children_property (*this); } - bool remove_child (const double &val) + bool remove_child (double val) { return do_remove_child (val); } - void adopt (const double &val) + void adopt (double val) { do_adopt_child (val); } @@ -1759,14 +1759,14 @@ } private: - void do_init_children (const Matrix &val) + void do_init_children (const Matrix& val) { children_list.clear (); for (octave_idx_type i = 0; i < val.numel (); i++) children_list.push_front (val.xelem (i)); } - void do_init_children (const std::list &val) + void do_init_children (const std::list& val) { children_list.clear (); for (const_children_list_iterator p = val.begin (); p != val.end (); p++) @@ -1800,7 +1800,7 @@ return false; } - void do_adopt_child (const double &val) + void do_adopt_child (double val) { children_list.push_front (val); } @@ -2600,7 +2600,7 @@ protected: struct cmp_caseless_str { - bool operator () (const caseless_str &a, const caseless_str &b) const + bool operator () (const caseless_str& a, const caseless_str& b) const { std::string a1 = a; std::transform (a1.begin (), a1.end (), a1.begin (), tolower); @@ -2706,6 +2706,8 @@ virtual std::string values_as_string (void); + virtual std::string value_as_string (const std::string& prop); + virtual octave_scalar_map values_as_struct (void); virtual graphics_handle get_parent (void) const @@ -2977,6 +2979,11 @@ std::string values_as_string (void) { return rep->values_as_string (); } + std::string value_as_string (const std::string& prop) + { + return rep->value_as_string (prop); + } + octave_map values_as_struct (void) { return rep->values_as_struct (); } graphics_handle get_parent (void) const { return rep->get_parent (); } @@ -5389,11 +5396,11 @@ // --------------------------------------------------------------------- octave_value -get_property_from_handle (double handle, const std::string &property, - const std::string &func); +get_property_from_handle (double handle, const std::string& property, + const std::string& func); bool -set_property_in_handle (double handle, const std::string &property, - const octave_value &arg, const std::string &func); +set_property_in_handle (double handle, const std::string& property, + const octave_value& arg, const std::string& func); // --------------------------------------------------------------------- @@ -5864,12 +5871,12 @@ void do_execute_callback (const graphics_handle& h, const octave_value& cb, const octave_value& data); - void do_post_callback (const graphics_handle& h, const std::string name, + void do_post_callback (const graphics_handle& h, const std::string& name, const octave_value& data); void do_post_function (graphics_event::event_fcn fcn, void* fcn_data); - void do_post_set (const graphics_handle& h, const std::string name, + void do_post_set (const graphics_handle& h, const std::string& name, const octave_value& value, bool notify_toolkit = true); int do_process_events (bool force = false); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/help.cc --- a/libinterp/corefcn/help.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/help.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1078,7 +1078,7 @@ if (args.length () == 1) { - const std::string name = args (0).string_value (); + const std::string name = args(0).string_value (); if (! error_state) { @@ -1367,7 +1367,7 @@ retval = Cell (ffl.append (afl)); else { - std::string dir = args (0).string_value (); + std::string dir = args(0).string_value (); if (! error_state) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/input.cc --- a/libinterp/corefcn/input.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/input.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1406,11 +1406,12 @@ DEFUN (filemarker, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} filemarker ()\n\ -@deftypefnx {Built-in Function} {} filemarker (@var{new_val})\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} filemarker (@var{new_val})\n\ @deftypefnx {Built-in Function} {} filemarker (@var{new_val}, \"local\")\n\ -Query or set the character used to separate filename from the\n\ -the subfunction names contained within the file. This can be used in\n\ -a generic manner to interact with subfunctions. For example,\n\ +Query or set the character used to separate the filename from the subfunction\n\ +names contained within the file. By default this is the character @samp{>}.\n\ +This can be used in a generic manner to interact with subfunctions.\n\ +For example,\n\ \n\ @example\n\ help ([\"myfunc\", filemarker, \"mysubfunc\"])\n\ @@ -1418,8 +1419,10 @@ \n\ @noindent\n\ returns the help string associated with the subfunction @code{mysubfunc}\n\ -of the function @code{myfunc}. Another use of @code{filemarker} is when\n\ -debugging it allows easier placement of breakpoints within subfunctions.\n\ +located in the file @file{myfunc.m}.\n\ +\n\ +@code{filemarker} is also useful during debugging for placing breakpoints\n\ +within subfunctions or nested functions.\n\ For example,\n\ \n\ @example\n\ @@ -1430,7 +1433,7 @@ will set a breakpoint at the first line of the subfunction @code{mysubfunc}.\n\ \n\ When called from inside a function with the @qcode{\"local\"} option, the\n\ -variable is changed locally for the function and any subroutines it calls. \n\ +variable is changed locally for the function and any subroutines it calls.\n\ The original variable value is restored when exiting the function.\n\ @end deftypefn") { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/inv.cc diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/jit-typeinfo.cc --- a/libinterp/corefcn/jit-typeinfo.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/jit-typeinfo.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1247,6 +1247,8 @@ destroy_fn.add_overload (create_identity(index)); destroy_fn.add_overload (create_identity(complex)); + // -------------------- scalar related operations -------------------- + // now for binary scalar operations add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd); add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub); @@ -1335,6 +1337,7 @@ val = builder.CreateFMul (val, mone); fn.do_return (builder, val); } + unary_ops[octave_value::op_uminus].add_overload (fn); fn = create_identity (scalar); unary_ops[octave_value::op_uplus].add_overload (fn); @@ -1842,7 +1845,7 @@ register_generic ("cos", matrix, matrix); add_builtin ("exp"); - register_intrinsic ("exp", llvm::Intrinsic::cos, scalar, scalar); + register_intrinsic ("exp", llvm::Intrinsic::exp, scalar, scalar); register_generic ("exp", matrix, matrix); add_builtin ("balance"); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/kron.cc --- a/libinterp/corefcn/kron.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/kron.cc Fri Mar 07 13:02:43 2014 -0500 @@ -55,8 +55,10 @@ assert (a.ndims () == 2); assert (b.ndims () == 2); - octave_idx_type nra = a.rows (), nrb = b.rows (); - octave_idx_type nca = a.cols (), ncb = b.cols (); + octave_idx_type nra = a.rows (); + octave_idx_type nrb = b.rows (); + octave_idx_type nca = a.cols (); + octave_idx_type ncb = b.cols (); MArray c (dim_vector (nra*nrb, nca*ncb)); T *cv = c.fortran_vec (); @@ -79,8 +81,11 @@ { assert (b.ndims () == 2); - octave_idx_type nra = a.rows (), nrb = b.rows (), dla = a.diag_length (); - octave_idx_type nca = a.cols (), ncb = b.cols (); + octave_idx_type nra = a.rows (); + octave_idx_type nrb = b.rows (); + octave_idx_type dla = a.diag_length (); + octave_idx_type nca = a.cols (); + octave_idx_type ncb = b.cols (); MArray c (dim_vector (nra*nrb, nca*ncb), T ()); @@ -129,12 +134,15 @@ static PermMatrix kron (const PermMatrix& a, const PermMatrix& b) { - octave_idx_type na = a.rows (), nb = b.rows (); - const octave_idx_type *pa = a.data (), *pb = b.data (); + octave_idx_type na = a.rows (); + octave_idx_type nb = b.rows (); + const octave_idx_type *pa = a.data (); + const octave_idx_type *pb = b.data (); PermMatrix c(na*nb); // Row permutation. octave_idx_type *pc = c.fortran_vec (); - bool cola = a.is_col_perm (), colb = b.is_col_perm (); + bool cola = a.is_col_perm (); + bool colb = b.is_col_perm (); if (cola && colb) { for (octave_idx_type i = 0; i < na; i++) @@ -282,7 +290,8 @@ if (nargin >= 2) { - octave_value a = args(0), b = args(1); + octave_value a = args(0); + octave_value b = args(1); retval = dispatch_kron (a, b); for (octave_idx_type i = 2; i < nargin; i++) retval = dispatch_kron (retval, args(i)); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/load-path.cc --- a/libinterp/corefcn/load-path.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/load-path.cc Fri Mar 07 13:02:43 2014 -0500 @@ -38,6 +38,7 @@ #include "defun.h" #include "input.h" #include "load-path.h" +#include "ov-usr-fcn.h" #include "pager.h" #include "parse.h" #include "toplev.h" @@ -120,6 +121,7 @@ if (fs) { method_file_map.clear (); + package_dir_map.clear (); dir_mtime = fs.mtime (); dir_time_last_checked = octave_time (); @@ -181,6 +183,8 @@ get_private_file_map (full_name); else if (fname[0] == '@') get_method_file_map (full_name, fname.substr (1)); + else if (fname[0] == '+') + get_package_dir (full_name, fname.substr (1)); } else { @@ -286,6 +290,13 @@ method_file_map[class_name].private_file_map = get_fcn_files (pd); } +void +load_path::dir_info::get_package_dir (const std::string& d, + const std::string& package_name) +{ + package_dir_map[package_name] = dir_info (d); +} + bool load_path::instance_ok (void) { @@ -373,8 +384,8 @@ } void -load_path::move_fcn_map (const std::string& dir_name, - const string_vector& fcn_files, bool at_end) +load_path::loader::move_fcn_map (const std::string& dir_name, + const string_vector& fcn_files, bool at_end) { octave_idx_type len = fcn_files.length (); @@ -422,7 +433,7 @@ } void -load_path::move_method_map (const std::string& dir_name, bool at_end) +load_path::loader::move_method_map (const std::string& dir_name, bool at_end) { for (method_map_iterator i = method_map.begin (); i != method_map.end (); @@ -466,7 +477,7 @@ } void -load_path::move (dir_info_list_iterator i, bool at_end) +load_path::do_move (dir_info_list_iterator i, bool at_end) { if (dir_info_list.size () > 1) { @@ -479,16 +490,56 @@ else dir_info_list.push_front (di); - std::string dir_name = di.dir_name; - - move_fcn_map (dir_name, di.fcn_files, at_end); - - // No need to move elements of private function map. - - move_method_map (dir_name, at_end); + move (di, at_end); + } +} + +void +load_path::move (const dir_info& di, bool at_end, const std::string& pname) +{ + loader& l = get_loader (pname); + + l.move (di, at_end); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + move (p->second, at_end, full_name); } } +void +load_path::loader::move (const dir_info& di, bool at_end) +{ + std::string dir_name = di.dir_name; + + std::list::iterator s = + std::find (dir_list.begin (), dir_list.end (), dir_name); + + if (s != dir_list.end ()) + { + dir_list.erase (s); + + if (at_end) + dir_list.push_back (dir_name); + else + dir_list.push_front (dir_name); + } + + move_fcn_map (dir_name, di.fcn_files, at_end); + + // No need to move elements of private function map. + + move_method_map (dir_name, at_end); +} + static void maybe_add_path_elts (std::string& path, const std::string& dir) { @@ -544,9 +595,10 @@ load_path::do_clear (void) { dir_info_list.clear (); - fcn_map.clear (); - private_fcn_map.clear (); - method_map.clear (); + + default_loader.clear (); + + loader_map.clear (); } static std::list @@ -683,7 +735,7 @@ dir_info_list_iterator i = find_dir_info (dir); if (i != dir_info_list.end ()) - move (i, at_end); + do_move (i, at_end); else { file_stat fs (dir); @@ -701,11 +753,7 @@ else dir_info_list.push_front (di); - add_to_fcn_map (di, at_end); - - add_to_private_fcn_map (di); - - add_to_method_map (di, at_end); + add (di, at_end); if (add_hook) add_hook (dir); @@ -726,12 +774,12 @@ i = find_dir_info ("."); if (i != dir_info_list.end ()) - move (i, false); + do_move (i, false); } void -load_path::remove_fcn_map (const std::string& dir, - const string_vector& fcn_files) +load_path::loader::remove_fcn_map (const std::string& dir, + const string_vector& fcn_files) { octave_idx_type len = fcn_files.length (); @@ -770,7 +818,7 @@ } void -load_path::remove_private_fcn_map (const std::string& dir) +load_path::loader::remove_private_fcn_map (const std::string& dir) { private_fcn_map_iterator p = private_fcn_map.find (dir); @@ -779,7 +827,7 @@ } void -load_path::remove_method_map (const std::string& dir) +load_path::loader::remove_method_map (const std::string& dir) { for (method_map_iterator i = method_map.begin (); i != method_map.end (); @@ -847,15 +895,11 @@ if (remove_hook) remove_hook (dir); - string_vector fcn_files = i->fcn_files; + dir_info& di = *i; + + remove (di); dir_info_list.erase (i); - - remove_fcn_map (dir, fcn_files); - - remove_private_fcn_map (dir); - - remove_method_map (dir); } } } @@ -864,17 +908,52 @@ } void +load_path::remove (const dir_info& di, const std::string& pname) +{ + loader& l = get_loader (pname); + + l.remove (di); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + remove (p->second, full_name); + } +} + +void +load_path::loader::remove (const dir_info& di) +{ + std::string dir = di.dir_name; + + string_vector fcn_files = di.fcn_files; + + dir_list.remove (dir); + + remove_fcn_map (dir, fcn_files); + + remove_private_fcn_map (dir); + + remove_method_map (dir); +} + +void load_path::do_update (void) const { // I don't see a better way to do this because we need to // preserve the correct directory ordering for new files that // have appeared. - fcn_map.clear (); - - private_fcn_map.clear (); - - method_map.clear (); + default_loader.clear (); + + loader_map.clear (); for (dir_info_list_iterator p = dir_info_list.begin (); p != dir_info_list.end (); @@ -884,11 +963,7 @@ di.update (); - add_to_fcn_map (di, true); - - add_to_private_fcn_map (di); - - add_to_method_map (di, true); + add (di, true); } } @@ -987,8 +1062,8 @@ } std::string -load_path::do_find_fcn (const std::string& fcn, std::string& dir_name, - int type) const +load_path::loader::find_fcn (const std::string& fcn, std::string& dir_name, + int type) const { std::string retval; @@ -1003,7 +1078,7 @@ std::string class_name = fcn.substr (1, pos-1); std::string meth = fcn.substr (pos+1); - retval = do_find_method (class_name, meth, dir_name); + retval = find_method (class_name, meth, dir_name); } else retval = std::string (); @@ -1042,8 +1117,8 @@ } std::string -load_path::do_find_private_fcn (const std::string& dir, - const std::string& fcn, int type) const +load_path::loader::find_private_fcn (const std::string& dir, + const std::string& fcn, int type) const { std::string retval; @@ -1072,9 +1147,9 @@ } std::string -load_path::do_find_method (const std::string& class_name, - const std::string& meth, - std::string& dir_name, int type) const +load_path::loader::find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name, int type) const { std::string retval; @@ -1120,7 +1195,7 @@ } std::list -load_path::do_methods (const std::string& class_name) const +load_path::loader::methods (const std::string& class_name) const { std::list retval; @@ -1149,13 +1224,63 @@ // update (); + default_loader.overloads (meth, retval); + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + l->second.overloads (meth, retval); + + return retval; +} + +void +load_path::loader::overloads (const std::string& meth, + std::list& l) const +{ for (const_method_map_iterator q = method_map.begin (); q != method_map.end (); q++) { const fcn_map_type& m = q->second; if (m.find (meth) != m.end ()) - retval.push_back (q->first); + { + std::string class_name = q->first; + + if (! prefix.empty ()) + class_name = prefix + "." + class_name; + + l.push_back (class_name); + } + } +} + +// Should we cache all files in private directories, or is it OK to just +// look them up each time as needed? + +std::string +find_private_file (const std::string& fname) +{ + std::string retval; + + // Look in private directory corresponding to current function (if + // any). + + octave_user_function *curr_fcn = symbol_table::get_curr_fcn (); + + if (curr_fcn && ! curr_fcn->is_private_function ()) + { + std::string dir_name = curr_fcn->dir_name (); + + if (! dir_name.empty ()) + { + std::string pfname = dir_name + file_ops::dir_sep_str () + + "private" + file_ops::dir_sep_str () + fname; + + file_stat fs (pfname); + + if (fs.exists () && fs.is_reg ()) + retval = pfname; + } } return retval; @@ -1166,33 +1291,43 @@ { std::string retval; + if (octave_env::absolute_pathname (file) + || octave_env::rooted_relative_pathname (file)) + { + file_stat fs (file); + + if (fs.exists ()) + return file; + } + else + { + std::string tfile = find_private_file (file); + + if (! tfile.empty ()) + return tfile; + } + if (file.find_first_of (file_ops::dir_sep_chars ()) != std::string::npos) { - if (octave_env::absolute_pathname (file) - || octave_env::rooted_relative_pathname (file)) + // Given name has a directory separator, so append it to each + // element of the load path in turn. + + for (const_dir_info_list_iterator p = dir_info_list.begin (); + p != dir_info_list.end (); + p++) { - file_stat fs (file); + std::string tfile = file_ops::concat (p->dir_name, file); + + file_stat fs (tfile); if (fs.exists ()) - return file; - } - else - { - for (const_dir_info_list_iterator p = dir_info_list.begin (); - p != dir_info_list.end (); - p++) - { - std::string tfile = file_ops::concat (p->dir_name, file); - - file_stat fs (tfile); - - if (fs.exists ()) - return tfile; - } + return tfile; } } else { + // Look in cache. + for (const_dir_info_list_iterator p = dir_info_list.begin (); p != dir_info_list.end (); p++) @@ -1515,6 +1650,12 @@ string_vector load_path::do_fcn_names (void) const { + return default_loader.fcn_names (); +} + +string_vector +load_path::loader::fcn_names (void) const +{ size_t len = fcn_map.size (); string_vector retval (len); @@ -1657,69 +1798,11 @@ } } - for (const_private_fcn_map_iterator i = private_fcn_map.begin (); - i != private_fcn_map.end (); i++) - { - os << "\n*** private functions in " - << file_ops::concat (i->first, "private") << ":\n\n"; - - print_fcn_list (os, i->second); - } - -#if defined (DEBUG_LOAD_PATH) - - for (const_fcn_map_iterator i = fcn_map.begin (); - i != fcn_map.end (); - i++) - { - os << i->first << ":\n"; - - const file_info_list_type& file_info_list = i->second; - - for (const_file_info_list_iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) - { - os << " " << p->dir_name << " ("; - - print_types (os, p->types); - - os << ")\n"; - } - } - - for (const_method_map_iterator i = method_map.begin (); - i != method_map.end (); - i++) - { - os << "CLASS " << i->first << ":\n"; - - const fcn_map_type& fm = i->second; - - for (const_fcn_map_iterator q = fm.begin (); - q != fm.end (); - q++) - { - os << " " << q->first << ":\n"; - - const file_info_list_type& file_info_list = q->second; - - for (const_file_info_list_iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) - { - os << " " << p->dir_name << " ("; - - print_types (os, p->types); - - os << ")\n"; - } - } - } - - os << "\n"; - -#endif + default_loader.display (os); + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + l->second.display (os); } // True if a path is contained in a path list separated by path_sep_char @@ -1743,7 +1826,29 @@ } void -load_path::add_to_fcn_map (const dir_info& di, bool at_end) const +load_path::add (const dir_info& di, bool at_end, + const std::string& pname) const +{ + loader& l = get_loader (pname); + + l.add (di, at_end); + + dir_info::package_dir_map_type package_dir_map = di.package_dir_map; + + for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin (); + p != package_dir_map.end (); ++p) + { + std::string full_name = p->first; + + if (! pname.empty ()) + full_name = pname + "." + full_name; + + add (p->second, at_end, full_name); + } +} + +void +load_path::loader::add_to_fcn_map (const dir_info& di, bool at_end) { std::string dir_name = di.dir_name; @@ -1839,7 +1944,7 @@ } void -load_path::add_to_private_fcn_map (const dir_info& di) const +load_path::loader::add_to_private_fcn_map (const dir_info& di) { dir_info::fcn_file_map_type private_file_map = di.private_file_map; @@ -1848,7 +1953,7 @@ } void -load_path::add_to_method_map (const dir_info& di, bool at_end) const +load_path::loader::add_to_method_map (const dir_info& di, bool at_end) { std::string dir_name = di.dir_name; @@ -1918,6 +2023,81 @@ } } +void +load_path::loader::display (std::ostream& os) const +{ + os << "*** loader: " << (prefix.empty () ? "" : prefix) << "\n\n"; + + for (std::list::const_iterator s = dir_list.begin (); + s != dir_list.end (); ++s) + os << *s << "\n"; + os << "\n"; + + for (const_private_fcn_map_iterator i = private_fcn_map.begin (); + i != private_fcn_map.end (); i++) + { + os << "\n*** private functions in " + << file_ops::concat (i->first, "private") << ":\n\n"; + + print_fcn_list (os, i->second); + } + +#if defined (DEBUG_LOAD_PATH) + + for (const_fcn_map_iterator i = fcn_map.begin (); + i != fcn_map.end (); + i++) + { + os << i->first << ":\n"; + + const file_info_list_type& file_info_list = i->second; + + for (const_file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + os << " " << p->dir_name << " ("; + + print_types (os, p->types); + + os << ")\n"; + } + } + + for (const_method_map_iterator i = method_map.begin (); + i != method_map.end (); + i++) + { + os << "CLASS " << i->first << ":\n"; + + const fcn_map_type& fm = i->second; + + for (const_fcn_map_iterator q = fm.begin (); + q != fm.end (); + q++) + { + os << " " << q->first << ":\n"; + + const file_info_list_type& file_info_list = q->second; + + for (const_file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + os << " " << p->dir_name << " ("; + + print_types (os, p->types); + + os << ")\n"; + } + } + } + + os << "\n"; + +#endif +} + std::string genpath (const std::string& dirname, const string_vector& skip) { @@ -1929,7 +2109,7 @@ { retval = dirname; - string_vector dirlist = dir.read (); + string_vector dirlist = dir.read ().sort (false); octave_idx_type len = dirlist.length (); @@ -1937,7 +2117,8 @@ { std::string elt = dirlist[i]; - bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'); + bool skip_p = (elt == "." || elt == ".." || elt[0] == '@' + || elt[0] == '+'); if (! skip_p) { @@ -1964,6 +2145,21 @@ return retval; } +std::list +load_path::do_get_all_package_names (bool only_top_level) const +{ + std::list retval; + + for (const_loader_map_iterator l = loader_map.begin (); + l != loader_map.end (); ++l) + { + if (! only_top_level || l->first.find ('.') == std::string::npos) + retval.push_back (l->first); + } + + return retval; +} + static void execute_pkg_add_or_del (const std::string& dir, const std::string& script_file) @@ -2339,3 +2535,10 @@ return retval; } + +DEFUN (__dump_load_path__, , , "") +{ + load_path::display (octave_stdout); + + return octave_value_list (); +} diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/load-path.h --- a/libinterp/corefcn/load-path.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/load-path.h Fri Mar 07 13:02:43 2014 -0500 @@ -39,8 +39,7 @@ protected: load_path (void) - : dir_info_list (), fcn_map (), private_fcn_map (), method_map (), - init_dirs () { } + : loader_map (), default_loader (), dir_info_list (), init_dirs () { } public: @@ -96,24 +95,29 @@ static std::string find_method (const std::string& class_name, const std::string& meth, - std::string& dir_name) + std::string& dir_name, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_find_method (class_name, meth, dir_name) - : std::string (); + ? instance->get_loader (pack_name).find_method (class_name, meth, + dir_name) + : std::string (); } static std::string find_method (const std::string& class_name, - const std::string& meth) + const std::string& meth, + const std::string& pack_name = std::string ()) { std::string dir_name; - return find_method (class_name, meth, dir_name); + return find_method (class_name, meth, dir_name, pack_name); } - static std::list methods (const std::string& class_name) + static std::list methods (const std::string& class_name, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_methods (class_name) : std::list (); + ? instance->get_loader(pack_name).methods (class_name) + : std::list (); } static std::list overloads (const std::string& meth) @@ -122,47 +126,72 @@ ? instance->do_overloads (meth) : std::list (); } - static std::string find_fcn (const std::string& fcn, std::string& dir_name) + static bool find_package (const std::string& package_name) + { + return instance_ok () + ? instance->do_find_package (package_name) : false; + } + + static std::list + get_all_package_names (bool only_top_level = true) { return instance_ok () - ? instance->do_find_fcn (fcn, dir_name) : std::string (); + ? instance->do_get_all_package_names (only_top_level) + : std::list (); } - static std::string find_fcn (const std::string& fcn) + static std::string find_fcn (const std::string& fcn, std::string& dir_name, + const std::string& pack_name = std::string ()) + { + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name) + : std::string (); + } + + static std::string find_fcn (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return find_fcn (fcn, dir_name); + return find_fcn (fcn, dir_name, pack_name); } static std::string find_private_fcn (const std::string& dir, - const std::string& fcn) + const std::string& fcn, + const std::string& pack_name = std::string ()) { return instance_ok () - ? instance->do_find_private_fcn (dir, fcn) : std::string (); + ? instance->get_loader (pack_name).find_private_fcn (dir, fcn) + : std::string (); } - static std::string find_fcn_file (const std::string& fcn) + static std::string find_fcn_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, M_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } - static std::string find_oct_file (const std::string& fcn) + static std::string find_oct_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, OCT_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } - static std::string find_mex_file (const std::string& fcn) + static std::string find_mex_file (const std::string& fcn, + const std::string& pack_name = std::string ()) { std::string dir_name; - return instance_ok () ? - instance->do_find_fcn (fcn, dir_name, MEX_FILE) : std::string (); + return instance_ok () + ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE) + : std::string (); } static std::string find_file (const std::string& file) @@ -297,19 +326,27 @@ typedef method_file_map_type::const_iterator const_method_file_map_iterator; typedef method_file_map_type::iterator method_file_map_iterator; + // + typedef std::map package_dir_map_type; + + typedef package_dir_map_type::const_iterator const_package_dir_map_iterator; + typedef package_dir_map_type::iterator package_dir_map_iterator; + // This default constructor is only provided so we can create a // std::map of dir_info objects. You should not use this // constructor for any other purpose. dir_info (void) : dir_name (), abs_dir_name (), is_relative (false), dir_mtime (), dir_time_last_checked (), - all_files (), fcn_files (), private_file_map (), method_file_map () + all_files (), fcn_files (), private_file_map (), method_file_map (), + package_dir_map () { } dir_info (const std::string& d) : dir_name (d), abs_dir_name (), is_relative (false), dir_mtime (), dir_time_last_checked (), - all_files (), fcn_files (), private_file_map (), method_file_map () + all_files (), fcn_files (), private_file_map (), method_file_map (), + package_dir_map () { initialize (); } @@ -321,7 +358,8 @@ dir_time_last_checked (di.dir_time_last_checked), all_files (di.all_files), fcn_files (di.fcn_files), private_file_map (di.private_file_map), - method_file_map (di.method_file_map) { } + method_file_map (di.method_file_map), + package_dir_map (di.package_dir_map) { } ~dir_info (void) { } @@ -338,6 +376,7 @@ fcn_files = di.fcn_files; private_file_map = di.private_file_map; method_file_map = di.method_file_map; + package_dir_map = di.package_dir_map; } return *this; @@ -354,6 +393,7 @@ string_vector fcn_files; fcn_file_map_type private_file_map; method_file_map_type method_file_map; + package_dir_map_type package_dir_map; private: @@ -366,6 +406,9 @@ void get_method_file_map (const std::string& d, const std::string& class_name); + void get_package_dir (const std::string& d, + const std::string& package_name); + friend fcn_file_map_type get_fcn_files (const std::string& d); }; @@ -442,13 +485,125 @@ typedef method_map_type::const_iterator const_method_map_iterator; typedef method_map_type::iterator method_map_iterator; - mutable dir_info_list_type dir_info_list; + class loader + { + public: + loader (const std::string& pfx = std::string ()) + : prefix (pfx), dir_list (), fcn_map (), private_fcn_map (), + method_map () { } + + loader (const loader& l) + : prefix (l.prefix), dir_list (l.dir_list), + private_fcn_map (l.private_fcn_map), method_map (l.method_map) { } + + ~loader (void) { } + + loader& operator = (const loader& l) + { + if (&l != this) + { + prefix = l.prefix; + dir_list = l.dir_list; + fcn_map = l.fcn_map; + private_fcn_map = l.private_fcn_map; + method_map = l.method_map; + } + + return *this; + } - mutable fcn_map_type fcn_map; + void add (const dir_info& di, bool at_end) + { + if (at_end) + dir_list.push_back (di.dir_name); + else + dir_list.push_front (di.dir_name); + + add_to_fcn_map (di, at_end); + + add_to_private_fcn_map (di); + + add_to_method_map (di, at_end); + } + + void move (const dir_info& di, bool at_end); + + void remove (const dir_info& di); + + void clear (void) + { + dir_list.clear (); + + fcn_map.clear (); + + private_fcn_map.clear (); + + method_map.clear (); + } + + void display (std::ostream& out) const; - mutable private_fcn_map_type private_fcn_map; + std::string find_fcn (const std::string& fcn, + std::string& dir_name, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::string find_private_fcn (const std::string& dir, + const std::string& fcn, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::string find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + std::list methods (const std::string& class_name) const; + + void overloads (const std::string& meth, std::list& l) const; + + string_vector fcn_names (void) const; + + private: + void add_to_fcn_map (const dir_info& di, bool at_end); + + void add_to_private_fcn_map (const dir_info& di); + + void add_to_method_map (const dir_info& di, bool at_end); + + void move_fcn_map (const std::string& dir, + const string_vector& fcn_files, bool at_end); + + void move_method_map (const std::string& dir, bool at_end); - mutable method_map_type method_map; + void remove_fcn_map (const std::string& dir, + const string_vector& fcn_files); + + void remove_private_fcn_map (const std::string& dir); + + void remove_method_map (const std::string& dir); + + private: + std::string prefix; + + std::list dir_list; + + fcn_map_type fcn_map; + + private_fcn_map_type private_fcn_map; + + method_map_type method_map; + }; + + // + typedef std::map loader_map_type; + + typedef loader_map_type::const_iterator const_loader_map_iterator; + typedef loader_map_type::iterator loader_map_iterator; + + mutable loader_map_type loader_map; + + mutable loader default_loader; + + mutable dir_info_list_type dir_info_list; mutable std::set init_dirs; @@ -475,12 +630,13 @@ bool do_contains_canonical (const std::string& dir) const; - void move_fcn_map (const std::string& dir, - const string_vector& fcn_files, bool at_end); + void do_move (dir_info_list_iterator i, bool at_end); - void move_method_map (const std::string& dir, bool at_end); + void move (const dir_info& di, bool at_end, + const std::string& pname = std::string ()); - void move (std::list::iterator i, bool at_end); + void remove (const dir_info& di, + const std::string& pname = std::string ()); void do_initialize (bool set_initial_path); @@ -494,12 +650,6 @@ void do_add (const std::string& dir, bool at_end, bool warn); - void remove_fcn_map (const std::string& dir, const string_vector& fcn_files); - - void remove_private_fcn_map (const std::string& dir); - - void remove_method_map (const std::string& dir); - bool do_remove (const std::string& dir); void do_update (void) const; @@ -508,23 +658,31 @@ check_file_type (std::string& fname, int type, int possible_types, const std::string& fcn, const char *who); - std::string do_find_fcn (const std::string& fcn, - std::string& dir_name, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + loader& get_loader (const std::string& name) const + { + if (! name.empty ()) + { + loader_map_iterator l = loader_map.find (name); - std::string do_find_private_fcn (const std::string& dir, - const std::string& fcn, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + if (l == loader_map.end ()) + l = loader_map.insert (loader_map.end (), + loader_map_type::value_type (name, loader (name))); - std::string do_find_method (const std::string& class_name, - const std::string& meth, - std::string& dir_name, - int type = M_FILE | OCT_FILE | MEX_FILE) const; + return l->second; + } - std::list do_methods (const std::string& class_name) const; + return default_loader; + } std::list do_overloads (const std::string& meth) const; + bool do_find_package (const std::string& package_name) const + { + return (loader_map.find (package_name) != loader_map.end ()); + } + + std::list do_get_all_package_names (bool only_top_level) const; + std::string do_find_file (const std::string& file) const; std::string do_find_dir (const std::string& dir) const; @@ -559,11 +717,8 @@ std::string do_get_command_line_path (void) const { return command_line_path; } - void add_to_fcn_map (const dir_info& di, bool at_end) const; - - void add_to_private_fcn_map (const dir_info& di) const; - - void add_to_method_map (const dir_info& di, bool at_end) const; + void add (const dir_info& di, bool at_end, + const std::string& pname = std::string ()) const; friend dir_info::fcn_file_map_type get_fcn_files (const std::string& d); }; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/load-save.cc --- a/libinterp/corefcn/load-save.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/load-save.cc Fri Mar 07 13:02:43 2014 -0500 @@ -502,17 +502,24 @@ if (! (octave_env::absolute_pathname (fname) || octave_env::rooted_relative_pathname (fname))) { + // Load path will also search "." first, but we don't want to + // issue a warning if the file is found in the current directory, + // so do an explicit check for that. + file_stat fs (fname); if (! (fs.exists () && fs.is_reg ())) { + // Not directly found; search load path. + std::string tmp = octave_env::make_absolute (load_path::find_file (fname)); if (! tmp.empty ()) { warning_with_id ("Octave:load-file-in-path", - "load: file found in load path"); + "load: file found in load path: %s", + tmp.c_str ()); fname = tmp; } } @@ -1065,7 +1072,8 @@ string_vector retval; int argc = argv.length (); - bool do_double = false, do_tabs = false; + bool do_double = false; + bool do_tabs = false; for (int i = 0; i < argc; i++) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/lookup.cc --- a/libinterp/corefcn/lookup.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/lookup.cc Fri Mar 07 13:02:43 2014 -0500 @@ -115,7 +115,8 @@ octave_value retval; Array idx = array.lookup (values); - octave_idx_type n = array.numel (), nval = values.numel (); + octave_idx_type n = array.numel (); + octave_idx_type nval = values.numel (); // Post-process. if (match_bool) @@ -246,7 +247,8 @@ return retval; } - octave_value table = args(0), y = args(1); + octave_value table = args(0); + octave_value y = args(1); if (table.ndims () > 2 || (table.columns () > 1 && table.rows () > 1)) warning ("lookup: table is not a vector"); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/ls-hdf5.cc --- a/libinterp/corefcn/ls-hdf5.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/ls-hdf5.cc Fri Mar 07 13:02:43 2014 -0500 @@ -738,7 +738,8 @@ hsize_t sz = d.length (); OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, sz); bool empty = false; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid = -1; + hid_t data_hid = -1; int retval; for (hsize_t i = 0; i < sz; i++) { @@ -865,7 +866,9 @@ bool mark_as_global, bool save_as_floats) { hsize_t dims[3]; - hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1; + hid_t type_id, space_id, data_id, data_type_id; + type_id = space_id = data_id = data_type_id = -1; + bool retval = false; octave_value val = tc; // FIXME: diagonal & permutation matrices currently don't know how to save diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/ls-mat5.cc --- a/libinterp/corefcn/ls-mat5.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/ls-mat5.cc Fri Mar 07 13:02:43 2014 -0500 @@ -929,7 +929,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); + = load_fcn_from_file (str, dir_name, "", "", fname); if (fcn) { @@ -958,7 +958,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); + = load_fcn_from_file (str, dir_name, "", "", fname); if (fcn) { @@ -983,7 +983,7 @@ std::string dir_name = fpath.substr (0, xpos); octave_function *fcn - = load_fcn_from_file (fpath, dir_name, "", fname); + = load_fcn_from_file (fpath, dir_name, "", "", fname); if (fcn) { @@ -1560,7 +1560,8 @@ read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet, const std::string& filename) { - int16_t version=0, magic=0; + int16_t version = 0; + int16_t magic = 0; uint64_t subsys_offset; is.seekg (116, std::ios::beg); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/lu.cc --- a/libinterp/corefcn/lu.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/lu.cc Fri Mar 07 13:02:43 2014 -0500 @@ -158,7 +158,7 @@ int n = 1; while (n < nargin && ! error_state) { - if (args (n).is_string ()) + if (args(n).is_string ()) { std::string tmp = args(n++).string_value (); @@ -592,7 +592,9 @@ bool check_lu_dims (const octave_value& l, const octave_value& u, const octave_value& p) { - octave_idx_type m = l.rows (), k = u.rows (), n = u.columns (); + octave_idx_type m = l.rows (); + octave_idx_type k = u.rows (); + octave_idx_type n = u.columns (); return ((l.ndims () == 2 && u.ndims () == 2 && k == l.columns ()) && k == std::min (m, n) && (p.is_undefined () || p.rows () == m)); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/mappers.cc --- a/libinterp/corefcn/mappers.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/mappers.cc Fri Mar 07 13:02:43 2014 -0500 @@ -2156,8 +2156,17 @@ %!assert (tolower ({"ABC", "DEF", {"GHI", {"JKL"}}}), {"abc", "def", {"ghi", {"jkl"}}}) %!assert (tolower (["ABC"; "DEF"]), ["abc"; "def"]) %!assert (tolower ({["ABC"; "DEF"]}), {["abc";"def"]}) -%!assert (tolower (68), "d") -%!assert (tolower ({[68, 68; 68, 68]}), {["dd";"dd"]}) +%!assert (tolower (68), 68) +%!assert (tolower ({[68, 68; 68, 68]}), {[68, 68; 68, 68]}) +%!test +%! classes = {@char, @double, @single, ... +%! @int8, @int16, @int32, @int64, ... +%! @uint8, @uint16, @uint32, @uint64}; +%! for i = 1:numel (classes) +%! cls = classes{i}; +%! assert (class (tolower (cls (97))), class (cls (97))); +%! assert (class (tolower (cls ([98, 99]))), class (cls ([98, 99]))); +%! endfor %!test %! a(3,3,3,3) = "D"; %! assert (tolower (a)(3,3,3,3), "d"); @@ -2207,8 +2216,17 @@ %!assert (toupper ({"abc", "def", {"ghi", {"jkl"}}}), {"ABC", "DEF", {"GHI", {"JKL"}}}) %!assert (toupper (["abc"; "def"]), ["ABC"; "DEF"]) %!assert (toupper ({["abc"; "def"]}), {["ABC";"DEF"]}) -%!assert (toupper (100), "D") -%!assert (toupper ({[100, 100; 100, 100]}), {["DD";"DD"]}) +%!assert (toupper (100), 100) +%!assert (toupper ({[100, 100; 100, 100]}), {[100, 100; 100, 100]}) +%!test +%! classes = {@char, @double, @single, ... +%! @int8, @int16, @int32, @int64, ... +%! @uint8, @uint16, @uint32, @uint64}; +%! for i = 1:numel (classes) +%! cls = classes{i}; +%! assert (class (toupper (cls (97))), class (cls (97))); +%! assert (class (toupper (cls ([98, 99]))), class (cls ([98, 99]))); +%! endfor %!test %! a(3,3,3,3) = "d"; %! assert (toupper (a)(3,3,3,3), "D"); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/matrix_type.cc --- a/libinterp/corefcn/matrix_type.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/matrix_type.cc Fri Mar 07 13:02:43 2014 -0500 @@ -281,7 +281,7 @@ && (str_typ == "upper" || str_typ == "lower")) { const ColumnVector perm = - ColumnVector (args (2).vector_value ()); + ColumnVector (args(2).vector_value ()); if (error_state) error ("matrix_type: Invalid permutation vector PERM"); @@ -454,7 +454,7 @@ || str_typ == "lower")) { const ColumnVector perm = - ColumnVector (args (2).vector_value ()); + ColumnVector (args(2).vector_value ()); if (error_state) error ("matrix_type: Invalid permutation vector PERM"); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/max.cc --- a/libinterp/corefcn/max.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/max.cc Fri Mar 07 13:02:43 2014 -0500 @@ -354,8 +354,10 @@ } else if (nargin == 2) { - octave_value argx = args(0), argy = args(1); - builtin_type_t xtyp = argx.builtin_type (), ytyp = argy.builtin_type (); + octave_value argx = args(0); + octave_value argy = args(1); + builtin_type_t xtyp = argx.builtin_type (); + builtin_type_t ytyp = argy.builtin_type (); builtin_type_t rtyp; if (xtyp == btyp_char && ytyp == btyp_char) rtyp = btyp_char; @@ -560,6 +562,10 @@ %! assert (ndims(i), 2); %! assert (i, [1, 1; 1, 1]); +## Test for bug #40743 +%!assert (max (zeros (1,0), ones (1,1)), zeros (1,0)) +%!assert (max (sparse (zeros (1,0)), sparse (ones (1,1))), sparse (zeros (1,0))) + %!error max () %!error max (1, 2, 3, 4) */ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/oct-map.cc --- a/libinterp/corefcn/oct-map.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/oct-map.cc Fri Mar 07 13:02:43 2014 -0500 @@ -117,7 +117,8 @@ { bool retval = true; - iterator p = begin (), q = other.begin (); + iterator p = begin (); + iterator q = other.begin (); for (; p != end () && q != other.end (); p++, q++) { if (p->first == q->first) @@ -251,15 +252,6 @@ } } -octave_map::octave_map (const Octave_map& m) - : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ()) -{ - for (iterator p = begin (); p != end (); p++) - contents(p) = m.contents (key (p)); - - optimize_dimensions (); -} - Cell octave_map::getfield (const std::string& k) const { @@ -819,9 +811,9 @@ %! sr = [s,s]; %! sc = [s;s]; %! sm = [s,s;s,s]; -%! assert (nfields (sr), 0); -%! assert (nfields (sc), 0); -%! assert (nfields (sm), 0); +%! assert (numfields (sr), 0); +%! assert (numfields (sc), 0); +%! assert (numfields (sm), 0); %! assert (size (sr), [1, 2]); %! assert (size (sc), [2, 1]); %! assert (size (sm), [2, 2]); @@ -1314,470 +1306,3 @@ } -Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals) - : map (), key_list (), dimensions (dv) -{ - Cell c (dv); - - if (key_vals.is_cellstr ()) - { - for (octave_idx_type i = 0; i < key_vals.numel (); i++) - { - std::string k = key_vals(i).string_value (); - map[k] = c; - key_list.push_back (k); - } - } - else - error ("Octave_map: expecting keys to be cellstr"); -} - -Octave_map::Octave_map (const octave_map& m) - : map (), key_list (), dimensions (m.dims ()) -{ - for (octave_map::const_iterator p = m.begin (); p != m.end (); p++) - map[m.key (p)] = m.contents (p); - const string_vector mkeys = m.fieldnames (); - for (octave_idx_type i = 0; i < mkeys.numel (); i++) - key_list.push_back (mkeys(i)); -} - -Octave_map -Octave_map::squeeze (void) const -{ - Octave_map retval (dims ().squeeze ()); - - for (const_iterator pa = begin (); pa != end (); pa++) - { - Cell tmp = contents (pa).squeeze (); - - if (error_state) - break; - - retval.assign (key (pa), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Octave_map -Octave_map::permute (const Array& vec, bool inv) const -{ - Octave_map retval (dims ()); - - for (const_iterator pa = begin (); pa != end (); pa++) - { - Cell tmp = contents (pa).permute (vec, inv); - - if (error_state) - break; - - retval.assign (key (pa), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Cell& -Octave_map::contents (const std::string& k) -{ - maybe_add_to_key_list (k); - - return map[k]; -} - -Cell -Octave_map::contents (const std::string& k) const -{ - const_iterator p = seek (k); - - return p != end () ? p->second : Cell (); -} - -int -Octave_map::intfield (const std::string& k, int def_val) const -{ - int retval = def_val; - - Cell c = contents (k); - - if (! c.is_empty ()) - retval = c(0).int_value (); - - return retval; -} - -std::string -Octave_map::stringfield (const std::string& k, - const std::string& def_val) const -{ - std::string retval = def_val; - - Cell c = contents (k); - - if (! c.is_empty ()) - retval = c(0).string_value (); - - return retval; -} - -string_vector -Octave_map::keys (void) const -{ - assert (static_cast(nfields ()) == key_list.size ()); - - return string_vector (key_list); -} - -Octave_map -Octave_map::transpose (void) const -{ - assert (ndims () == 2); - - dim_vector dv = dims (); - - octave_idx_type nr = dv(0); - octave_idx_type nc = dv(1); - - dim_vector new_dims (nc, nr); - - Octave_map retval (new_dims); - - for (const_iterator p = begin (); p != end (); p++) - retval.assign (key(p), Cell (contents(p).transpose ())); - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Octave_map -Octave_map::reshape (const dim_vector& new_dims) const -{ - Octave_map retval; - - if (new_dims != dims ()) - { - for (const_iterator p = begin (); p != end (); p++) - retval.assign (key(p), contents(p).reshape (new_dims)); - - retval.dimensions = new_dims; - - // Preserve order of keys. - retval.key_list = key_list; - } - else - retval = *this; - - return retval; -} - -void -Octave_map::resize (const dim_vector& dv, bool fill) -{ - if (dv != dims ()) - { - if (nfields () == 0) - dimensions = dv; - else - { - for (const_iterator p = begin (); p != end (); p++) - { - Cell tmp = contents(p); - - if (fill) - tmp.resize (dv, Matrix ()); - else - tmp.resize (dv); - - dimensions = dv; - - assign (key(p), tmp); - } - } - } -} - -Octave_map -Octave_map::concat (const Octave_map& rb, const Array& ra_idx) -{ - Octave_map retval; - - if (nfields () == rb.nfields ()) - { - for (const_iterator pa = begin (); pa != end (); pa++) - { - const_iterator pb = rb.seek (key(pa)); - - if (pb == rb.end ()) - { - error ("field name mismatch in structure concatenation"); - break; - } - - retval.assign (key(pa), - contents(pa).insert (rb.contents(pb), ra_idx)); - } - - // Preserve order of keys. - retval.key_list = key_list; - } - else - { - dim_vector dv = dims (); - - if (dv.all_zero ()) - retval = rb; - else - { - dv = rb.dims (); - - if (dv.all_zero ()) - retval = *this; - else - error ("invalid structure concatenation"); - } - } - - return retval; -} - -static bool -keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys) -{ - bool retval = false; - - keys = string_vector (); - - if (a.nfields () == 0) - { - keys = b.keys (); - retval = true; - } - else - { - string_vector a_keys = a.keys ().sort (); - string_vector b_keys = b.keys ().sort (); - - octave_idx_type a_len = a_keys.length (); - octave_idx_type b_len = b_keys.length (); - - if (a_len == b_len) - { - for (octave_idx_type i = 0; i < a_len; i++) - { - if (a_keys[i] != b_keys[i]) - goto done; - } - - keys = a_keys; - retval = true; - } - } - -done: - return retval; -} - -Octave_map& -Octave_map::maybe_delete_elements (const octave_value_list& idx) -{ - string_vector t_keys = keys (); - octave_idx_type len = t_keys.length (); - - if (len > 0) - { - for (octave_idx_type i = 0; i < len; i++) - { - std::string k = t_keys[i]; - - contents(k).delete_elements (idx); - - if (error_state) - break; - } - - if (!error_state) - dimensions = contents(t_keys[0]).dims (); - } - - return *this; -} - -Octave_map& -Octave_map::assign (const octave_value_list& idx, const Octave_map& rhs) -{ - string_vector t_keys; - - if (keys_ok (*this, rhs, t_keys)) - { - octave_idx_type len = t_keys.length (); - - if (len == 0) - { - Cell tmp_lhs (dims ()); - Cell tmp_rhs (rhs.dims ()); - - tmp_lhs.assign (idx, tmp_rhs, Matrix ()); - - if (! error_state) - resize (tmp_lhs.dims ()); - else - error ("size mismatch in structure assignment"); - } - else - { - for (octave_idx_type i = 0; i < len; i++) - { - std::string k = t_keys[i]; - - Cell t_rhs = rhs.contents (k); - - assign (idx, k, t_rhs); - - if (error_state) - break; - } - } - } - else - error ("field name mismatch in structure assignment"); - - return *this; -} - -Octave_map& -Octave_map::assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs) -{ - Cell tmp; - - if (contains (k)) - tmp = map[k]; - else - tmp = Cell (dimensions); - - tmp.assign (idx, rhs); - - if (! error_state) - { - dim_vector tmp_dims = tmp.dims (); - - if (tmp_dims != dimensions) - { - for (iterator p = begin (); p != end (); p++) - contents(p).resize (tmp_dims, Matrix ()); - - dimensions = tmp_dims; - } - - maybe_add_to_key_list (k); - - map[k] = tmp; - } - - return *this; -} - -Octave_map& -Octave_map::assign (const std::string& k, const octave_value& rhs) -{ - if (nfields () == 0) - { - maybe_add_to_key_list (k); - - map[k] = Cell (rhs); - - dimensions = dim_vector (1, 1); - } - else - { - dim_vector dv = dims (); - - if (dv.all_ones ()) - { - maybe_add_to_key_list (k); - - map[k] = Cell (rhs); - } - else - error ("invalid structure assignment"); - } - - return *this; -} - -Octave_map& -Octave_map::assign (const std::string& k, const Cell& rhs) -{ - if (nfields () == 0) - { - maybe_add_to_key_list (k); - - map[k] = rhs; - - dimensions = rhs.dims (); - } - else - { - if (dims () == rhs.dims ()) - { - maybe_add_to_key_list (k); - - map[k] = rhs; - } - else - error ("invalid structure assignment"); - } - - return *this; -} - -Octave_map -Octave_map::index (const octave_value_list& idx, bool resize_ok) const -{ - Octave_map retval; - - octave_idx_type n_idx = idx.length (); - - if (n_idx > 0) - { - Array ra_idx (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ra_idx(i) = idx(i).index_vector (); - if (error_state) - break; - } - - if (! error_state) - { - for (const_iterator p = begin (); p != end (); p++) - { - Cell tmp = contents (p); - - tmp = tmp.Array::index (ra_idx, resize_ok); - - if (error_state) - break; - - retval.assign (key(p), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - } - } - else - retval = *this; - - return retval; -} diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/oct-map.h --- a/libinterp/corefcn/oct-map.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/oct-map.h Fri Mar 07 13:02:43 2014 -0500 @@ -287,8 +287,6 @@ octave_map (const octave_scalar_map& m); - octave_map (const Octave_map& m); - octave_map& operator = (const octave_map& m) { xkeys = m.xkeys; @@ -475,189 +473,4 @@ inline octave_map octave_value_extract (const octave_value& v) { return v.map_value (); } -// The original Octave_map object which is now deprecated. -// It was fully deprecated in version 3.8 and should be removed in 3.12. -// Octave_map and octave_map are convertible to each other. - -class -OCTINTERP_API -Octave_map -{ -public: - - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - - typedef std::list::iterator key_list_iterator; - typedef std::list::const_iterator const_key_list_iterator; - - // Warning! You should always use at least two dimensions. - - Octave_map (const dim_vector& dv = dim_vector (0, 0), - const Cell& key_vals = Cell ()); - - Octave_map (const std::string& k, const octave_value& value) - : map (), key_list (), dimensions (1, 1) - { - map[k] = value; - key_list.push_back (k); - } - - Octave_map (const string_vector& sv, - const dim_vector& dv = dim_vector (0, 0)) - : map (), key_list (), dimensions (dv) - { - for (octave_idx_type i = 0; i < sv.length (); i++) - { - std::string k = sv[i]; - map[k] = Cell (dv); - key_list.push_back (k); - } - } - - Octave_map (const std::string& k, const Cell& vals) - : map (), key_list (), dimensions (vals.dims ()) - { - map[k] = vals; - key_list.push_back (k); - } - - Octave_map (const std::string& k, const octave_value_list& val_list) - : map (), key_list (), dimensions (1, val_list.length ()) - { - map[k] = val_list; - key_list.push_back (k); - } - - Octave_map (const Octave_map& m) - : map (m.map), key_list (m.key_list), dimensions (m.dimensions) { } - - Octave_map (const octave_map& m); - - Octave_map& operator = (const Octave_map& m) - { - if (this != &m) - { - map = m.map; - key_list = m.key_list; - dimensions = m.dimensions; - } - - return *this; - } - - ~Octave_map (void) { } - - Octave_map squeeze (void) const; - - Octave_map permute (const Array& vec, bool inv = false) const; - - // This is the number of keys. - octave_idx_type nfields (void) const { return map.size (); } - - void del (const std::string& k) - { - iterator p = map.find (k); - - if (p != map.end ()) - { - map.erase (p); - - key_list_iterator q - = std::find (key_list.begin (), key_list.end (), k); - - assert (q != key_list.end ()); - - key_list.erase (q); - } - } - - iterator begin (void) { return iterator (map.begin ()); } - const_iterator begin (void) const { return const_iterator (map.begin ()); } - - iterator end (void) { return iterator (map.end ()); } - const_iterator end (void) const { return const_iterator (map.end ()); } - - std::string key (const_iterator p) const { return p->first; } - - Cell& contents (const std::string& k); - Cell contents (const std::string& k) const; - - Cell& contents (iterator p) - { return p->second; } - - Cell contents (const_iterator p) const - { return p->second; } - - int intfield (const std::string& k, int def_val = 0) const; - - std::string stringfield (const std::string& k, - const std::string& def_val = std::string ()) const; - - iterator seek (const std::string& k) { return map.find (k); } - const_iterator seek (const std::string& k) const { return map.find (k); } - - bool contains (const std::string& k) const - { return (seek (k) != map.end ()); } - - void clear (void) - { - map.clear (); - key_list.clear (); - } - - string_vector keys (void) const; - - octave_idx_type rows (void) const { return dimensions(0); } - - octave_idx_type columns (void) const { return dimensions(1); } - - dim_vector dims (void) const { return dimensions; } - - int ndims (void) const { return dimensions.length (); } - - Octave_map transpose (void) const; - - Octave_map reshape (const dim_vector& new_dims) const; - - void resize (const dim_vector& dv, bool fill = false); - - octave_idx_type numel (void) const { return dimensions.numel (); } - - Octave_map concat (const Octave_map& rb, - const Array& ra_idx); - - Octave_map& maybe_delete_elements (const octave_value_list& idx); - - Octave_map& assign (const octave_value_list& idx, const Octave_map& rhs); - - Octave_map& assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs); - - Octave_map& assign (const std::string& k, const octave_value& rhs); - - Octave_map& assign (const std::string& k, const Cell& rhs); - - Octave_map index (const octave_value_list& idx, - bool resize_ok = false) const; - -private: - - // The map of names to values. - std::map map; - - // An extra list of keys, so we can keep track of the order the keys - // are added for compatibility with you know what. - std::list key_list; - - // The current size. - mutable dim_vector dimensions; - - void maybe_add_to_key_list (const std::string& k) - { - if (! contains (k)) - key_list.push_back (k); - } -} GCC_ATTR_DEPRECATED; - #endif diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/oct-obj.cc --- a/libinterp/corefcn/oct-obj.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/oct-obj.cc Fri Mar 07 13:02:43 2014 -0500 @@ -35,7 +35,8 @@ octave_value_list::octave_value_list (const std::list& lst) { - octave_idx_type n = 0, nel = 0; + octave_idx_type n = 0; + octave_idx_type nel = 0; // Determine number. for (std::list::const_iterator p = lst.begin (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/oct-obj.h --- a/libinterp/corefcn/oct-obj.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/oct-obj.h Fri Mar 07 13:02:43 2014 -0500 @@ -107,10 +107,16 @@ octave_value_list slice (octave_idx_type offset, octave_idx_type len, bool tags = false) const { - octave_value_list retval (data.linear_slice (offset, offset + len)); + // linear_slice uses begin/end indices instead of offset and + // length. Avoid calling with upper bound out of range. + // linear_slice handles the case of len < 0. + + octave_value_list retval + = data.linear_slice (offset, std::min (offset + len, length ())); + if (tags && len > 0 && names.length () > 0) - retval.names = names.linear_slice (offset, - std::min (len, names.length ())); + retval.names = names.linear_slice (offset, std::min (offset + len, + names.length ())); return retval; } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/oct-stream.cc --- a/libinterp/corefcn/oct-stream.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/oct-stream.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1053,7 +1053,8 @@ { std::istream& is = *isp; - int c = 0, lastc = -1; + int c = 0; + int lastc = -1; cnt = 0; while (is && (c = is.get ()) != EOF) @@ -2357,15 +2358,15 @@ return retval; } -#define DO_DOUBLE_CONV(TQUAL) \ +#define DO_DOUBLE_CONV_1(TYPE) \ do \ { \ - if (val > std::numeric_limits::max () \ - || val < std::numeric_limits::min ()) \ + if (val > std::numeric_limits::max () \ + || val < std::numeric_limits::min ()) \ { \ std::string tfmt = fmt; \ \ - tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \ + tfmt.replace (tfmt.rfind (elt->type), 1, ".g"); \ \ if (elt->modifier == 'l') \ tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \ @@ -2375,7 +2376,17 @@ } \ else \ retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \ - static_cast (val), who); \ + static_cast (val), who); \ + } \ + while (0) + +#define DO_DOUBLE_CONV(TQUAL) \ + do \ + { \ + if (elt->modifier == 'l') \ + DO_DOUBLE_CONV_1 (TQUAL long); \ + else \ + DO_DOUBLE_CONV_1 (TQUAL int); \ } \ while (0) @@ -2478,15 +2489,19 @@ const char *tval; if (xisinf (val)) - if (elt->flags.find ('+') != std::string::npos) - tval = (val < 0 ? "-Inf" : "+Inf"); - else - tval = (val < 0 ? "-Inf" : "Inf"); + { + if (elt->flags.find ('+') != std::string::npos) + tval = (val < 0 ? "-Inf" : "+Inf"); + else + tval = (val < 0 ? "-Inf" : "Inf"); + } else - if (elt->flags.find ('+') != std::string::npos) - tval = (lo_ieee_is_NA (val) ? "+NA" : "+NaN"); - else - tval = (lo_ieee_is_NA (val) ? "NA" : "NaN"); + { + if (elt->flags.find ('+') != std::string::npos) + tval = (lo_ieee_is_NA (val) ? "+NA" : "+NaN"); + else + tval = (lo_ieee_is_NA (val) ? "NA" : "NaN"); + } retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/pinv.cc --- a/libinterp/corefcn/pinv.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/pinv.cc Fri Mar 07 13:02:43 2014 -0500 @@ -76,22 +76,45 @@ if (arg.is_diag_matrix ()) { - if (nargin == 2) - warning ("pinv: tol is ignored for diagonal matrices"); - - if (arg.is_complex_type ()) + if (isfloat) { - if (isfloat) - retval = arg.float_complex_diag_matrix_value ().pseudo_inverse (); + float tol = 0.0; + if (nargin == 2) + tol = args(1).float_value (); + + if (error_state) + return retval; + + if (tol < 0.0) + { + error ("pinv: TOL must be greater than zero"); + return retval; + } + + if (arg.is_real_type ()) + retval = arg.float_diag_matrix_value ().pseudo_inverse (tol); else - retval = arg.complex_diag_matrix_value ().pseudo_inverse (); + retval = arg.float_complex_diag_matrix_value ().pseudo_inverse (tol); } else { - if (isfloat) - retval = arg.float_diag_matrix_value ().pseudo_inverse (); + double tol = 0.0; + if (nargin == 2) + tol = args(1).double_value (); + + if (error_state) + return retval; + + if (tol < 0.0) + { + error ("pinv: TOL must be greater than zero"); + return retval; + } + + if (arg.is_real_type ()) + retval = arg.diag_matrix_value ().pseudo_inverse (tol); else - retval = arg.diag_matrix_value ().pseudo_inverse (); + retval = arg.complex_diag_matrix_value ().pseudo_inverse (tol); } } else if (arg.is_perm_matrix ()) @@ -189,4 +212,20 @@ %!assert (y*x*y, y, -hitol) %!assert ((x*y)', x*y, hitol) %!assert ((y*x)', y*x, hitol) + +## Clear shared variables +%!shared + +## Test pinv for Diagonal matrices +%!test +%! x = diag ([3 2 1 0 -0.5]); +%! y = pinv (x); +%! assert (typeinfo (y)(1:8), "diagonal"); +%! assert (isa (y, "double")); +%! assert (diag (y), [1/3, 1/2, 1, 0 1/-0.5]'); +%! y = pinv (x, 1); +%! assert (diag (y), [1/3 1/2 1 0 0]'); +%! y = pinv (x, 2); +%! assert (diag (y), [1/3 1/2 0 0 0]'); + */ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/pr-output.cc --- a/libinterp/corefcn/pr-output.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/pr-output.cc Fri Mar 07 13:02:43 2014 -0500 @@ -3387,8 +3387,7 @@ } void -octave_print_internal (std::ostream&, const octave_value&, - bool pr_as_read_syntax) +octave_print_internal (std::ostream&, const octave_value&, bool) { panic_impossible (); } @@ -3439,7 +3438,7 @@ rat_format = true; std::ostringstream buf; - args(0).print (buf); + arg.print (buf); std::string s = buf.str (); std::list lst; @@ -3501,11 +3500,12 @@ if (nargin == 1 && nargout < 2) { + octave_value arg = args(0); + if (nargout == 0) - args(0).print (octave_stdout); + arg.print (octave_stdout); else { - octave_value arg = args(0); std::ostringstream buf; arg.print (buf); retval = octave_value (buf.str (), arg.is_dq_string () ? '"' : '\''); @@ -3542,7 +3542,7 @@ if (nargin == 2) { - int fid = octave_stream_list::get_file_number (args (0)); + int fid = octave_stream_list::get_file_number (args(0)); octave_stream os = octave_stream_list::lookup (fid, "fdisp"); @@ -3550,8 +3550,10 @@ { std::ostream *osp = os.output_stream (); + octave_value arg = args(1); + if (osp) - args(1).print (*osp); + arg.print (*osp); else error ("fdisp: stream FID not open for writing"); } @@ -3666,6 +3668,38 @@ set_output_prec_and_fw (5, 10); } + else if (arg == "shorte") + { + init_format_state (); + print_e = true; + set_output_prec_and_fw (5, 10); + } + else if (arg == "shortE") + { + init_format_state (); + print_e = true; + print_big_e = true; + set_output_prec_and_fw (5, 10); + } + else if (arg == "shortg") + { + init_format_state (); + print_g = true; + set_output_prec_and_fw (5, 10); + } + else if (arg == "shortG") + { + init_format_state (); + print_g = true; + print_big_e = true; + set_output_prec_and_fw (5, 10); + } + else if (arg == "shortEng") + { + init_format_state (); + print_eng = true; + set_output_prec_and_fw (5, 10); + } else if (arg == "long") { if (--argc > 0) @@ -3711,6 +3745,38 @@ set_output_prec_and_fw (15, 20); } + else if (arg == "longe") + { + init_format_state (); + print_e = true; + set_output_prec_and_fw (15, 20); + } + else if (arg == "longE") + { + init_format_state (); + print_e = true; + print_big_e = true; + set_output_prec_and_fw (15, 20); + } + else if (arg == "longg") + { + init_format_state (); + print_g = true; + set_output_prec_and_fw (15, 20); + } + else if (arg == "longG") + { + init_format_state (); + print_g = true; + print_big_e = true; + set_output_prec_and_fw (15, 20); + } + else if (arg == "longEng") + { + init_format_state (); + print_eng = true; + set_output_prec_and_fw (15, 20); + } else if (arg == "hex") { init_format_state (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/pt-jit.cc --- a/libinterp/corefcn/pt-jit.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/pt-jit.cc Fri Mar 07 13:02:43 2014 -0500 @@ -46,6 +46,8 @@ static int Vjit_startcnt = 1000; +static int Vjit_failure_count = 0; + #include #include #include @@ -164,7 +166,7 @@ if (expr) { jit_variable *retvar = get_variable ("#return"); - jit_value *retval; + jit_value *retval = 0; try { retval = visit (expr); @@ -230,13 +232,13 @@ void jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_anon_fcn_handle implementation"); } void jit_convert::visit_argument_list (tree_argument_list&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_argument_list implementation"); } void @@ -337,25 +339,25 @@ void jit_convert::visit_global_command (tree_global_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_global_command implemenation"); } void jit_convert::visit_persistent_command (tree_persistent_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_persistent_command implementation"); } void jit_convert::visit_decl_elt (tree_decl_elt&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_decl_elt implementation"); } void jit_convert::visit_decl_init_list (tree_decl_init_list&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_decl_init_list implementation"); } void @@ -464,37 +466,37 @@ void jit_convert::visit_complex_for_command (tree_complex_for_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_complex_for_command implementation"); } void jit_convert::visit_octave_user_script (octave_user_script&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_octave_user_script implementation"); } void jit_convert::visit_octave_user_function (octave_user_function&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_octave_user_function implementation"); } void jit_convert::visit_octave_user_function_header (octave_user_function&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_octave_user_function_header implementation"); } void jit_convert::visit_octave_user_function_trailer (octave_user_function&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_octave_user_function_trailer implementation"); } void jit_convert::visit_function_def (tree_function_def&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_function_def implementation"); } void @@ -518,7 +520,7 @@ void jit_convert::visit_if_clause (tree_if_clause&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_if_clause implementation"); } void @@ -539,7 +541,6 @@ // the condition check for the ith clause. For the else, it is simple the // else body. If there is no else body, then it is padded with the tail std::vector entry_blocks (lst.size () + 1 - last_else); - std::vector branch_blocks (lst.size (), 0); // final blocks entry_blocks[0] = block; // we need to construct blocks first, because they have jumps to eachother @@ -630,25 +631,25 @@ void jit_convert::visit_matrix (tree_matrix&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_matrix implementation"); } void jit_convert::visit_cell (tree_cell&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_cell implementation"); } void jit_convert::visit_multi_assignment (tree_multi_assignment&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_multi_assignment implementation"); } void jit_convert::visit_no_op_command (tree_no_op_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_no_op_command implementation"); } void @@ -679,13 +680,19 @@ void jit_convert::visit_fcn_handle (tree_fcn_handle&) { + throw jit_fail_exception ("No visit_fcn_handle implementation"); +} + +void +jit_convert::visit_funcall (tree_funcall&) +{ throw jit_fail_exception (); } void jit_convert::visit_parameter_list (tree_parameter_list&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_parameter_list implementation"); } void @@ -721,13 +728,13 @@ void jit_convert::visit_return_command (tree_return_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_return_command implementation"); } void jit_convert::visit_return_list (tree_return_list&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_return_list implementation"); } void @@ -805,31 +812,132 @@ void jit_convert::visit_switch_case (tree_switch_case&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_switch_case implementation"); } void jit_convert::visit_switch_case_list (tree_switch_case_list&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_switch_case_list implementation"); } void -jit_convert::visit_switch_command (tree_switch_command&) +jit_convert::visit_switch_command (tree_switch_command& cmd) { - throw jit_fail_exception (); + tree_switch_case_list *lst = cmd.case_list (); + + // always visit switch expression + tree_expression *expr = cmd.switch_value (); + assert (expr && "Switch value can not be null"); + jit_value *value = visit (expr); + assert (value); + + size_t case_blocks_num = lst->size (); + + if (! case_blocks_num) // there's nothing to do + return; + + // check for otherwise, it's interpreted as last 'else' condition + size_t has_otherwise = 0; + tree_switch_case *last = lst->back (); + if (last->is_default_case ()) + has_otherwise = 1; + + std::vector entry_blocks (case_blocks_num + 1 - has_otherwise); + + // the first entry point is always the actual block. afterward new blocks + // are created for every case and the otherwise branch + entry_blocks[0] = block; + for (size_t i = 1; i < case_blocks_num; ++i) + entry_blocks[i] = factory.create ("case_cond"); + + jit_block *tail = factory.create ("switch_tail"); + + // if there's no otherwise branch, the the 'else' of the last branch + // has to point to the tail + if (! has_otherwise) + entry_blocks[entry_blocks.size()-1] = tail; + + // each branch in the case statement will have different breaks/continues + block_list current_breaks = breaks; + block_list current_continues = continues; + breaks.clear (); + continues.clear (); + + size_t num_incomming = 0; // number of incomming blocks to our tail + + tree_switch_case_list::iterator iter = lst->begin (); + for (size_t i = 0; i < case_blocks_num; ++iter, ++i) + { + tree_switch_case *twc = *iter; + block = entry_blocks[i]; // case_cond + assert (block); + + if (i) + blocks.push_back (entry_blocks[i]); // first block already pushed + + if (! twc->is_default_case ()) + { + // compare result of switch expression with actual case label + tree_expression *te = twc->case_label (); + jit_value *label = visit (te); + assert(label); + + const jit_operation& fn = jit_typeinfo::binary_op (octave_value::op_eq); + jit_value *cond = create_checked (fn, value, label); + assert(cond); + + jit_call *check = create_checked (&jit_typeinfo::logically_true, + cond); + + jit_block *body = factory.create ("case_body"); + blocks.push_back (body); + + block->append (factory.create (check, body, + entry_blocks[i+1])); + block = body; // case_body + } + + tree_statement_list *stmt_lst = twc->commands (); + assert(stmt_lst); + + try + { + stmt_lst->accept (*this); + num_incomming++; + block->append (factory.create (tail)); + } + catch (const jit_break_exception&) + { } + + // each branch in the case statement will have different breaks/continues + current_breaks.splice (current_breaks.end (), breaks); + current_continues.splice (current_continues.end (), continues); + } + + // each branch in the case statement will have different breaks/continues + breaks.splice (breaks.end (), current_breaks); + continues.splice (continues.end (), current_continues); + + if (num_incomming || ! has_otherwise) + { + blocks.push_back (tail); + block = tail; // switch_tail + } + else + throw jit_break_exception (); // every branch broke } void jit_convert::visit_try_catch_command (tree_try_catch_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_try_catch_command implementation"); } void jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&) { - throw jit_fail_exception (); + throw jit_fail_exception ("No visit_unwind_protect_command implementation"); } void @@ -895,9 +1003,66 @@ } void -jit_convert::visit_do_until_command (tree_do_until_command&) +jit_convert::visit_do_until_command (tree_do_until_command& duc) { - throw jit_fail_exception (); + unwind_protect prot; + prot.protect_var (breaks); + prot.protect_var (continues); + breaks.clear (); + continues.clear (); + + jit_block *body = factory.create ("do_until_body"); + jit_block *cond_check = factory.create ("do_until_cond_check"); + jit_block *tail = factory.create ("do_until_tail"); + + block->append (factory.create (body)); + blocks.push_back (body); + block = body; + + tree_statement_list *loop_body = duc.body (); + bool all_breaking = false; + if (loop_body) + { + try + { + loop_body->accept (*this); + } + catch (const jit_break_exception&) + { + all_breaking = true; + } + } + + finish_breaks (tail, breaks); + + if (! all_breaking || continues.size ()) + { + jit_block *interrupt_check + = factory.create ("interrupt_check"); + blocks.push_back (interrupt_check); + finish_breaks (interrupt_check, continues); + if (! all_breaking) + block->append (factory.create (interrupt_check)); + + block = interrupt_check; + jit_error_check *ec + = factory.create (jit_error_check::var_interrupt, + cond_check, final_block); + block->append (ec); + + blocks.push_back (cond_check); + block = cond_check; + + tree_expression *expr = duc.condition (); + assert (expr && "Do-Until expression can not be null"); + jit_value *check = visit (expr); + check = create_checked (&jit_typeinfo::logically_true, check); + + block->append (factory.create (check, tail, body)); + } + + blocks.push_back (tail); + block = tail; } void @@ -2123,6 +2288,8 @@ std::cout << "jit fail: " << e.what () << std::endl; } + Vjit_failure_count++; + wrapper.erase (); raw_fn.erase (); } @@ -2279,6 +2446,9 @@ if (e.known ()) std::cout << "jit fail: " << e.what () << std::endl; } + + Vjit_failure_count++; + } if (llvm_function) @@ -2314,6 +2484,29 @@ #endif + +DEFUN (jit_failure_count, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} jit_failure_count ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} jit_failure_count (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} jit_failure_count (@var{new_val}, \"local\")\n\ +Query or set the internal variable that counts the number of\n\ +JIT fail exceptions for Octave's JIT compiler.\n\ +\n\ +When called from inside a function with the @qcode{\"local\"} option, the\n\ +variable is changed locally for the function and any subroutines it calls. \n\ +The original variable value is restored when exiting the function.\n\ +@seealso{jit_enable, jit_startcnt, debug_jit}\n\ +@end deftypefn") +{ +#if defined (HAVE_LLVM) + return SET_INTERNAL_VARIABLE (jit_failure_count); +#else + warning ("jit_failure_count: JIT compiling not available in this version of Octave"); + return octave_value (); +#endif +} + DEFUN (debug_jit, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} debug_jit ()\n\ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/pt-jit.h --- a/libinterp/corefcn/pt-jit.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/pt-jit.h Fri Mar 07 13:02:43 2014 -0500 @@ -129,6 +129,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/sparse.cc --- a/libinterp/corefcn/sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -113,7 +113,7 @@ if (nargin == 1) { - octave_value arg = args (0); + octave_value arg = args(0); if (arg.is_bool_type ()) retval = arg.sparse_bool_matrix_value (); else if (arg.is_complex_type ()) @@ -156,7 +156,8 @@ if (! error_state) { - octave_idx_type m = -1, n = -1, nzmax = -1; + octave_idx_type m, n, nzmax; + m = n = nzmax = -1; if (nargin == 6) { nzmax = args(5).idx_type_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/sqrtm.cc --- a/libinterp/corefcn/sqrtm.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/sqrtm.cc Fri Mar 07 13:02:43 2014 -0500 @@ -101,7 +101,8 @@ typedef typename Matrix::element_type real_type; - real_type cutoff = 0, one = 1; + real_type cutoff = 0; + real_type one = 1; real_type eps = std::numeric_limits::epsilon (); if (! iscomplex) diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/str2double.cc --- a/libinterp/corefcn/str2double.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/str2double.cc Fri Mar 07 13:02:43 2014 -0500 @@ -60,7 +60,8 @@ { // It's infinity. is.get (); - char c1 = is.get (), c2 = is.get (); + char c1 = is.get (); + char c2 = is.get (); if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f') { num = octave_Inf; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/strfind.cc --- a/libinterp/corefcn/strfind.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/strfind.cc Fri Mar 07 13:02:43 2014 -0500 @@ -209,7 +209,8 @@ if (nargin == 2) { - octave_value argstr = args(0), argpat = args(1); + octave_value argstr = args(0); + octave_value argpat = args(1); if (argpat.is_string ()) { Array needle = argpat.char_array_value (); @@ -279,7 +280,9 @@ { Array ret = str; - octave_idx_type siz = str.numel (), psiz = pat.numel (), rsiz = rep.numel (); + octave_idx_type siz = str.numel (); + octave_idx_type psiz = pat.numel (); + octave_idx_type rsiz = rep.numel (); if (psiz != 0) { @@ -312,7 +315,8 @@ retsiz = siz + nidx * (rsiz - psiz); ret.clear (dim_vector (1, retsiz)); - const char *src = str.data (), *reps = rep.data (); + const char *src = str.data (); + const char *reps = rep.data (); char *dest = ret.fortran_vec (); octave_idx_type k = 0; @@ -380,7 +384,9 @@ if (nargin == 3) { - octave_value argstr = args(0), argpat = args(1), argrep = args(2); + octave_value argstr = args(0); + octave_value argpat = args(1); + octave_value argrep = args(2); if (argpat.is_string () && argrep.is_string ()) { const Array pat = argpat.char_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/strfns.cc --- a/libinterp/corefcn/strfns.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/strfns.cc Fri Mar 07 13:02:43 2014 -0500 @@ -585,7 +585,7 @@ if (args.length () == 2) { - retval = do_strcmp_fun (args (0), args (1), 0, + retval = do_strcmp_fun (args(0), args(1), 0, "strcmp", strcmp_array_op, strcmp_str_op); } else @@ -647,7 +647,8 @@ strncmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n) { - octave_idx_type l1 = s1.numel (), l2 = s2.numel (); + octave_idx_type l1 = s1.numel (); + octave_idx_type l2 = s2.numel (); return (n > 0 && n <= l1 && n <= l2 && std::equal (s1.data (), s1.data () + n, s2.data ())); } @@ -658,7 +659,8 @@ static bool strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n) { - octave_idx_type l1 = s1.length (), l2 = s2.length (); + octave_idx_type l1 = s1.length (); + octave_idx_type l2 = s2.length (); return (n > 0 && n <= l1 && n <= l2 && std::equal (s1.data (), s1.data () + n, s2.data ())); } @@ -781,7 +783,7 @@ if (args.length () == 2) { - retval = do_strcmp_fun (args (0), args (1), 0, + retval = do_strcmp_fun (args(0), args(1), 0, "strcmpi", strcmpi_array_op, strcmpi_str_op); } else @@ -799,7 +801,8 @@ strncmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n) { - octave_idx_type l1 = s1.numel (), l2 = s2.numel (); + octave_idx_type l1 = s1.numel (); + octave_idx_type l2 = s2.numel (); return (n > 0 && n <= l1 && n <= l2 && std::equal (s1.data (), s1.data () + n, s2.data (), icmp_char_eq ())); @@ -810,7 +813,8 @@ strncmpi_str_op (const std::string& s1, const std::string& s2, octave_idx_type n) { - octave_idx_type l1 = s1.length (), l2 = s2.length (); + octave_idx_type l1 = s1.length (); + octave_idx_type l2 = s2.length (); return (n > 0 && n <= l1 && n <= l2 && std::equal (s1.data (), s1.data () + n, s2.data (), icmp_char_eq ())); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/symtab.cc --- a/libinterp/corefcn/symtab.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/symtab.cc Fri Mar 07 13:02:43 2014 -0500 @@ -38,6 +38,7 @@ #include "dirfns.h" #include "input.h" #include "load-path.h" +#include "ov-classdef.h" #include "ov-fcn.h" #include "ov-usr-fcn.h" #include "pager.h" @@ -149,6 +150,24 @@ return retval; } +static void +split_name_with_package (const std::string& name, std::string& fname, + std::string& pname) +{ + size_t pos = name.rfind ('.'); + + fname.clear (); + pname.clear (); + + if (pos != std::string::npos) + { + fname = name.substr (pos + 1); + pname = name.substr (0, pos); + } + else + fname = name; +} + // Check the load path to see if file that defined this is still // visible. If the file is no longer visible, then erase the // definition and move on. If the file is visible, then we also @@ -165,11 +184,13 @@ static inline bool load_out_of_date_fcn (const std::string& ff, const std::string& dir_name, octave_value& function, - const std::string& dispatch_type = std::string ()) + const std::string& dispatch_type = std::string (), + const std::string& package_name = std::string ()) { bool retval = false; - octave_function *fcn = load_fcn_from_file (ff, dir_name, dispatch_type); + octave_function *fcn = load_fcn_from_file (ff, dir_name, dispatch_type, + package_name); if (fcn) { @@ -206,11 +227,13 @@ bool relative = check_relative && fcn->is_relative (); - if (tc < Vlast_prompt_time + if (tc <= Vlast_prompt_time || (relative && tc < Vlast_chdir_time)) { bool clear_breakpoints = false; std::string nm = fcn->name (); + std::string pack = fcn->package_name (); + std::string canonical_nm = fcn->canonical_name (); bool is_same_file = false; @@ -235,10 +258,13 @@ if (! dispatch_type.empty ()) { file = load_path::find_method (dispatch_type, nm, - dir_name); + dir_name, pack); if (file.empty ()) { + std::string s_name; + std::string s_pack; + const std::list& plist = symbol_table::parent_classes (dispatch_type); std::list::const_iterator it @@ -246,10 +272,17 @@ while (it != plist.end ()) { + split_name_with_package (*it, s_name, + s_pack); + file = load_path::find_method (*it, nm, - dir_name); + dir_name, + s_pack); if (! file.empty ()) - break; + { + pack = s_pack; + break; + } it++; } @@ -261,7 +294,7 @@ file = lookup_autoload (nm); if (file.empty ()) - file = load_path::find_fcn (nm, dir_name); + file = load_path::find_fcn (nm, dir_name, pack); } if (! file.empty ()) @@ -303,7 +336,8 @@ { retval = load_out_of_date_fcn (ff, dir_name, function, - dispatch_type); + dispatch_type, + pack); clear_breakpoints = true; } @@ -322,7 +356,7 @@ // place of the old. retval = load_out_of_date_fcn (file, dir_name, function, - dispatch_type); + dispatch_type, pack); clear_breakpoints = true; } @@ -330,7 +364,8 @@ // If the function has been replaced then clear any // breakpoints associated with it if (clear_breakpoints) - bp_table::remove_all_breakpoints_in_file (nm, true); + bp_table::remove_all_breakpoints_in_file (canonical_nm, + true); } } } @@ -383,11 +418,13 @@ std::string dir_name; - std::string file_name = load_path::find_method (name, name, dir_name); + std::string file_name = load_path::find_method (name, name, dir_name, + package_name); if (! file_name.empty ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name, name); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, name, + package_name); if (fcn) { @@ -396,6 +433,31 @@ class_constructors[name] = retval; } } + else + { + // Classdef constructors can be defined anywhere in the path, not + // necessarily in @-folders. Look for a normal function and load it. + // If the loaded function is a classdef constructor, store it as such + // and restore function_on_path to its previous value. + + octave_value old_function_on_path = function_on_path; + + octave_value maybe_cdef_ctor = find_user_function (); + + if (maybe_cdef_ctor.is_defined ()) + { + octave_function *fcn = maybe_cdef_ctor.function_value (true); + + if (fcn && fcn->is_classdef_constructor ()) + { + retval = maybe_cdef_ctor; + + class_constructors[name] = retval; + + function_on_path = old_function_on_path; + } + } + } return retval; } @@ -406,47 +468,57 @@ { octave_value retval; - if (name == dispatch_type) + if (full_name () == dispatch_type) retval = load_class_constructor (); else { - std::string dir_name; + octave_function *cm = cdef_manager::find_method_symbol (name, + dispatch_type); - std::string file_name = load_path::find_method (dispatch_type, name, - dir_name); + if (cm) + retval = octave_value (cm); - if (! file_name.empty ()) + if (! retval.is_defined ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name, - dispatch_type); + std::string dir_name; - if (fcn) + std::string file_name = load_path::find_method (dispatch_type, name, + dir_name); + + if (! file_name.empty ()) { - retval = octave_value (fcn); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type); - class_methods[dispatch_type] = retval; - } - } + if (fcn) + { + retval = octave_value (fcn); - if (retval.is_undefined ()) - { - // Search parent classes + class_methods[dispatch_type] = retval; + } + } - const std::list& plist = parent_classes (dispatch_type); - - std::list::const_iterator it = plist.begin (); - - while (it != plist.end ()) + if (retval.is_undefined ()) { - retval = find_method (*it); + // Search parent classes - if (retval.is_defined ()) + const std::list& plist = + parent_classes (dispatch_type); + + std::list::const_iterator it = plist.begin (); + + while (it != plist.end ()) { - class_methods[dispatch_type] = retval; - break; + retval = find_method (*it); + + if (retval.is_defined ()) + { + class_methods[dispatch_type] = retval; + break; + } + + it++; } - - it++; } } } @@ -787,6 +859,13 @@ if (fcn.is_defined ()) return fcn; + // Package + + fcn = find_package (); + + if (fcn.is_defined ()) + return fcn; + // Built-in function (might be undefined). return built_in_function; @@ -975,7 +1054,7 @@ std::string dir_name = file_name.substr (0, pos); - octave_function *fcn = load_fcn_from_file (file_name, dir_name, + octave_function *fcn = load_fcn_from_file (file_name, dir_name, "", "", name, true); if (fcn) @@ -998,11 +1077,13 @@ { std::string dir_name; - std::string file_name = load_path::find_fcn (name, dir_name); + std::string file_name = load_path::find_fcn (name, dir_name, + package_name); if (! file_name.empty ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, "", + package_name); if (fcn) function_on_path = octave_value (fcn); @@ -1012,6 +1093,25 @@ return function_on_path; } +octave_value +symbol_table::fcn_info::fcn_info_rep::find_package (void) +{ + // FIXME: implement correct way to check out of date package + //if (package.is_defined ()) + // out_of_date_check (package); + + if (! (error_state || package.is_defined ())) + { + octave_function * fcn = + cdef_manager::find_package_symbol (full_name ()); + + if (fcn) + package = octave_value (fcn); + } + + return package; +} + // Insert INF_CLASS in the set of class names that are considered // inferior to SUP_CLASS. Return FALSE if INF_CLASS is currently // marked as superior to SUP_CLASS. @@ -1069,10 +1169,11 @@ symbol_table::fcn_info::fcn_info_rep::dump (std::ostream& os, const std::string& prefix) const { - os << prefix << name + os << prefix << full_name () << " [" << (cmdline_function.is_defined () ? "c" : "") << (built_in_function.is_defined () ? "b" : "") + << (package.is_defined () ? "p" : "") << "]\n"; std::string tprefix = prefix + " "; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/symtab.h --- a/libinterp/corefcn/symtab.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/symtab.h Fri Mar 07 13:02:43 2014 -0500 @@ -756,10 +756,19 @@ public: fcn_info_rep (const std::string& nm) - : name (nm), subfunctions (), private_functions (), + : name (nm), package_name (), subfunctions (), private_functions (), class_constructors (), class_methods (), dispatch_map (), cmdline_function (), autoload_function (), function_on_path (), - built_in_function (), count (1) { } + built_in_function (), count (1) + { + size_t pos = name.rfind ('.'); + + if (pos != std::string::npos) + { + package_name = name.substr (0, pos); + name = name.substr (pos+1); + } + } octave_value load_private_function (const std::string& dir_name); @@ -775,6 +784,8 @@ octave_value find_autoload (void); + octave_value find_package (void); + octave_value find_user_function (void); bool is_user_function_defined (void) const @@ -883,6 +894,11 @@ clear_user_function (); } + void clear_package (void) + { + package = octave_value (); + } + void clear (bool force = false) { clear_map (subfunctions, force); @@ -892,6 +908,7 @@ clear_autoload_function (force); clear_user_function (force); + clear_package (); } void add_dispatch (const std::string& type, const std::string& fname) @@ -915,8 +932,18 @@ void dump (std::ostream& os, const std::string& prefix) const; + std::string full_name (void) const + { + if (package_name.empty ()) + return name; + else + return package_name + "." + name; + } + std::string name; + std::string package_name; + // Scope id to function object. std::map subfunctions; @@ -938,6 +965,8 @@ octave_value function_on_path; + octave_value package; + octave_value built_in_function; octave_refcount count; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/syscalls.cc --- a/libinterp/corefcn/syscalls.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/syscalls.cc Fri Mar 07 13:02:43 2014 -0500 @@ -511,7 +511,7 @@ if (nargin == 3) { - octave_stream strm = octave_stream_list::lookup (args (0), "fcntl"); + octave_stream strm = octave_stream_list::lookup (args(0), "fcntl"); if (! error_state) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/toplev.cc --- a/libinterp/corefcn/toplev.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/toplev.cc Fri Mar 07 13:02:43 2014 -0500 @@ -301,7 +301,8 @@ octave_map octave_call_stack::do_backtrace (size_t nskip, - octave_idx_type& curr_user_frame) const + octave_idx_type& curr_user_frame, + bool print_subfn) const { size_t user_code_frames = do_num_user_code_frames (curr_user_frame); @@ -340,7 +341,7 @@ file(k) = f->fcn_file_name (); std::string parent_fcn_name = f->parent_fcn_name (); - if (parent_fcn_name == std::string ()) + if (! print_subfn || parent_fcn_name == std::string ()) name(k) = f->name (); else name(k) = f->parent_fcn_name () + Vfilemarker + f->name (); @@ -1274,8 +1275,6 @@ { false, "CAMD_LIBS", OCTAVE_CONF_CAMD_LIBS }, { false, "CARBON_LIBS", OCTAVE_CONF_CARBON_LIBS }, { false, "CC", OCTAVE_CONF_CC }, - // FIXME: CC_VERSION is deprecated. Remove in version 3.12 - { false, "CC_VERSION", OCTAVE_CONF_CC_VERSION }, { false, "CCOLAMD_CPPFLAGS", OCTAVE_CONF_CCOLAMD_CPPFLAGS }, { false, "CCOLAMD_LDFLAGS", OCTAVE_CONF_CCOLAMD_LDFLAGS }, { false, "CCOLAMD_LIBS", OCTAVE_CONF_CCOLAMD_LIBS }, @@ -1298,8 +1297,6 @@ { false, "CXXCPP", OCTAVE_CONF_CXXCPP }, { false, "CXXFLAGS", OCTAVE_CONF_CXXFLAGS }, { false, "CXXPICFLAG", OCTAVE_CONF_CXXPICFLAG }, - // FIXME: CXX_VERSION is deprecated. Remove in version 3.12 - { false, "CXX_VERSION", OCTAVE_CONF_CXX_VERSION }, { false, "DEFAULT_PAGER", OCTAVE_DEFAULT_PAGER }, { false, "DEFS", OCTAVE_CONF_DEFS }, { false, "DL_LD", OCTAVE_CONF_DL_LD }, diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/toplev.h --- a/libinterp/corefcn/toplev.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/toplev.h Fri Mar 07 13:02:43 2014 -0500 @@ -278,7 +278,16 @@ static octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame) { return instance_ok () - ? instance->do_backtrace (nskip, curr_user_frame) : octave_map (); + ? instance->do_backtrace (nskip, curr_user_frame, true) + : octave_map (); + } + + static octave_map backtrace (size_t nskip, octave_idx_type& curr_user_frame, + bool print_subfn) + { + return instance_ok () + ? instance->do_backtrace (nskip, curr_user_frame, print_subfn) + : octave_map (); } static octave_map empty_backtrace (void); @@ -414,7 +423,8 @@ } octave_map do_backtrace (size_t nskip, - octave_idx_type& curr_user_frame) const; + octave_idx_type& curr_user_frame, + bool print_subfn) const; bool do_goto_frame (size_t n, bool verbose); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/tril.cc --- a/libinterp/corefcn/tril.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/tril.cc Fri Mar 07 13:02:43 2014 -0500 @@ -42,7 +42,8 @@ static Array do_tril (const Array& a, octave_idx_type k, bool pack) { - octave_idx_type nr = a.rows (), nc = a.columns (); + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.columns (); const T *avec = a.fortran_vec (); octave_idx_type zero = 0; @@ -83,7 +84,8 @@ static Array do_triu (const Array& a, octave_idx_type k, bool pack) { - octave_idx_type nr = a.rows (), nc = a.columns (); + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.columns (); const T *avec = a.fortran_vec (); octave_idx_type zero = 0; @@ -211,7 +213,7 @@ print_usage (); else { - octave_value arg = args (0); + octave_value arg = args(0); dim_vector dims = arg.dims (); if (dims.length () != 2) @@ -274,7 +276,8 @@ if (arg.numel () == 0) return arg; - octave_idx_type nr = dims(0), nc = dims (1); + octave_idx_type nr = dims(0); + octave_idx_type nc = dims(1); // The sole purpose of the below is to force the correct // matrix size. This would not be necessary if the diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/txt-eng-ft.cc --- a/libinterp/corefcn/txt-eng-ft.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/txt-eng-ft.cc Fri Mar 07 13:02:43 2014 -0500 @@ -635,7 +635,8 @@ FT_UInt glyph_index, previous = 0; std::string str = e.string_value (); - size_t n = str.length (), curr = 0; + size_t n = str.length (); + size_t curr = 0; mbstate_t ps; memset (&ps, 0, sizeof (ps)); // Initialize state to 0. wchar_t wc; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/utils.cc --- a/libinterp/corefcn/utils.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/utils.cc Fri Mar 07 13:02:43 2014 -0500 @@ -303,7 +303,7 @@ If the second optional argument @qcode{\"all\"} is supplied, return\n\ a cell array containing the list of all files that have the same\n\ name in the path. If no files are found, return an empty cell array.\n\ -@seealso{file_in_path, find_dir_in_path, path}\n\ +@seealso{file_in_path, dir_in_loadpath, path}\n\ @end deftypefn") { octave_value retval; @@ -380,7 +380,7 @@ If the third optional argument @qcode{\"all\"} is supplied, return\n\ a cell array containing the list of all files that have the same\n\ name in the path. If no files are found, return an empty cell array.\n\ -@seealso{file_in_loadpath, find_dir_in_path, path}\n\ +@seealso{file_in_loadpath, dir_in_loadpath, path}\n\ @end deftypefn") { octave_value retval; @@ -892,10 +892,10 @@ %!error make_absolute_filename ("foo", "bar") */ -DEFUN (find_dir_in_path, args, , +DEFUN (dir_in_loadpath, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} find_dir_in_path (@var{dir})\n\ -@deftypefnx {Built-in Function} {} find_dir_in_path (@var{dir}, \"all\")\n\ +@deftypefn {Built-in Function} {} dir_in_loadpath (@var{dir})\n\ +@deftypefnx {Built-in Function} {} dir_in_loadpath (@var{dir}, \"all\")\n\ Return the full name of the path element matching @var{dir}. The\n\ match is performed at the end of each path element. For example, if\n\ @var{dir} is @qcode{\"foo/bar\"}, it matches the path element\n\ @@ -926,7 +926,7 @@ retval = Cell (load_path::find_matching_dirs (dir)); } else - error ("find_dir_in_path: DIR must be a directory name"); + error ("dir_in_loadpath: DIR must be a directory name"); } else print_usage (); @@ -937,8 +937,8 @@ /* ## FIXME: We need system-dependent tests here. -%!error find_dir_in_path () -%!error find_dir_in_path ("foo", "bar", 1) +%!error dir_in_loadpath () +%!error dir_in_loadpath ("foo", "bar", 1) */ DEFUNX ("errno", Ferrno, args, , diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/variables.cc --- a/libinterp/corefcn/variables.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/variables.cc Fri Mar 07 13:02:43 2014 -0500 @@ -548,7 +548,7 @@ Check only for directories.\n\ @end table\n\ \n\ -@seealso{file_in_loadpath, file_in_path, find_dir_in_path, stat}\n\ +@seealso{file_in_loadpath, file_in_path, dir_in_loadpath, stat}\n\ @end deftypefn") { octave_value retval = false; @@ -1405,7 +1405,9 @@ param.modifier = 'r'; param.parameter_length = 0; - int a = 0, b = -1, balance = 1; + int a = 0; + int b = -1; + int balance = 1; unsigned int items; size_t pos; std::string cmd; @@ -2255,6 +2257,7 @@ { symbol_table::clear_objects (); octave_class::clear_exemplar_map (); + symbol_table::clear_all (); } else { @@ -2464,6 +2467,7 @@ { symbol_table::clear_objects (); octave_class::clear_exemplar_map (); + symbol_table::clear_all (); } else { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/corefcn/xdiv.cc --- a/libinterp/corefcn/xdiv.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/corefcn/xdiv.cc Fri Mar 07 13:02:43 2014 -0500 @@ -713,7 +713,9 @@ if (! mx_div_conform (a, d)) return MT (); - octave_idx_type m = a.rows (), n = d.rows (), l = d.length (); + octave_idx_type m = a.rows (); + octave_idx_type n = d.rows (); + octave_idx_type l = d.length (); MT x (m, n); typedef typename DMT::element_type S; typedef typename MT::element_type T; @@ -794,7 +796,10 @@ if (! mx_leftdiv_conform (d, a, blas_no_trans)) return MT (); - octave_idx_type m = d.cols (), n = a.cols (), k = a.rows (), l = d.length (); + octave_idx_type m = d.cols (); + octave_idx_type n = a.cols (); + octave_idx_type k = a.rows (); + octave_idx_type l = d.length (); MT x (m, n); typedef typename DMT::element_type S; typedef typename MT::element_type T; @@ -871,8 +876,11 @@ if (! mx_div_conform (a, d)) return MT (); - octave_idx_type m = a.rows (), n = d.rows (), k = d.cols (); - octave_idx_type l = std::min (m, n), lk = std::min (l, k); + octave_idx_type m = a.rows (); + octave_idx_type n = d.rows (); + octave_idx_type k = d.cols (); + octave_idx_type l = std::min (m, n); + octave_idx_type lk = std::min (l, k); MT x (m, n); typedef typename DMT::element_type S; typedef typename MT::element_type T; @@ -943,8 +951,11 @@ if (! mx_leftdiv_conform (d, a, blas_no_trans)) return MT (); - octave_idx_type m = d.cols (), n = a.cols (), k = d.rows (); - octave_idx_type l = std::min (m, n), lk = std::min (l, k); + octave_idx_type m = d.cols (); + octave_idx_type n = a.cols (); + octave_idx_type k = d.rows (); + octave_idx_type l = std::min (m, n); + octave_idx_type lk = std::min (l, k); MT x (m, n); typedef typename DMT::element_type S; typedef typename MT::element_type T; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/dldfcn/__delaunayn__.cc --- a/libinterp/dldfcn/__delaunayn__.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/dldfcn/__delaunayn__.cc Fri Mar 07 13:02:43 2014 -0500 @@ -175,7 +175,8 @@ facetT *facet; vertexT *vertex, **vertexp; - octave_idx_type nf = 0, i = 0; + octave_idx_type nf = 0; + octave_idx_type i = 0; FORALLfacets { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/dldfcn/qr.cc --- a/libinterp/dldfcn/qr.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/dldfcn/qr.cc Fri Mar 07 13:02:43 2014 -0500 @@ -744,7 +744,9 @@ bool check_qr_dims (const octave_value& q, const octave_value& r, bool allow_ecf = false) { - octave_idx_type m = q.rows (), k = r.rows (), n = r.columns (); + octave_idx_type m = q.rows (); + octave_idx_type k = r.rows (); + octave_idx_type n = r.columns (); return ((q.ndims () == 2 && r.ndims () == 2 && k == q.columns ()) && (m == k || (allow_ecf && k == n && k < m))); } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/dldfcn/symrcm.cc --- a/libinterp/dldfcn/symrcm.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/dldfcn/symrcm.cc Fri Mar 07 13:02:43 2014 -0500 @@ -487,7 +487,8 @@ octave_idx_type s = 0; // head- and tail-indices for the queue - octave_idx_type qt = 0, qh = 0; + octave_idx_type qt = 0; + octave_idx_type qh = 0; CMK_Node v, w; // dimension of the matrix octave_idx_type N = nr; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/dldfcn/tsearch.cc --- a/libinterp/dldfcn/tsearch.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/dldfcn/tsearch.cc Fri Mar 07 13:02:43 2014 -0500 @@ -110,8 +110,10 @@ const octave_idx_type np = xi.length (); ColumnVector values (np); - double x0 = 0.0, y0 = 0.0; - double a11 = 0.0, a12 = 0.0, a21 = 0.0, a22 = 0.0, det = 0.0; + double x0, y0, a11, a12, a21, a22, det; + x0 = y0 = 0.0; + a11 = a12 = a21 = a22 = 0.0; + det = 0.0; octave_idx_type k = nelem; // k is a counter of elements for (octave_idx_type kp = 0; kp < np; kp++) diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/module.mk --- a/libinterp/octave-value/module.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/module.mk Fri Mar 07 13:02:43 2014 -0500 @@ -36,6 +36,7 @@ octave-value/ov-cell.h \ octave-value/ov-ch-mat.h \ octave-value/ov-class.h \ + octave-value/ov-classdef.h \ octave-value/ov-colon.h \ octave-value/ov-complex.h \ octave-value/ov-cs-list.h \ @@ -94,6 +95,7 @@ octave-value/ov-cell.cc \ octave-value/ov-ch-mat.cc \ octave-value/ov-class.cc \ + octave-value/ov-classdef.cc \ octave-value/ov-colon.cc \ octave-value/ov-complex.cc \ octave-value/ov-cs-list.cc \ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-diag.cc --- a/libinterp/octave-value/ov-base-diag.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-diag.cc Fri Mar 07 13:02:43 2014 -0500 @@ -100,7 +100,6 @@ bool resize_ok) { octave_value retval; - typedef typename DMT::element_type el_type; if (idx.length () == 2 && ! resize_ok) { @@ -441,7 +440,8 @@ bool octave_base_diag::load_ascii (std::istream& is) { - octave_idx_type r = 0, c = 0; + octave_idx_type r = 0; + octave_idx_type c = 0; bool success = true; if (extract_keyword (is, "rows", r, true) @@ -505,8 +505,7 @@ template void -octave_base_diag::print (std::ostream& os, - bool pr_as_read_syntax) const +octave_base_diag::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-diag.h --- a/libinterp/octave-value/ov-base-diag.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-diag.h Fri Mar 07 13:02:43 2014 -0500 @@ -203,7 +203,7 @@ bool print_as_scalar (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_info (std::ostream& os, const std::string& prefix) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-int.cc --- a/libinterp/octave-value/ov-base-int.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-int.cc Fri Mar 07 13:02:43 2014 -0500 @@ -347,7 +347,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank); // Octave uses column-major, while HDF5 uses row-major ordering @@ -550,7 +551,8 @@ hid_t save_type_hid = HDF5_SAVE_TYPE; bool retval = true; hsize_t dimens[3]; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; space_hid = H5Screate_simple (0, dimens, 0); if (space_hid < 0) return false; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-mat.cc --- a/libinterp/octave-value/ov-base-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -351,7 +351,8 @@ { // optimize all scalar indices. Don't construct an index array, // but rather calc a scalar index directly. - octave_idx_type k = 1, j = 0; + octave_idx_type k = 1; + octave_idx_type j = 0; for (octave_idx_type i = 0; i < n_idx; i++) { j += idx_vec(i)(0) * k; @@ -435,7 +436,7 @@ template void -octave_base_matrix::print (std::ostream& os, bool pr_as_read_syntax) const +octave_base_matrix::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-mat.h --- a/libinterp/octave-value/ov-base-mat.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-mat.h Fri Mar 07 13:02:43 2014 -0500 @@ -153,7 +153,7 @@ bool print_as_scalar (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_info (std::ostream& os, const std::string& prefix) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-scalar.cc --- a/libinterp/octave-value/ov-base-scalar.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-scalar.cc Fri Mar 07 13:02:43 2014 -0500 @@ -143,7 +143,7 @@ template void -octave_base_scalar::print (std::ostream& os, bool pr_as_read_syntax) const +octave_base_scalar::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-scalar.h --- a/libinterp/octave-value/ov-base-scalar.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-scalar.h Fri Mar 07 13:02:43 2014 -0500 @@ -132,7 +132,7 @@ bool is_true (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-sparse.cc --- a/libinterp/octave-value/ov-base-sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -288,7 +288,7 @@ template void -octave_base_sparse::print (std::ostream& os, bool pr_as_read_syntax) const +octave_base_sparse::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); @@ -440,27 +440,55 @@ octave_value octave_base_sparse::map (octave_base_value::unary_mapper_t umap) const { + if (umap == umap_xtolower || umap == umap_xtoupper) + return matrix; + // Try the map on the dense value. + // FIXME: We should probably be smarter about this, especially for the + // cases that are expected to return sparse matrices. octave_value retval = this->full_value ().map (umap); // Sparsify the result if possible. - // FIXME: intentionally skip this step for string mappers. Is this wanted? - if (umap >= umap_xisalnum && umap <= umap_xtoupper) - return retval; - switch (retval.builtin_type ()) + switch (umap) { - case btyp_double: - retval = retval.sparse_matrix_value (); + case umap_xisalnum: + case umap_xisalpha: + case umap_xisascii: + case umap_xiscntrl: + case umap_xisdigit: + case umap_xisgraph: + case umap_xislower: + case umap_xisprint: + case umap_xispunct: + case umap_xisspace: + case umap_xisupper: + case umap_xisxdigit: + case umap_xtoascii: + // FIXME: intentionally skip this step for string mappers. + // Is this wanted? break; - case btyp_complex: - retval = retval.sparse_complex_matrix_value (); - break; - case btyp_bool: - retval = retval.sparse_bool_matrix_value (); - break; + default: - break; + { + switch (retval.builtin_type ()) + { + case btyp_double: + retval = retval.sparse_matrix_value (); + break; + + case btyp_complex: + retval = retval.sparse_complex_matrix_value (); + break; + + case btyp_bool: + retval = retval.sparse_bool_matrix_value (); + break; + + default: + break; + } + } } return retval; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base-sparse.h --- a/libinterp/octave-value/ov-base-sparse.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base-sparse.h Fri Mar 07 13:02:43 2014 -0500 @@ -147,7 +147,7 @@ bool print_as_scalar (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_info (std::ostream& os, const std::string& prefix) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base.cc --- a/libinterp/octave-value/ov-base.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base.cc Fri Mar 07 13:02:43 2014 -0500 @@ -52,6 +52,7 @@ #include "parse.h" #include "pr-output.h" #include "utils.h" +#include "toplev.h" #include "variables.h" builtin_type_t btyp_mixed_numeric (builtin_type_t x, builtin_type_t y) @@ -396,7 +397,7 @@ } void -octave_base_value::print (std::ostream&, bool) const +octave_base_value::print (std::ostream&, bool) { gripe_wrong_type_arg ("octave_base_value::print ()", type_name ()); } @@ -1536,6 +1537,111 @@ return new octave_cell (); } +static inline octave_value_list +sanitize (const octave_value_list& ovl) +{ + octave_value_list retval = ovl; + + for (octave_idx_type i = 0; i < ovl.length (); i++) + { + if (retval(i).is_magic_colon ()) + retval(i) = ":"; + } + + return retval; +} + +octave_value +make_idx_args (const std::string& type, + const std::list& idx, + const std::string& who) +{ + octave_value retval; + + size_t len = type.length (); + + if (len == idx.size ()) + { + Cell type_field (1, len); + Cell subs_field (1, len); + + std::list::const_iterator p = idx.begin (); + + for (size_t i = 0; i < len; i++) + { + char t = type[i]; + + switch (t) + { + case '(': + type_field(i) = "()"; + subs_field(i) = Cell (sanitize (*p++)); + break; + + case '{': + type_field(i) = "{}"; + subs_field(i) = Cell (sanitize (*p++)); + break; + + case '.': + { + type_field(i) = "."; + + octave_value_list vlist = *p++; + + if (vlist.length () == 1) + { + octave_value val = vlist(0); + + if (val.is_string ()) + subs_field(i) = val; + else + { + error ("expecting character string argument for '.' index"); + return retval; + } + } + else + { + error ("expecting single argument for '.' index"); + return retval; + } + } + break; + + default: + panic_impossible (); + break; + } + } + + octave_map m; + + m.assign ("type", type_field); + m.assign ("subs", subs_field); + + retval = m; + } + else + error ("invalid index for %s", who.c_str ()); + + return retval; +} + +bool +called_from_builtin (void) +{ + octave_function *fcn = octave_call_stack::caller (); + + // FIXME: we probably need a better check here, or some other + // mechanism to avoid overloaded functions when builtin is used. + // For example, what if someone overloads the builtin function? + // Also, are there other places where using builtin is not properly + // avoiding dispatch? + + return (fcn && fcn->name () == "builtin"); +} + void install_base_type_conversions (void) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-base.h --- a/libinterp/octave-value/ov-base.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-base.h Fri Mar 07 13:02:43 2014 -0500 @@ -606,7 +606,7 @@ virtual bool print_as_scalar (void) const { return false; } - virtual void print (std::ostream& os, bool pr_as_read_syntax = false) const; + virtual void print (std::ostream& os, bool pr_as_read_syntax = false); virtual void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; @@ -828,4 +828,16 @@ // is memory to be saved extern OCTINTERP_API bool Vsparse_auto_mutate; +// Utility function to convert C++ arguments used in subsref/subsasgn into an +// octave_value_list object that can be used to call a function/method in the +// interpreter. +extern OCTINTERP_API octave_value +make_idx_args (const std::string& type, + const std::list& idx, + const std::string& who); + +// Tells whether some regular octave_value_base methods are being called from +// within the "builtin" function. +extern OCTINTERP_API bool called_from_builtin (void); + #endif diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-bool-mat.cc --- a/libinterp/octave-value/ov-bool-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-bool-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -421,7 +421,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; boolNDArray m = bool_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-bool-sparse.cc --- a/libinterp/octave-value/ov-bool-sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-bool-sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -358,7 +358,8 @@ if (group_hid < 0) return false; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; SparseBoolMatrix m = sparse_bool_matrix_value (); octave_idx_type tmp; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-bool.cc --- a/libinterp/octave-value/ov-bool.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-bool.cc Fri Mar 07 13:02:43 2014 -0500 @@ -165,7 +165,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-cell.cc --- a/libinterp/octave-value/ov-cell.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-cell.cc Fri Mar 07 13:02:43 2014 -0500 @@ -687,7 +687,7 @@ } void -octave_cell::print (std::ostream& os, bool) const +octave_cell::print (std::ostream& os, bool) { print_raw (os); } @@ -1077,7 +1077,8 @@ return (empty > 0); hsize_t rank = dv.length (); - hid_t space_hid = -1, data_hid = -1, size_hid = -1; + hid_t space_hid, data_hid, size_hid; + space_hid = data_hid = size_hid = -1; #if HAVE_HDF5_18 data_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-cell.h --- a/libinterp/octave-value/ov-cell.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-cell.h Fri Mar 07 13:02:43 2014 -0500 @@ -147,7 +147,7 @@ bool print_as_scalar (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-class.cc --- a/libinterp/octave-value/ov-class.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-class.cc Fri Mar 07 13:02:43 2014 -0500 @@ -268,97 +268,6 @@ error ("assignment to class element failed"); } -static inline octave_value_list -sanitize (const octave_value_list& ovl) -{ - octave_value_list retval = ovl; - - for (octave_idx_type i = 0; i < ovl.length (); i++) - { - if (retval(i).is_magic_colon ()) - retval(i) = ":"; - } - - return retval; -} - -static inline octave_value -make_idx_args (const std::string& type, - const std::list& idx, - const std::string& who) -{ - octave_value retval; - - size_t len = type.length (); - - if (len == idx.size ()) - { - Cell type_field (1, len); - Cell subs_field (1, len); - - std::list::const_iterator p = idx.begin (); - - for (size_t i = 0; i < len; i++) - { - char t = type[i]; - - switch (t) - { - case '(': - type_field(i) = "()"; - subs_field(i) = Cell (sanitize (*p++)); - break; - - case '{': - type_field(i) = "{}"; - subs_field(i) = Cell (sanitize (*p++)); - break; - - case '.': - { - type_field(i) = "."; - - octave_value_list vlist = *p++; - - if (vlist.length () == 1) - { - octave_value val = vlist(0); - - if (val.is_string ()) - subs_field(i) = val; - else - { - error ("expecting character string argument for '.' index"); - return retval; - } - } - else - { - error ("expecting single argument for '.' index"); - return retval; - } - } - break; - - default: - panic_impossible (); - break; - } - } - - octave_map m; - - m.assign ("type", type_field); - m.assign ("subs", subs_field); - - retval = m; - } - else - error ("invalid index for %s", who.c_str ()); - - return retval; -} - Cell octave_class::dotref (const octave_value_list& idx) { @@ -398,20 +307,6 @@ return retval; } -static bool -called_from_builtin (void) -{ - octave_function *fcn = octave_call_stack::caller (); - - // FIXME: we probably need a better check here, or some other - // mechanism to avoid overloaded functions when builtin is used. - // For example, what if someone overloads the builtin function? - // Also, are there other places where using builtin is not properly - // avoiding dispatch? - - return (fcn && fcn->name () == "builtin"); -} - Matrix octave_class::size (void) { @@ -1150,7 +1045,7 @@ void -octave_class::print (std::ostream& os, bool) const +octave_class::print (std::ostream& os, bool) { print_raw (os); } @@ -1279,7 +1174,8 @@ bool octave_class::reconstruct_parents (void) { - bool retval = true, might_have_inheritance = false; + bool retval = true; + bool might_have_inheritance = false; std::string dbgstr = "dork"; // First, check to see if there might be an issue with inheritance. diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-class.h --- a/libinterp/octave-value/ov-class.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-class.h Fri Mar 07 13:02:43 2014 -0500 @@ -169,7 +169,7 @@ string_vector all_strings (bool pad) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-classdef.cc Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,3910 @@ +/* + +Copyright (C) 2012-2013 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "defun.h" +#include "load-path.h" +#include "ov-builtin.h" +#include "ov-classdef.h" +#include "ov-fcn-handle.h" +#include "ov-typeinfo.h" +#include "ov-usr-fcn.h" +#include "pt-assign.h" +#include "pt-classdef.h" +#include "pt-funcall.h" +#include "pt-misc.h" +#include "pt-stmt.h" +#include "pt-walk.h" +#include "singleton-cleanup.h" +#include "symtab.h" +#include "toplev.h" + +#include "Array.cc" + +static void +gripe_method_access (const std::string& from, const cdef_method& meth) +{ + octave_value acc = meth.get ("Access"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + + error ("%s: method `%s' has %s access and cannot be run in this context", + from.c_str (), meth.get_name ().c_str (), acc_s.c_str ()); +} + +static void +gripe_property_access (const std::string& from, const cdef_property& prop, + bool is_set = false) +{ + octave_value acc = prop.get (is_set ? "SetAccess" : "GetAccess"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + + if (is_set) + error ("%s: property `%s' has %s access and cannot be set in this context", + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); + else + error ("%s: property `%s' has %s access and cannot be obtained in this context", + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); +} + +static std::string +get_base_name (const std::string& nm) +{ + std::string::size_type pos = nm.find_last_of ('.'); + + if (pos != std::string::npos) + return nm.substr (pos + 1); + + return nm; +} + +static void +make_function_of_class (const std::string& class_name, + const octave_value& fcn) +{ + octave_function *of = fcn.function_value (); + + if (! error_state) + { + of->stash_dispatch_class (class_name); + + octave_user_function *uf = of->user_function_value (true); + + if (! error_state && uf) + { + if (get_base_name (class_name) == uf->name ()) + { + uf->mark_as_class_constructor (); + uf->mark_as_classdef_constructor (); + } + else + uf->mark_as_class_method (); + } + } +} + +static void +make_function_of_class (const cdef_class& cls, const octave_value& fcn) +{ + make_function_of_class (cls.get_name (), fcn); +} + +static octave_value +make_fcn_handle (octave_builtin::fcn ff, const std::string& nm) +{ + octave_value fcn (new octave_builtin (ff, nm)); + + octave_value fcn_handle (new octave_fcn_handle (fcn, nm)); + + return fcn_handle; +} + +static octave_value +make_fcn_handle (const octave_value& fcn, const std::string& nm) +{ + octave_value retval; + + if (fcn.is_defined ()) + retval = octave_value (new octave_fcn_handle (fcn, nm)); + + return retval; +} + +inline octave_value_list +execute_ov (octave_value val, const octave_value_list& args, int nargout) +{ + std::list idx (1, args); + + std::string type ("("); + + return val.subsref (type, idx, nargout); +} + +static cdef_class +lookup_class (const std::string& name, bool error_if_not_found = true, + bool load_if_not_found = true) +{ + return cdef_manager::find_class (name, error_if_not_found, + load_if_not_found); +} + +static cdef_class +lookup_class (const cdef_class& cls) +{ + // FIXME: placeholder for the time being, the purpose + // is to centralized any class update activity here. + + return cls; +} + +static cdef_class +lookup_class (const octave_value& ov) +{ + if (ov.is_string()) + return lookup_class (ov.string_value ()); + else + { + cdef_class cls (to_cdef (ov)); + + if (! error_state) + return lookup_class (cls); + } + + return cdef_class (); +} + +static std::list +lookup_classes (const Cell& cls_list) +{ + std::list retval; + + for (int i = 0; i < cls_list.numel (); i++) + { + cdef_class c = lookup_class (cls_list(i)); + + if (! error_state) + retval.push_back (c); + else + { + retval.clear (); + break; + } + } + + return retval; +} + +static octave_value +to_ov (const std::list& class_list) +{ + Cell cls (class_list.size (), 1); + int i = 0; + + for (std::list::const_iterator it = class_list.begin (); + it != class_list.end (); ++it, ++i) + cls(i) = to_ov (*it); + + return octave_value (cls); +} + +static bool +is_superclass (const cdef_class& clsa, const cdef_class& clsb, + bool allow_equal = true, int max_depth = -1) +{ + bool retval = false; + + if (allow_equal && clsa == clsb) + retval = true; + else if (max_depth != 0) + { + Cell c = clsb.get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && ! retval && i < c.numel (); i++) + { + cdef_class cls = lookup_class (c(i)); + + if (! error_state) + retval = is_superclass (clsa, cls, true, + max_depth < 0 ? max_depth : max_depth-1); + } + } + + return retval; +} + +inline bool +is_strict_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false); } + +inline bool +is_direct_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false, 1); } + +static octave_value_list +class_get_properties (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + retval(0) = cls.get_properties (); + } + + return retval; +} + +static cdef_class +get_class_context (std::string& name, bool& in_constructor) +{ + cdef_class cls; + + octave_function* fcn = octave_call_stack::current (); + + in_constructor = false; + + if (fcn && + (fcn->is_class_method () + || fcn->is_classdef_constructor () + || fcn->is_anonymous_function_of_class () + || (fcn->is_private_function () + && ! fcn->dispatch_class ().empty ()))) + { + cls = lookup_class (fcn->dispatch_class ()); + if (! error_state) + { + name = fcn->name (); + in_constructor = fcn->is_classdef_constructor (); + } + } + + return cls; +} + +inline cdef_class +get_class_context (void) +{ + std::string dummy_string; + bool dummy_bool; + + return get_class_context (dummy_string, dummy_bool); +} + +static bool +in_class_method (const cdef_class& cls) +{ + cdef_class ctx = get_class_context (); + + return (ctx.ok () && is_superclass (ctx, cls)); +} + +static bool +check_access (const cdef_class& cls, const octave_value& acc, + const std::string& meth_name = std::string (), + const std::string& prop_name = std::string (), + bool is_prop_set = false) +{ + if (acc.is_string ()) + { + std::string acc_s = acc.string_value (); + + if (acc_s == "public") + return true; + + cdef_class ctx = get_class_context (); + + // The access is private or protected, this requires a + // valid class context. + + if (! error_state && ctx.ok ()) + { + if (acc_s == "private") + return (ctx == cls); + else if (acc_s == "protected") + { + if (is_superclass (cls, ctx)) + // Calling a protected method in a superclass. + return true; + else if (is_strict_superclass (ctx, cls)) + { + // Calling a protected method or property in a derived class. + // This is only allowed if the context class knows about it + // and has access to it. + + if (! meth_name.empty ()) + { + cdef_method m = ctx.find_method (meth_name); + + if (m.ok ()) + return check_access (ctx, m.get ("Access"), meth_name); + + return false; + } + else if (! prop_name.empty ()) + { + cdef_property p = ctx.find_property (prop_name); + + if (p.ok ()) + { + octave_value p_access = p.get (is_prop_set ? + "SetAccess" : + "GetAccess"); + + return check_access (ctx, p_access, meth_name, + prop_name, is_prop_set); + } + + return false; + } + else + panic_impossible (); + } + + return false; + } + else + panic_impossible (); + } + } + else if (acc.is_cell ()) + { + Cell acc_c = acc.cell_value (); + + cdef_class ctx = get_class_context (); + + // At this point, a class context is always required. + + if (! error_state && ctx.ok ()) + { + if (ctx == cls) + return true; + + for (int i = 0; ! error_state && i < acc.numel (); i++) + { + cdef_class acc_cls (to_cdef (acc_c(i))); + + if (! error_state) + { + if (is_superclass (acc_cls, ctx)) + return true; + } + } + } + } + else + error ("invalid property/method access in class `%s'", + cls.get_name ().c_str ()); + + return false; +} + +static bool +is_dummy_method (const octave_value& fcn) +{ + bool retval = false; + + if (fcn.is_defined ()) + { + if (fcn.is_user_function ()) + { + octave_user_function *uf = fcn.user_function_value (true); + + if (! uf || ! uf->body ()) + retval = true; + } + } + else + retval = true; + + return retval; +} + +bool +is_method_executing (const octave_value& ov, const cdef_object& obj) +{ + octave_function* stack_fcn = octave_call_stack::current (); + + octave_function* method_fcn = ov.function_value (true); + + // Does the top of the call stack match our target function? + + if (stack_fcn && stack_fcn == method_fcn) + { + octave_user_function* uf = method_fcn->user_function_value (true); + + // We can only check the context object for user-function (not builtin), + // where we have access to the parameters (arguments and return values). + // That's ok as there's no need to call this function for builtin + // methods. + + if (uf) + { + // At this point, the method is executing, but we still need to + // check the context object for which the method is executing. For + // methods, it's the first argument of the function; for ctors, it + // is the first return value. + + tree_parameter_list* pl = uf->is_classdef_constructor () + ? uf->return_list () : uf->parameter_list (); + + if (pl && pl->size () > 0) + { + octave_value arg0 = pl->front ()->lvalue ().value (); + + if (arg0.is_defined () && arg0.type_name () == "object") + { + cdef_object arg0_obj = to_cdef (arg0); + + return obj.is (arg0_obj); + } + } + } + } + + return false; +} + +static octave_value_list +class_get_methods (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + retval(0) = cls.get_methods (); + } + + return retval; +} + +static octave_value_list +class_get_superclasses (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls (to_cdef (args(0))); + + Cell classes = cls.get ("SuperClasses").cell_value (); + + retval(0) = to_ov (lookup_classes (classes)); + } + + return retval; +} + +static octave_value_list +class_get_inferiorclasses (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls (to_cdef (args(0))); + + Cell classes = cls.get ("InferiorClasses").cell_value (); + + retval(0) = to_ov (lookup_classes (classes)); + } + + return retval; +} + +static octave_value_list +class_fromName (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval(0) = to_ov (lookup_class (name)); + else + error ("fromName: invalid class name, expected a string value"); + } + else + error ("fromName: invalid number of parameters"); + + return retval; +} + +static octave_value_list +class_fevalStatic (const octave_value_list& args, int nargout) +{ + octave_value_list retval; + + if (args.length () > 1 && args(0).type_name () == "object") + { + cdef_class cls (to_cdef (args(0))); + + if (! error_state) + { + std::string meth_name = args(1).string_value (); + + if (! error_state) + { + cdef_method meth = cls.find_method (meth_name); + + if (meth.ok ()) + { + if (meth.is_static ()) + retval = meth.execute (args.splice (0, 2), nargout, + true, "fevalStatic"); + else + error ("fevalStatic: method `%s' is not static", + meth_name.c_str ()); + } + else + error ("fevalStatic: method not found: %s", + meth_name.c_str ()); + } + else + error ("fevalStatic: invalid method name, expected a string value"); + } + error ("fevalStatic: invalid object, expected a meta.class object"); + } + else + error ("fevalStatic: invalid arguments"); + + return retval; +} + +static octave_value_list +class_getConstant (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 2 && args(0).type_name () == "object" + && args(0).class_name () == "meta.class") + { + cdef_class cls = to_cdef (args(0)); + + if (! error_state) + { + std::string prop_name = args(1).string_value (); + + if (! error_state) + { + cdef_property prop = cls.find_property (prop_name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "getConstant"); + else + error ("getConstant: property `%s' is not constant", + prop_name.c_str ()); + } + else + error ("getConstant: property not found: %s", + prop_name.c_str ()); + } + else + error ("getConstant: invalid property name, expected a string value"); + } + else + error ("getConstant: invalid object, expected a meta.class object"); + } + else + error ("getConstant: invalid arguments"); + + return retval; +} + +#define META_CLASS_CMP(OP, CLSA, CLSB, FUN) \ +static octave_value_list \ +class_ ## OP (const octave_value_list& args, int /* nargout */) \ +{ \ + octave_value_list retval; \ +\ + if (args.length () == 2 \ + && args(0).type_name () == "object" && args(1).type_name () == "object" \ + && args(0).class_name () == "meta.class" && args(1).class_name () == "meta.class") \ + { \ + cdef_class clsa = to_cdef (args(0)); \ +\ + cdef_class clsb = to_cdef (args(1)); \ +\ + if (! error_state) \ + retval(0) = FUN (CLSA, CLSB); \ + else \ + error (#OP ": invalid objects, expected meta.class objects"); \ + } \ + else \ + error (#OP ": invalid arguments"); \ +\ + return retval; \ +} + +META_CLASS_CMP (lt, clsb, clsa, is_strict_superclass) +META_CLASS_CMP (le, clsb, clsa, is_superclass) +META_CLASS_CMP (gt, clsa, clsb, is_strict_superclass) +META_CLASS_CMP (ge, clsa, clsb, is_superclass) +META_CLASS_CMP (eq, clsa, clsb, operator==) +META_CLASS_CMP (ne, clsa, clsb, operator!=) + +octave_value_list +property_get_defaultvalue (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_property prop (to_cdef (args(0))); + + retval(0) = prop.get ("DefaultValue"); + + if (! retval(0).is_defined ()) + error_with_id ("Octave:class:NotDefaultDefined", + "no default value for property `%s'", + prop.get_name ().c_str ()); + } + + return retval; +} + +static octave_value_list +handle_delete (const octave_value_list& /* args */, int /* nargout */) +{ + octave_value_list retval; + + // FIXME: implement this + + return retval; +} + +static cdef_class +make_class (const std::string& name, + const std::list& super_list = std::list ()) +{ + cdef_class cls (name, super_list); + + cls.set_class (cdef_class::meta_class ()); + cls.put ("Abstract", false); + cls.put ("ConstructOnLoad", false); + cls.put ("ContainingPackage", Matrix ()); + cls.put ("Description", std::string ()); + cls.put ("DetailedDescription", std::string ()); + cls.put ("Events", Cell ()); + cls.put ("Hidden", false); + cls.put ("InferiorClasses", Cell ()); + cls.put ("Methods", Cell ()); + cls.put ("Properties", Cell ()); + cls.put ("Sealed", false); + + if (name == "handle") + { + cls.put ("HandleCompatible", true); + cls.mark_as_handle_class (); + } + else if (super_list.empty ()) + { + cls.put ("HandleCompatible", false); + } + else + { + bool all_handle_compatible = true; + bool has_handle_class = false; + + for (std::list::const_iterator it = super_list.begin (); + it != super_list.end (); ++it) + { + all_handle_compatible = all_handle_compatible && it->get ("HandleCompatible").bool_value (); + has_handle_class = has_handle_class || it->is_handle_class (); + } + + if (has_handle_class && ! all_handle_compatible) + ::error ("%s: cannot mix handle and non-HandleCompatible classes", + name.c_str ()); + else + { + cls.put ("HandleCompatible", all_handle_compatible); + if (has_handle_class) + cls.mark_as_handle_class (); + } + } + + if (error_state) + return cdef_class (); + + if (! name.empty ()) + cdef_manager::register_class (cls); + + return cls; +} + +static cdef_class +make_class (const std::string& name, const cdef_class& super) +{ + return make_class (name, std::list (1, super)); +} + +static cdef_class +make_meta_class (const std::string& name, const cdef_class& super) +{ + cdef_class cls = make_class (name, super); + + cls.put ("Sealed", true); + cls.mark_as_meta_class (); + + return cls; +} + +static cdef_property +make_property (const cdef_class& cls, const std::string& name, + const octave_value& get_method = Matrix (), + const std::string& get_access = "public", + const octave_value& set_method = Matrix (), + const std::string& set_access = "public") +{ + cdef_property prop (name); + + prop.set_class (cdef_class::meta_property ()); + prop.put ("Description", std::string ()); + prop.put ("DetailedDescription", std::string ()); + prop.put ("Abstract", false); + prop.put ("Constant", false); + prop.put ("GetAccess", get_access); + prop.put ("SetAccess", set_access); + prop.put ("Dependent", false); + prop.put ("Transient", false); + prop.put ("Hidden", false); + prop.put ("GetObservable", false); + prop.put ("SetObservable", false); + prop.put ("GetMethod", get_method); + prop.put ("SetMethod", set_method); + prop.put ("DefiningClass", to_ov (cls)); + prop.put ("DefaultValue", octave_value ()); + prop.put ("HasDefault", false); + + std::string class_name = cls.get_name (); + + if (! get_method.is_empty ()) + make_function_of_class (class_name, get_method); + if (! set_method.is_empty ()) + make_function_of_class (class_name, set_method); + + return prop; +} + +inline cdef_property +make_attribute (const cdef_class& cls, const std::string& name) +{ + return make_property (cls, name, Matrix (), "public", Matrix (), "private"); +} + +static cdef_method +make_method (const cdef_class& cls, const std::string& name, + const octave_value& fcn,const std::string& m_access = "public", + bool is_static = false) +{ + cdef_method meth (name); + + meth.set_class (cdef_class::meta_method ()); + meth.put ("Abstract", false); + meth.put ("Access", m_access); + meth.put ("DefiningClass", to_ov (cls)); + meth.put ("Description", std::string ()); + meth.put ("DetailedDescription", std::string ()); + meth.put ("Hidden", false); + meth.put ("Sealed", true); + meth.put ("Static", is_static); + + if (fcn.is_defined ()) + make_function_of_class (cls, fcn); + + meth.set_function (fcn); + + if (is_dummy_method (fcn)) + meth.mark_as_external (cls.get_name ()); + + return meth; +} + +inline cdef_method +make_method (const cdef_class& cls, const std::string& name, + octave_builtin::fcn ff, const std::string& m_access = "public", + bool is_static = false) +{ + octave_value fcn (new octave_builtin (ff, name)); + + return make_method (cls, name, fcn, m_access, is_static); +} + +static cdef_package +make_package (const std::string& nm, + const std::string& parent = std::string ()) +{ + cdef_package pack (nm); + + pack.set_class (cdef_class::meta_package ()); + if (parent.empty ()) + pack.put ("ContainingPackage", Matrix ()); + else + pack.put ("ContainingPackage", to_ov (cdef_manager::find_package (parent))); + + if (! nm.empty ()) + cdef_manager::register_package (pack); + + return pack; +} + +//---------------------------------------------------------------------------- + +DEFINE_OCTAVE_ALLOCATOR (octave_classdef); + +int octave_classdef::t_id (-1); + +const std::string octave_classdef::t_name ("object"); + +void +octave_classdef::register_type (void) +{ + t_id = octave_value_typeinfo::register_type + (octave_classdef::t_name, "", octave_value (new octave_classdef ())); +} + +octave_value_list +octave_classdef::subsref (const std::string& type, + const std::list& idx, + int nargout) +{ + size_t skip = 0; + octave_value_list retval; + + cdef_class cls = object.get_class (); + + if (! in_class_method (cls) && ! called_from_builtin ()) + { + cdef_method meth = cls.find_method ("subsref"); + + if (meth.ok ()) + { + octave_value_list args; + + args(1) = make_idx_args (type, idx, "subsref"); + + if (! error_state) + { + count++; + args(0) = octave_value (this); + + retval = meth.execute (args, nargout, true, "subsref"); + } + + return retval; + } + } + + // At this point, the default subsref mechanism must be used. + + retval = object.subsref (type, idx, nargout, skip, cdef_class ()); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +octave_value +octave_classdef::subsref (const std::string& type, + const std::list& idx, + bool auto_add) +{ + size_t skip = 0; + octave_value_list retval; + + // This variant of subsref is used to create temporary values when doing + // assignment with multi-level indexing. AFAIK this is only used for internal + // purpose (not sure we should even implement this) and any overload subsref + // should not be called. + + retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (1, type, idx, skip); + } + + return retval.length () > 0 ? retval(0) : octave_value (); +} + +octave_value +octave_classdef::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + cdef_class cls = object.get_class (); + + if (! in_class_method (cls) && ! called_from_builtin ()) + { + cdef_method meth = cls.find_method ("subsasgn"); + + if (meth.ok ()) + { + octave_value_list args; + + args(1) = make_idx_args (type, idx, "subsasgn"); + + if (! error_state) + { + count++; + args(0) = octave_value (this); + args(2) = rhs; + + octave_value_list retlist; + + retlist = meth.execute (args, 1, true, "subsasgn"); + + if (! error_state) + { + if (retlist.length () > 0) + retval = retlist(0); + else + ::error ("overloaded method `subsasgn' did not return any value"); + } + } + } + } + + if (! error_state && ! retval.is_defined ()) + retval = object.subsasgn (type, idx, rhs); + + return retval; +} + +octave_value +octave_classdef::undef_subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + if (type.length () == 1 && type[0] == '(') + { + object = object.make_array (); + + if (! error_state) + return subsasgn (type, idx, rhs); + } + else + return octave_base_value::undef_subsasgn (type, idx, rhs); + + return octave_value (); +} + +void +octave_classdef::print (std::ostream& os, bool) +{ + if (! called_from_builtin ()) + { + cdef_method meth = object.get_class ().find_method ("disp"); + + if (meth.ok ()) + { + octave_value_list args; + + count++; + args(0) = octave_value (this); + + indent (os); + meth.execute (args, 0, true, "disp"); + + return; + } + } + + print_raw (os); +} + +void +octave_classdef::print_raw (std::ostream& os, bool) const +{ + indent (os); + os << ""; + newline (os); +} + +bool +octave_classdef::print_name_tag (std::ostream& os, + const std::string& name) const +{ + return octave_base_value::print_name_tag (os, name); +} + +void +octave_classdef::print_with_name (std::ostream& os, const std::string& name, + bool print_padding) +{ + cdef_method meth = object.get_class ().find_method ("display"); + + if (meth.ok ()) + { + octave_value_list args; + + count++; + args(0) = octave_value (this); + + string_vector arg_names (1); + + arg_names[0] = name; + args.stash_name_tags (arg_names); + + indent (os); + meth.execute (args, 0, true, "display"); + } + else + octave_base_value::print_with_name (os, name, print_padding); +} + +//---------------------------------------------------------------------------- + +class octave_classdef_meta : public octave_function +{ +public: + octave_classdef_meta (const cdef_meta_object& obj) + : object (obj) { } + + ~octave_classdef_meta (void) + { object.meta_release (); } + + octave_function* function_value (bool = false) { return this; } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, + int nargout) + { return object.meta_subsref (type, idx, nargout); } + + octave_value + subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval; + + retval = subsref (type, idx, 1); + + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& idx) + { + // Emulate ()-type meta subsref + + std::list l (1, idx); + std::string type ("("); + + return subsref (type, l, nargout); + } + + bool is_postfix_index_handled (char type) const + { return object.meta_is_postfix_index_handled (type); } + + bool + is_classdef_constructor (const std::string& cname = std::string ()) const + { + bool retval = false; + + if (object.is_class ()) + { + if (cname.empty ()) + retval = true; + else + { + cdef_class cls (object); + + if (cls.get_name () == cname) + retval = true; + } + } + + return retval; + } + +private: + cdef_meta_object object; +}; + +//---------------------------------------------------------------------------- + +class octave_classdef_superclass_ref : public octave_function +{ +public: + octave_classdef_superclass_ref (const octave_value_list& a) + : octave_function (), args (a) { } + + ~octave_classdef_superclass_ref (void) { } + + octave_function* function_value (bool = false) { return this; } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, + int nargout) + { + size_t skip = 0; + octave_value_list retval; + + switch (type[0]) + { + case '(': + skip = 1; + retval = do_multi_index_op (type.length () > 1 ? 1 : nargout, + idx.front ()); + break; + default: + retval = do_multi_index_op (1, octave_value_list ()); + break; + } + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip + && retval.length () > 0) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; + } + + octave_value + subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval; + + retval = subsref (type, idx, 1); + + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& idx) + { + octave_value_list retval; + + std::string meth_name; + bool in_constructor; + cdef_class ctx; + + ctx = get_class_context (meth_name, in_constructor); + + if (! error_state && ctx.ok ()) + { + std::string mname = args(0).string_value (); + std::string cname = args(1).string_value (); + + cdef_class cls = lookup_class (cname); + + if (! error_state) + { + if (in_constructor) + { + if (is_direct_superclass (cls, ctx)) + { + if (is_constructed_object (mname)) + { + octave_value sym = symbol_table::varval (mname); + + cls.run_constructor (to_cdef_ref (sym), idx); + + retval(0) = sym; + } + else + ::error ("cannot call superclass constructor with " + "variable `%s'", mname.c_str ()); + } + else + ::error ("`%s' is not a direct superclass of `%s'", + cname.c_str (), ctx.get_name ().c_str ()); + } + else + { + if (mname == meth_name) + { + if (is_strict_superclass (cls, ctx)) + { + // I see 2 possible implementations here: + // 1) use cdef_object::subsref with a different class + // context; this avoids duplicating code, but + // assumes the object is always the first argument + // 2) lookup the method manually and call + // cdef_method::execute; this duplicates part of + // logic in cdef_object::subsref, but avoid the + // assumption of 1) + // Not being sure about the assumption of 1), I + // go with option 2) for the time being. + + cdef_method meth = cls.find_method (meth_name, false); + + if (meth.ok ()) + retval = meth.execute (idx, nargout, true, + meth_name); + else + ::error ("no method `%s' found in superclass `%s'", + meth_name.c_str (), cname.c_str ()); + } + else + ::error ("`%s' is not a superclass of `%s'", + cname.c_str (), ctx.get_name ().c_str ()); + } + else + ::error ("method name mismatch (`%s' != `%s')", + mname.c_str (), meth_name.c_str ()); + } + } + } + else if (! error_state) + ::error ("superclass calls can only occur in methods or constructors"); + + return retval; + } + +private: + bool is_constructed_object (const std::string nm) + { + octave_function *of = octave_call_stack::current (); + + if (of->is_classdef_constructor ()) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + + if (ret_list && ret_list->length () == 1) + return (ret_list->front ()->name () == nm); + } + } + + return false; + } + +private: + octave_value_list args; +}; + +//---------------------------------------------------------------------------- + +string_vector +cdef_object_rep::map_keys (void) const +{ + cdef_class cls = get_class (); + + if (cls.ok ()) + return cls.get_names (); + + return string_vector (); +} + +octave_value_list +cdef_object_scalar::subsref (const std::string& type, + const std::list& idx, + int nargout, size_t& skip, + const cdef_class& context, bool auto_add) +{ + skip = 0; + + cdef_class cls = (context.ok () ? context : get_class ()); + + octave_value_list retval; + + if (! cls.ok ()) + return retval; + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + cdef_method meth = cls.find_method (name); + + if (meth.ok ()) + { + int _nargout = (type.length () > 2 ? 1 : nargout); + + octave_value_list args; + + skip = 1; + + if (type.length () > 1 && type[1] == '(') + { + std::list::const_iterator it = idx.begin (); + + args = *++it; + + skip++; + } + + if (meth.is_static ()) + retval = meth.execute (args, _nargout, true, "subsref"); + else + { + refcount++; + retval = meth.execute (cdef_object (this), args, _nargout, + true, "subsref"); + } + } + + if (skip == 0 && ! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "subsref"); + else + { + refcount++; + retval(0) = prop.get_value (cdef_object (this), + true, "subsref"); + } + + skip = 1; + } + else + error ("subsref: unknown method or property: %s", name.c_str ()); + } + break; + } + + case '(': + { + refcount++; + + cdef_object this_obj (this); + + Array arr (dim_vector (1, 1), this_obj); + + cdef_object new_obj = cdef_object (new cdef_object_array (arr)); + + new_obj.set_class (get_class ()); + + retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add); + } + break; + + default: + error ("object cannot be indexed with `%c'", type[0]); + break; + } + + return retval; +} + +octave_value +cdef_object_scalar::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + cdef_class cls = get_class (); + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + if (! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (prop.is_constant ()) + error ("subsasgn: cannot assign constant property: %s", + name.c_str ()); + else + { + refcount++; + + cdef_object obj (this); + + if (type.length () == 1) + { + prop.set_value (obj, rhs, true, "subsasgn"); + + if (! error_state) + retval = to_ov (obj); + } + else + { + octave_value val = + prop.get_value (obj, true, "subsasgn"); + + if (! error_state) + { + std::list args (idx); + + args.erase (args.begin ()); + + val = val.assign (octave_value::op_asn_eq, + type.substr (1), args, rhs); + + if (! error_state) + { + if (val.class_name () != "object" + || ! to_cdef (val).is_handle_object ()) + prop.set_value (obj, val, true, "subsasgn"); + + if (! error_state) + retval = to_ov (obj); + } + } + } + } + } + else + error ("subsasgn: unknown property: %s", name.c_str ()); + } + } + break; + + case '(': + { + refcount++; + + cdef_object this_obj (this); + + Array arr (dim_vector (1, 1), this_obj); + + cdef_object new_obj = cdef_object (new cdef_object_array (arr)); + + new_obj.set_class (get_class ()); + + octave_value tmp = new_obj.subsasgn (type, idx, rhs); + + if (! error_state) + retval = tmp; + } + break; + + default: + error ("subsasgn: object cannot be index with `%c'", type[0]); + break; + } + + return retval; +} + +void +cdef_object_scalar::mark_for_construction (const cdef_class& cls) +{ + std::string cls_name = cls.get_name (); + + Cell supcls = cls.get ("SuperClasses").cell_value (); + + if (! error_state) + { + std::list supcls_list = lookup_classes (supcls); + + if (! error_state) + ctor_list[cls] = supcls_list; + } +} + +octave_value_list +cdef_object_array::subsref (const std::string& type, + const std::list& idx, + int /* nargout */, size_t& skip, + const cdef_class& /* context */, bool auto_add) +{ + octave_value_list retval; + + skip = 1; + + switch (type[0]) + { + case '(': + { + const octave_value_list& ival = idx.front (); + bool is_scalar = true; + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + if (! error_state) + is_scalar = is_scalar && iv(i).is_scalar (); + } + + if (! error_state) + { + Array ires = array.index (iv, auto_add); + + if (! error_state) + { + // If resizing is enabled (auto_add = true), it's possible + // indexing was out-of-bound and the result array contains + // invalid cdef_objects. + + if (auto_add) + fill_empty_values (ires); + + if (is_scalar) + retval(0) = to_ov (ires(0)); + else + { + cdef_object array_obj (new cdef_object_array (ires)); + + array_obj.set_class (get_class ()); + + retval(0) = to_ov (array_obj); + } + } + } + } + break; + + case '.': + if (type.size () == 1 && idx.size () == 1) + { + Cell c (dims ()); + + octave_idx_type n = array.numel (); + + // dummy variables + size_t dummy_skip; + cdef_class dummy_cls; + + for (octave_idx_type i = 0; i < n; i++) + { + octave_value_list r = array(i).subsref (type, idx, 1, dummy_skip, + dummy_cls); + + if (! error_state) + { + if (r.length () > 0) + c(i) = r(0); + } + else + break; + } + + if (! error_state) + retval(0) = octave_value (c, true); + + break; + } + // fall through "default" + + default: + ::error ("can't perform indexing operation on array of %s objects", + class_name ().c_str ()); + break; + } + + return retval; +} + +octave_value +cdef_object_array::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + switch (type[0]) + { + case '(': + if (type.length () == 1) + { + cdef_object rhs_obj = to_cdef (rhs); + + if (! error_state) + { + if (rhs_obj.get_class () == get_class ()) + { + const octave_value_list& ival = idx.front (); + bool is_scalar = true; + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + if (! error_state) + is_scalar = is_scalar && iv(i).is_scalar (); + } + + if (! error_state) + { + Array rhs_mat; + + if (! rhs_obj.is_array ()) + { + rhs_mat = Array (dim_vector (1, 1)); + rhs_mat(0) = rhs_obj; + } + else + rhs_mat = rhs_obj.array_value (); + + if (! error_state) + { + octave_idx_type n = array.numel (); + + array.assign (iv, rhs_mat, cdef_object ()); + + if (! error_state) + { + if (array.numel () > n) + fill_empty_values (); + + if (! error_state) + { + refcount++; + retval = to_ov (cdef_object (this)); + } + } + } + } + } + else + ::error ("can't assign %s object into array of %s objects.", + rhs_obj.class_name ().c_str (), + class_name ().c_str ()); + } + } + else + { + const octave_value_list& ival = idx.front (); + + bool is_scalar = true; + + Array iv (dim_vector (1, ival.length ())); + + for (int i = 0; ! error_state && i < ival.length (); i++) + { + iv(i) = ival(i).index_vector (); + + if (! error_state) + { + is_scalar = is_scalar && iv(i).is_scalar (); + + if (! is_scalar) + error ("subsasgn: invalid indexing for object array " + "assignment, the index must reference a single " + "object in the array."); + } + } + + if (! error_state) + { + Array a = array.index (iv, true); + + if (a.numel () != 1) + error ("subsasgn: invalid indexing for object array " + "assignment"); + + if (! error_state) + { + cdef_object obj = a(0); + + int ignore_copies = 0; + + // If the object in 'a' is not valid, this means the index + // was out-of-bound and we need to create a new object. + + if (! obj.ok ()) + obj = get_class ().construct_object (octave_value_list ()); + else + // Optimize the subsasgn call to come. There are 2 copies + // that we can safely ignore: + // - 1 in "array" + // - 1 in "a" + ignore_copies = 2; + + std::list next_idx (idx); + + next_idx.erase (next_idx.begin ()); + + octave_value tmp = obj.subsasgn (type.substr (1), next_idx, + rhs, ignore_copies); + + if (! error_state) + { + cdef_object robj = to_cdef (tmp); + + if (robj.ok () + && ! robj.is_array () + && robj.get_class () == get_class ()) + { + // Small optimization, when dealing with handle + // objects, we don't need to re-assign the result + // of subsasgn back into the array. + + if (! robj.is (a(0))) + { + Array rhs_a (dim_vector (1, 1), + robj); + + octave_idx_type n = array.numel (); + + array.assign (iv, rhs_a); + + if (array.numel () > n) + fill_empty_values (); + } + + refcount++; + + retval = to_ov (cdef_object (this)); + } + else + error ("subasgn: invalid assignment into array of %s " + "objects", class_name ().c_str ()); + } + } + } + } + break; + + default: + ::error ("can't perform indexing operation on array of %s objects", + class_name ().c_str ()); + break; + } + + return retval; +} + +void +cdef_object_array::fill_empty_values (Array& arr) +{ + cdef_class cls = get_class (); + + if (! error_state) + { + cdef_object obj; + + int n = arr.numel (); + + for (int i = 0; ! error_state && i < n; i++) + { + if (! arr.xelem (i).ok ()) + { + if (! obj.ok ()) + { + obj = cls.construct_object (octave_value_list ()); + + if (! error_state) + arr.xelem (i) = obj; + } + else + arr.xelem (i) = obj.copy (); + } + } + } +} + +bool cdef_object_scalar::is_constructed_for (const cdef_class& cls) const +{ + return (is_constructed () + || ctor_list.find (cls) == ctor_list.end ()); +} + +bool cdef_object_scalar::is_partially_constructed_for (const cdef_class& cls) const +{ + std::map< cdef_class, std::list >::const_iterator it; + + if (is_constructed ()) + return true; + else if ((it = ctor_list.find (cls)) == ctor_list.end () + || it->second.empty ()) + return true; + + for (std::list::const_iterator lit = it->second.begin (); + lit != it->second.end (); ++lit) + if (! is_constructed_for (*lit)) + return false; + + return true; +} + +handle_cdef_object::~handle_cdef_object (void) +{ + gnulib::printf ("deleting %s object (handle)\n", + get_class ().get_name ().c_str ()); +} + +value_cdef_object::~value_cdef_object (void) +{ + gnulib::printf ("deleting %s object (value)\n", + get_class ().get_name ().c_str ()); +} + +cdef_class::cdef_class_rep::cdef_class_rep (const std::list& superclasses) + : cdef_meta_object_rep (), member_count (0), handle_class (false), + object_count (0), meta (false) +{ + put ("SuperClasses", to_ov (superclasses)); + implicit_ctor_list = superclasses; +} + +cdef_method +cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local) +{ + method_iterator it = method_map.find (nm); + + if (it == method_map.end ()) + { + // FIXME: look into class directory + } + else + { + cdef_method& meth = it->second; + + // FIXME: check if method reload needed + + if (meth.ok ()) + return meth; + } + + if (! local) + { + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + { + cdef_method meth = cls.find_method (nm); + + if (meth.ok ()) + return meth; + } + } + } + + return cdef_method (); +} + +class ctor_analyzer : public tree_walker +{ +public: + ctor_analyzer (const std::string& ctor, const std::string& obj) + : tree_walker (), who (ctor), obj_name (obj) { } + + void visit_statement_list (tree_statement_list& t) + { + for (tree_statement_list::const_iterator it = t.begin (); + ! error_state && it != t.end (); ++it) + (*it)->accept (*this); + } + + void visit_statement (tree_statement& t) + { + if (t.is_expression ()) + t.expression ()->accept (*this); + } + + void visit_simple_assignment (tree_simple_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_multi_assignment (tree_multi_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_index_expression (tree_index_expression& t) + { + t.expression ()->accept (*this); + } + + void visit_funcall (tree_funcall& t) + { + octave_value fcn = t.function (); + + if (fcn.is_function ()) + { + octave_function *of = fcn.function_value (true); + + if (of) + { + if (of->name () == "__superclass_reference__") + { + octave_value_list args = t.arguments (); + + if (args(0).string_value () == obj_name) + { + std::string class_name = args(1).string_value (); + + cdef_class cls = lookup_class (class_name, false); + + if (cls.ok ()) + ctor_list.push_back (cls); + } + } + } + } + } + + std::list get_constructor_list (void) const + { return ctor_list; } + + // NO-OP + void visit_anon_fcn_handle (tree_anon_fcn_handle&) { } + void visit_argument_list (tree_argument_list&) { } + void visit_binary_expression (tree_binary_expression&) { } + void visit_break_command (tree_break_command&) { } + void visit_colon_expression (tree_colon_expression&) { } + void visit_continue_command (tree_continue_command&) { } + void visit_global_command (tree_global_command&) { } + void visit_persistent_command (tree_persistent_command&) { } + void visit_decl_elt (tree_decl_elt&) { } + void visit_decl_init_list (tree_decl_init_list&) { } + void visit_simple_for_command (tree_simple_for_command&) { } + void visit_complex_for_command (tree_complex_for_command&) { } + void visit_octave_user_script (octave_user_script&) { } + void visit_octave_user_function (octave_user_function&) { } + void visit_function_def (tree_function_def&) { } + void visit_identifier (tree_identifier&) { } + void visit_if_clause (tree_if_clause&) { } + void visit_if_command (tree_if_command&) { } + void visit_if_command_list (tree_if_command_list&) { } + void visit_switch_case (tree_switch_case&) { } + void visit_switch_case_list (tree_switch_case_list&) { } + void visit_switch_command (tree_switch_command&) { } + void visit_matrix (tree_matrix&) { } + void visit_cell (tree_cell&) { } + void visit_no_op_command (tree_no_op_command&) { } + void visit_constant (tree_constant&) { } + void visit_fcn_handle (tree_fcn_handle&) { } + void visit_parameter_list (tree_parameter_list&) { } + void visit_postfix_expression (tree_postfix_expression&) { } + void visit_prefix_expression (tree_prefix_expression&) { } + void visit_return_command (tree_return_command&) { } + void visit_return_list (tree_return_list&) { } + void visit_try_catch_command (tree_try_catch_command&) { } + void visit_unwind_protect_command (tree_unwind_protect_command&) { } + void visit_while_command (tree_while_command&) { } + void visit_do_until_command (tree_do_until_command&) { } + +private: + /* The name of the constructor being analyzed */ + std::string who; + + /* The name of the first output argument of the constructor */ + std::string obj_name; + + /* The list of superclass constructors that are explicitly called */ + std::list ctor_list; +}; + +void +cdef_class::cdef_class_rep::install_method (const cdef_method& meth) +{ + method_map[meth.get_name ()] = meth; + + member_count++; + + if (meth.is_constructor ()) + { + // Analyze the constructor code to determine what superclass + // constructors are called explicitly. + + octave_function *of = meth.get_function ().function_value (true); + + if (of) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + tree_statement_list *body = uf->body (); + + if (ret_list && ret_list->size () == 1) + { + std::string obj_name = ret_list->front ()->name (); + ctor_analyzer a (meth.get_name (), obj_name); + + body->accept (a); + if (! error_state) + { + std::list explicit_ctor_list + = a.get_constructor_list (); + + for (std::list::const_iterator it = explicit_ctor_list.begin (); + ! error_state && it != explicit_ctor_list.end (); ++it) + { + gnulib::printf ("explicit superclass constructor: %s\n", + it->get_name ().c_str ()); + implicit_ctor_list.remove (*it); + } + } + } + else + ::error ("%s: invalid constructor output arguments", + meth.get_name ().c_str ()); + } + } + } +} + +void +cdef_class::cdef_class_rep::load_all_methods (void) +{ + // FIXME: re-scan class directory +} + +Cell +cdef_class::cdef_class_rep::get_methods (void) +{ + std::map meths; + + find_methods (meths, false); + + if (! error_state) + { + Cell c (meths.size (), 1); + + int idx = 0; + + for (std::map::const_iterator it = meths.begin (); + it != meths.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_methods (std::map& meths, + bool only_inherited) +{ + load_all_methods (); + + method_const_iterator it; + + for (it = method_map.begin (); it != method_map.end (); ++it) + { + if (! it->second.is_constructor ()) + { + std::string nm = it->second.get_name (); + + if (meths.find (nm) == meths.end ()) + { + if (only_inherited) + { + octave_value acc = it->second.get ("Access"); + + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } + + meths[nm] = it->second; + } + } + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_methods (meths, true); + else + break; + } +} + +cdef_property +cdef_class::cdef_class_rep::find_property (const std::string& nm) +{ + property_iterator it = property_map.find (nm); + + if (it != property_map.end ()) + { + cdef_property& prop = it->second; + + if (prop.ok ()) + return prop; + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + { + cdef_property prop = cls.find_property (nm); + + if (prop.ok ()) + return prop; + } + } + + return cdef_property (); +} + +void +cdef_class::cdef_class_rep::install_property (const cdef_property& prop) +{ + property_map[prop.get_name ()] = prop; + + member_count++; +} + +Cell +cdef_class::cdef_class_rep::get_properties (void) +{ + std::map props; + + find_properties (props, false); + + if (! error_state) + { + Cell c (props.size (), 1); + + int idx = 0; + + for (std::map::const_iterator it = props.begin (); + it != props.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_properties (std::map& props, + bool only_inherited) +{ + property_const_iterator it; + + for (it = property_map.begin (); ! error_state && it != property_map.end (); + ++it) + { + std::string nm = it->second.get_name (); + + if (props.find (nm) == props.end ()) + { + if (only_inherited) + { + octave_value acc = it->second.get ("GetAccess"); + + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } + + props[nm] = it->second; + } + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_properties (props, true); + else + break; + } +} + +void +cdef_class::cdef_class_rep::find_names (std::set& names, + bool all) +{ + load_all_methods (); + + for (method_const_iterator it = method_map.begin (); + ! error_state && it != method_map.end(); ++it) + { + if (! it->second.is_constructor ()) + { + std::string nm = it->second.get_name (); + + if (! all) + { + octave_value acc = it->second.get ("Access"); + + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); + } + } + + for (property_const_iterator it = property_map.begin (); + ! error_state && it != property_map.end (); ++it) + { + std::string nm = it->second.get_name (); + + if (! all) + { + octave_value acc = it->second.get ("GetAccess"); + + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); + } + + // Look into superclasses + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; ! error_state && i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (! error_state) + cls.get_rep ()->find_names (names, all); + else + break; + } +} + +string_vector +cdef_class::cdef_class_rep::get_names (void) +{ + std::set names; + + find_names (names, false); + + if (! error_state) + { + string_vector v (names.size ()); + + int idx = 0; + for (std::set::const_iterator it = names.begin (); + it != names.end (); ++it, ++idx) + v[idx] = *it; + + return v.sort (true); + } + + return string_vector (); +} + +void +cdef_class::cdef_class_rep::delete_object (cdef_object obj) +{ + method_iterator it = method_map.find ("delete"); + + if (it != method_map.end ()) + { + cdef_class cls = obj.get_class (); + + obj.set_class (wrap ()); + + it->second.execute (obj, octave_value_list (), 0, false); + + obj.set_class (cls); + } + + // FIXME: should we destroy corresponding properties here? + + // Call "delete" in super classes + + Cell super_classes = get ("SuperClasses").cell_value (); + + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i)); + + if (!error_state) + cls.delete_object (obj); + } +} + +octave_value_list +cdef_class::cdef_class_rep::meta_subsref (const std::string& type, + const std::list& idx, + int nargout) +{ + size_t skip = 1; + + octave_value_list retval; + + switch (type[0]) + { + case '(': + // Constructor call + gnulib::printf ("constructor\n"); + retval(0) = construct (idx.front ()); + break; + + case '.': + // Static method, constant (or property?) + gnulib::printf ("static method/property\n"); + if (idx.front ().length () == 1) + { + std::string nm = idx.front ()(0).string_value (); + + if (! error_state) + { + cdef_method meth = find_method (nm); + + if (meth.ok ()) + { + if (meth.is_static ()) + { + octave_value_list args; + + if (type.length () > 1 && idx.size () > 1 + && type[1] == '(') + { + args = *(++(idx.begin ())); + skip++; + } + + retval = meth.execute (args, (type.length () > skip + ? 1 : nargout), true, + "meta.class"); + } + else + ::error ("method `%s' is not static", nm.c_str ()); + } + else + { + cdef_property prop = find_property (nm); + + if (prop.ok ()) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (true, "meta.class"); + else + ::error ("property `%s' is not constant", + nm.c_str ()); + } + else + ::error ("no such method or property `%s'", nm.c_str ()); + } + } + else + ::error ("invalid meta.class indexing, expected a method or property name"); + } + else + ::error ("invalid meta.class indexing"); + break; + + default: + ::error ("invalid meta.class indexing"); + break; + } + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +void +cdef_class::cdef_class_rep::meta_release (void) +{ + cdef_manager::unregister_class (wrap ()); +} + +void +cdef_class::cdef_class_rep::initialize_object (cdef_object& obj) +{ + // Populate the object with default property values + + std::list super_classes = lookup_classes (get ("SuperClasses").cell_value ()); + + if (! error_state) + { + for (std::list::iterator it = super_classes.begin (); + ! error_state && it != super_classes.end (); ++it) + it->initialize_object (obj); + + if (! error_state) + { + for (property_const_iterator it = property_map.begin (); + ! error_state && it != property_map.end (); ++it) + { + if (! it->second.get ("Dependent").bool_value ()) + { + octave_value pvalue = it->second.get ("DefaultValue"); + + if (pvalue.is_defined ()) + obj.put (it->first, pvalue); + else + obj.put (it->first, octave_value (Matrix ())); + } + } + + if (! error_state) + { + refcount++; + obj.mark_for_construction (cdef_class (this)); + } + } + } +} + +void +cdef_class::cdef_class_rep::run_constructor (cdef_object& obj, + const octave_value_list& args) +{ + octave_value_list empty_args; + + for (std::list::const_iterator it = implicit_ctor_list.begin (); + ! error_state && it != implicit_ctor_list.end (); ++it) + { + cdef_class supcls = lookup_class (*it); + + if (! error_state) + supcls.run_constructor (obj, empty_args); + } + + if (error_state) + return; + + std::string cls_name = get_name (); + std::string ctor_name = get_base_name (cls_name); + + cdef_method ctor = find_method (ctor_name); + + if (ctor.ok ()) + { + octave_value_list ctor_args (args); + octave_value_list ctor_retval; + + ctor_args.prepend (to_ov (obj)); + ctor_retval = ctor.execute (ctor_args, 1, true, "constructor"); + + if (! error_state) + { + if (ctor_retval.length () == 1) + obj = to_cdef (ctor_retval(0)); + else + { + ::error ("%s: invalid number of output arguments for classdef constructor", + ctor_name.c_str ()); + return; + } + } + } + + obj.mark_as_constructed (wrap ()); +} + +octave_value +cdef_class::cdef_class_rep::construct (const octave_value_list& args) +{ + cdef_object obj = construct_object (args); + + if (! error_state && obj.ok ()) + return to_ov (obj); + + return octave_value (); +} + +cdef_object +cdef_class::cdef_class_rep::construct_object (const octave_value_list& args) +{ + if (! is_abstract ()) + { + cdef_object obj; + + if (is_meta_class ()) + { + // This code path is only used to create empty meta objects + // as filler for the empty values within a meta object array. + + cdef_class this_cls = wrap (); + + static cdef_object empty_class; + + if (this_cls == cdef_class::meta_class ()) + { + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + obj = empty_class; + } + else if (this_cls == cdef_class::meta_property ()) + { + static cdef_property empty_property; + + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + if (! empty_property.ok ()) + empty_property = make_property (empty_class, ""); + obj = empty_property; + } + else if (this_cls == cdef_class::meta_method ()) + { + static cdef_method empty_method; + + if (! empty_class.ok ()) + empty_class = make_class ("", std::list ()); + if (! empty_method.ok ()) + empty_method = make_method (empty_class, "", octave_value ()); + obj = empty_method; + } + else if (this_cls == cdef_class::meta_package ()) + { + static cdef_package empty_package; + + if (! empty_package.ok ()) + empty_package = make_package (""); + obj = empty_package; + } + else + panic_impossible (); + + return obj; + } + else + { + if (is_handle_class ()) + obj = cdef_object (new handle_cdef_object ()); + else + obj = cdef_object (new value_cdef_object ()); + obj.set_class (wrap ()); + + initialize_object (obj); + + if (! error_state) + { + run_constructor (obj, args); + + if (! error_state) + return obj; + } + } + } + else + error ("cannot instantiate object for abstract class `%s'", + get_name ().c_str ()); + + return cdef_object (); +} + +static octave_value +compute_attribute_value (tree_classdef_attribute* t) +{ + if (t->expression ()) + { + if (t->expression ()->is_identifier ()) + { + std::string s = t->expression ()->name (); + + if (s == "public") + return std::string ("public"); + else if (s == "protected") + return std::string ("protected"); + else if (s == "private") + return std::string ("private"); + } + + return t->expression ()->rvalue1 (); + } + else + return octave_value (true); +} + +template +static std::string +attribute_value_to_string (T* t, octave_value v) +{ + if (v.is_string ()) + return v.string_value (); + else if (t->expression ()) + return t->expression ()->original_text (); + else + return std::string ("true"); +} + +cdef_class +cdef_class::make_meta_class (tree_classdef* t, bool is_at_folder) +{ + cdef_class retval; + std::string class_name, full_class_name; + + // Class creation + + class_name = full_class_name = t->ident ()->name (); + if (! t->package_name ().empty ()) + full_class_name = t->package_name () + "." + full_class_name; + gnulib::printf ("class: %s\n", full_class_name.c_str ()); + + std::list slist; + + if (t->superclass_list ()) + { + for (tree_classdef_superclass_list::iterator it = t->superclass_list ()->begin (); + ! error_state && it != t->superclass_list ()->end (); ++it) + { + std::string sclass_name = (*it)->class_name (); + + gnulib::printf ("superclass: %s\n", sclass_name.c_str ()); + + cdef_class sclass = lookup_class (sclass_name); + + if (! error_state) + { + if (! sclass.get ("Sealed").bool_value ()) + slist.push_back (sclass); + else + { + ::error ("`%s' cannot inherit from `%s', because it is sealed", + full_class_name.c_str (), sclass_name.c_str ()); + return retval; + } + } + else + return retval; + + } + } + + retval = ::make_class (full_class_name, slist); + + if (error_state) + return cdef_class (); + + // Package owning this class + + if (! t->package_name ().empty ()) + { + cdef_package pack = cdef_manager::find_package (t->package_name ()); + + if (! error_state && pack.ok ()) + retval.put ("ContainingPackage", to_ov (pack)); + } + + // Class attributes + + if (t->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator it = t->attribute_list ()->begin (); + it != t->attribute_list ()->end (); ++it) + { + std::string aname = (*it)->ident ()->name (); + octave_value avalue = compute_attribute_value (*it); + + gnulib::printf ("class attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*it, avalue).c_str ()); + retval.put (aname, avalue); + } + } + + tree_classdef_body* b = t->body (); + + if (b) + { + // Keep track of the get/set accessor methods. They will be used + // later on when creating properties. + + std::map get_methods; + std::map set_methods; + + // Method blocks + + std::list mb_list = b->methods_list (); + + for (tree_classdef_body::methods_list_iterator it = mb_list.begin (); + it != mb_list.end (); ++it) + { + std::map amap; + gnulib::printf ("method block\n"); + + // Method attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + gnulib::printf ("method attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + amap[aname] = avalue; + } + } + + // Methods + + if ((*it)->element_list ()) + { + for (tree_classdef_methods_list::iterator mit = (*it)->element_list ()->begin (); + mit != (*it)->element_list ()->end (); ++mit) + { + std::string mname = mit->function_value ()->name (); + std::string mprefix = mname.substr (0, 4); + + if (mprefix == "get.") + get_methods[mname.substr (4)] = + make_fcn_handle (*mit, full_class_name + ">" + mname); + else if (mprefix == "set.") + set_methods[mname.substr (4)] = + make_fcn_handle (*mit, full_class_name + ">" + mname); + else + { + cdef_method meth = make_method (retval, mname, *mit); + + gnulib::printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), + mname.c_str ()); + for (std::map::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + meth.put (ait->first, ait->second); + + retval.install_method (meth); + } + } + } + } + + if (is_at_folder) + { + // Look for all external methods visible on octave path at the + // time of loading of the class. + // + // TODO: This is an "extension" to Matlab behavior, which only + // looks in the @-folder containing the original classdef + // file. However, this is easier to implement it that way at + // the moment. + + std::list external_methods = + load_path::methods (full_class_name); + + for (std::list::const_iterator it = external_methods.begin (); + it != external_methods.end (); ++it) + { + // TODO: should we issue a warning if the method is already + // defined in the classdef file? + + if (*it != class_name + && ! retval.find_method (*it, true).ok ()) + { + // Create a dummy method that is used until the actual + // method is loaded. + + octave_user_function *fcn = new octave_user_function (); + + fcn->stash_function_name (*it); + + cdef_method meth = make_method (retval, *it, + octave_value (fcn)); + + retval.install_method (meth); + } + } + } + + // Property blocks + + // FIXME: default property expression should be able to call static + // methods of the class being constructed. A restricted CLASSNAME + // symbol should be added to the scope before evaluating default + // value expressions. + + std::list pb_list = b->properties_list (); + + for (tree_classdef_body::properties_list_iterator it = pb_list.begin (); + it != pb_list.end (); ++it) + { + std::map amap; + gnulib::printf ("property block\n"); + + // Property attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + gnulib::printf ("property attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + if (aname == "Access") + { + amap["GetAccess"] = avalue; + amap["SetAccess"] = avalue; + } + else + amap[aname] = avalue; + } + } + + // Properties + + if ((*it)->element_list ()) + { + for (tree_classdef_property_list::iterator pit = (*it)->element_list ()->begin (); + pit != (*it)->element_list ()->end (); ++pit) + { + std::string prop_name = (*pit)->ident ()->name (); + + cdef_property prop = ::make_property (retval, prop_name); + + gnulib::printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); + if ((*pit)->expression ()) + { + octave_value pvalue = (*pit)->expression ()->rvalue1 (); + + gnulib::printf ("property default: %s\n", + attribute_value_to_string (*pit, pvalue).c_str ()); + prop.put ("DefaultValue", pvalue); + } + + // Install property attributes. This is done before assigning the + // property accessors so we can do validationby using cdef_property + // methods. + + for (std::map::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + prop.put (ait->first, ait->second); + + // Install property access methods, if any. Remove the accessor + // methods from the temporary storage map, so we can detect which + // ones are invalid and do not correspond to a defined property. + + std::map::iterator git = + get_methods.find (prop_name); + + if (git != get_methods.end ()) + { + make_function_of_class (retval, git->second); + prop.put ("GetMethod", git->second); + get_methods.erase (git); + } + + std::map::iterator sit = + set_methods.find (prop_name); + + if (sit != set_methods.end ()) + { + make_function_of_class (retval, sit->second); + prop.put ("SetMethod", sit->second); + set_methods.erase (sit); + } + + retval.install_property (prop); + } + } + } + } + + return retval; +} + +octave_function* +cdef_class::get_method_function (const std::string& /* nm */) +{ + octave_classdef_meta* p = new octave_classdef_meta (*this); + + return p; +} + +octave_value +cdef_property::cdef_property_rep::get_value (const cdef_object& obj, + bool do_check_access, + const std::string& who) +{ + octave_value retval; + + if (do_check_access && ! check_get_access ()) + { + gripe_property_access (who, wrap (), false); + + return retval; + } + + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls)) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return retval; + } + } + + octave_value get_fcn = get ("GetMethod"); + + // FIXME: should check whether we're already in get accessor method + + if (get_fcn.is_empty () || is_method_executing (get_fcn, obj)) + retval = obj.get (get ("Name").string_value ()); + else + { + octave_value_list args; + + args(0) = to_ov (obj); + + args = execute_ov (get_fcn, args, 1); + + if (! error_state) + retval = args(0); + } + + return retval; +} + +octave_value +cdef_property::cdef_property_rep::get_value (bool do_check_access, + const std::string& who) +{ + if (do_check_access && ! check_get_access ()) + { + gripe_property_access (who, wrap (), false); + + return octave_value (); + } + + return get ("DefaultValue"); +} + +bool +cdef_property::cdef_property_rep::is_recursive_set (const cdef_object& /* obj */) const +{ + // FIXME: implement + return false; +} + +void +cdef_property::cdef_property_rep::set_value (cdef_object& obj, + const octave_value& val, + bool do_check_access, + const std::string& who) +{ + if (do_check_access && ! check_set_access ()) + { + gripe_property_access (who, wrap (), true); + + return; + } + + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls)) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return; + } + } + + octave_value set_fcn = get ("SetMethod"); + + if (set_fcn.is_empty () || is_method_executing (set_fcn, obj)) + obj.put (get ("Name").string_value (), val); + else + { + octave_value_list args; + + args(0) = to_ov (obj); + args(1) = val; + + args = execute_ov (set_fcn, args, 1); + + if (! error_state) + { + if (args.length() > 0) + { + cdef_object new_obj = to_cdef (args(0)); + + if (! error_state) + obj = new_obj; + } + } + } +} + +bool +cdef_property::cdef_property_rep::check_get_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("GetAccess"), std::string (), + get_name (), false); + + return false; +} + +bool +cdef_property::cdef_property_rep::check_set_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("SetAccess"), std::string (), + get_name (), true); + + return false; +} + +void +cdef_method::cdef_method_rep::check_method (void) +{ + if (is_external ()) + { + if (is_dummy_method (function)) + { + std::string name = get_name (); + std::string cls_name = dispatch_type; + std::string pack_name; + + size_t pos = cls_name.rfind ('.'); + + if (pos != std::string::npos) + { + pack_name = cls_name.substr (0, pos); + cls_name = cls_name.substr (pos + 1); + } + + std::string dir_name; + std::string file_name = load_path::find_method (cls_name, name, + dir_name, pack_name); + + if (! file_name.empty ()) + { + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type, + pack_name); + + if (fcn) + { + function = octave_value (fcn); + + make_function_of_class (dispatch_type, function); + } + } + } + else + { + // FIXME: check out-of-date status + } + + if (is_dummy_method (function)) + ::error ("no definition found for method `%s' of class `%s'", + get_name ().c_str (), dispatch_type.c_str ()); + } +} + +octave_value_list +cdef_method::cdef_method_rep::execute (const octave_value_list& args, + int nargout, bool do_check_access, + const std::string& who) +{ + octave_value_list retval; + + if (do_check_access && ! check_access ()) + { + gripe_method_access (who, wrap ()); + + return retval; + } + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + if (! error_state && function.is_defined ()) + { + retval = execute_ov (function, args, nargout); + } + } + else + error ("%s: cannot execute abstract method", + get ("Name").string_value ().c_str ()); + + return retval; +} + +octave_value_list +cdef_method::cdef_method_rep::execute (const cdef_object& obj, + const octave_value_list& args, + int nargout, bool do_check_access, + const std::string& who) +{ + octave_value_list retval; + + if (do_check_access && ! check_access ()) + { + gripe_method_access (who, wrap ()); + + return retval; + } + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + if (! error_state && function.is_defined ()) + { + octave_value_list new_args; + + new_args.resize (args.length () + 1); + + new_args(0) = to_ov (obj); + for (int i = 0; i < args.length (); i++) + new_args(i+1) = args(i); + + retval = execute_ov (function, new_args, nargout); + } + } + else + error ("%s: cannot execute abstract method", + get ("Name").string_value ().c_str ()); + + return retval; +} + +bool +cdef_method::cdef_method_rep::is_constructor (void) const +{ + if (function.is_function()) + return function.function_value ()->is_classdef_constructor (); + + return false; +} + +bool +cdef_method::cdef_method_rep::check_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("Access"), get_name ()); + + return false; +} + +octave_value_list +cdef_method::cdef_method_rep::meta_subsref + (const std::string& type, const std::list& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '(': + retval = execute (idx.front (), type.length () > 1 ? 1 : nargout, true); + break; + + default: + error ("invalid meta.method indexing"); + break; + } + + if (! error_state) + { + if (type.length () > 1 && idx.size () > 1 && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx, 1); + } + + return retval; +} + +static cdef_package +lookup_package (const std::string& name) +{ + return cdef_manager::find_package (name); +} + +static octave_value_list +package_fromName (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval(0) = to_ov (lookup_package (name)); + else + error ("fromName: invalid package name, expected a string value"); + } + else + error ("fromName: invalid number of parameters"); + + return retval; +} + +static octave_value_list +package_get_classes (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 1 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_classes (); + } + + return retval; +} + +static octave_value_list +package_get_functions (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 0 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_functions (); + } + + return retval; +} + +static octave_value_list +package_get_packages (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval (1, Matrix ()); + + if (args.length () == 0 && args(0).type_name () == "object" + && args(0).class_name () == "meta.package") + { + cdef_package pack (to_cdef (args(0))); + + retval(0) = pack.get_packages (); + } + + return retval; +} + +static octave_value_list +package_getAllPackages (const octave_value_list& /* args */, + int /* nargout */) +{ + std::map toplevel_packages; + + std::list names = load_path::get_all_package_names (); + + toplevel_packages["meta"] = cdef_manager::find_package ("meta", false, + false); + + for (std::list::const_iterator it = names.begin (); + it != names.end (); ++it) + toplevel_packages[*it] = cdef_manager::find_package (*it, false, true); + + Cell c (toplevel_packages.size (), 1); + + int i = 0; + + for (std::map::const_iterator it = toplevel_packages.begin (); + it != toplevel_packages.end (); ++it) + c(i++,0) = to_ov (it->second); + + return octave_value_list (octave_value (c)); +} + +void +cdef_package::cdef_package_rep::install_class (const cdef_class& cls, + const std::string& nm) +{ + class_map[nm] = cls; + + member_count++; +} + +void +cdef_package::cdef_package_rep::install_function (const octave_value& fcn, + const std::string& nm) +{ + function_map[nm] = fcn; +} + +void +cdef_package::cdef_package_rep::install_package (const cdef_package& pack, + const std::string& nm) +{ + package_map[nm] = pack; + + member_count++; +} + +template +Cell +map2Cell (const std::map& m) +{ + Cell retval (1, m.size ()); + int i = 0; + + for (typename std::map::const_iterator it = m.begin (); + it != m.end (); ++it, ++i) + { + retval(i) = to_ov (it->second); + } + + return retval; +} + +Cell +cdef_package::cdef_package_rep::get_classes (void) const +{ return map2Cell (class_map); } + +Cell +cdef_package::cdef_package_rep::get_functions (void) const +{ return map2Cell (function_map); } + +Cell +cdef_package::cdef_package_rep::get_packages (void) const +{ return map2Cell (package_map); } + +octave_value +cdef_package::cdef_package_rep::find (const std::string& nm) +{ + std::string symbol_name = get_name () + "." + nm; + + return symbol_table::find (symbol_name, octave_value_list (), true, false); +} + +octave_value_list +cdef_package::cdef_package_rep::meta_subsref + (const std::string& type, const std::list& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '.': + if (idx.front ().length () == 1) + { + std::string nm = idx.front ()(0).string_value (); + + if (! error_state) + { + gnulib::printf ("meta.package query: %s\n", nm.c_str ()); + + octave_value o = find (nm); + + if (o.is_defined ()) + { + if (o.is_function ()) + { + octave_function* fcn = o.function_value (); + + if (! error_state) + { + // NOTE: the case where the package query is the last + // part of this subsref index is handled in the parse + // tree, because there is some logic to handle magic + // "end" that makes it impossible to execute the + // function call at this stage. + + if (type.size () > 1 && + ! fcn->is_postfix_index_handled (type[1])) + { + octave_value_list tmp_args; + + retval = o.do_multi_index_op (nargout, + tmp_args); + } + else + retval(0) = o; + + if (type.size () > 1 && idx.size () > 1) + retval = retval(0).next_subsref (nargout, type, + idx, 1); + } + } + else if (type.size () > 1 && idx.size () > 1) + retval = o.next_subsref (nargout, type, idx, 1); + else + retval(0) = o; + } + else if (! error_state) + error ("member `%s' in package `%s' does not exist", + nm.c_str (), get_name ().c_str ()); + } + else + error ("invalid meta.package indexing, expected a symbol name"); + } + else + error ("invalid meta.package indexing"); + break; + + default: + error ("invalid meta.package indexing"); + break; + } + + return retval; +} + +void +cdef_package::cdef_package_rep::meta_release (void) +{ + // FIXME: Do we really want to unregister the package, as it + // could still be referenced by classes or sub-packages? + // If the package object is recreated later on, it won't + // match the one already referenced by those classes or + // sub-packages. + + //cdef_manager::unregister_package (wrap ()); +} + +cdef_class cdef_class::_meta_class = cdef_class (); +cdef_class cdef_class::_meta_property = cdef_class (); +cdef_class cdef_class::_meta_method = cdef_class (); +cdef_class cdef_class::_meta_package = cdef_class (); + +cdef_package cdef_package::_meta = cdef_package (); + +void +install_classdef (void) +{ + octave_classdef::register_type (); + + /* bootstrap */ + cdef_class handle = make_class ("handle"); + cdef_class meta_class = cdef_class::_meta_class = make_meta_class ("meta.class", handle); + handle.set_class (meta_class); + meta_class.set_class (meta_class); + + /* meta classes */ + cdef_class meta_property = cdef_class::_meta_property = make_meta_class ("meta.property", handle); + cdef_class meta_method = cdef_class::_meta_method = make_meta_class ("meta.method", handle); + cdef_class meta_package = cdef_class::_meta_package = make_meta_class ("meta.package", handle); + + cdef_class meta_event = make_meta_class ("meta.event", handle); + cdef_class meta_dynproperty = make_meta_class ("meta.dynamicproperty", handle); + + /* meta.class properties */ + meta_class.install_property (make_attribute (meta_class, "Abstract")); + meta_class.install_property (make_attribute (meta_class, "ConstructOnLoad")); + meta_class.install_property (make_property (meta_class, "ContainingPackage")); + meta_class.install_property (make_property (meta_class, "Description")); + meta_class.install_property (make_property (meta_class, "DetailedDescription")); + meta_class.install_property (make_property (meta_class, "Events")); + meta_class.install_property (make_attribute (meta_class, "HandleCompatible")); + meta_class.install_property (make_attribute (meta_class, "Hidden")); + meta_class.install_property + (make_property (meta_class, "InferiorClasses", + make_fcn_handle (class_get_inferiorclasses, "meta.class>get.InferiorClasses"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "Methods", + make_fcn_handle (class_get_methods, "meta.class>get.Methods"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "MethodList", + make_fcn_handle (class_get_methods, "meta.class>get.MethodList"), + "public", Matrix (), "private")); + meta_class.install_property (make_attribute (meta_class, "Name")); + meta_class.install_property + (make_property (meta_class, "Properties", + make_fcn_handle (class_get_properties, "meta.class>get.Properties"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "PropertyList", + make_fcn_handle (class_get_properties, "meta.class>get.PropertyList"), + "public", Matrix (), "private")); + meta_class.install_property (make_attribute (meta_class, "Sealed")); + meta_class.install_property + (make_property (meta_class, "SuperClasses", + make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClasses"), + "public", Matrix (), "private")); + meta_class.install_property + (make_property (meta_class, "SuperClassList", + make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClassList"), + "public", Matrix (), "private")); + /* meta.class methods */ + meta_class.install_method (make_method (meta_class, "fromName", class_fromName, + "public", true)); + meta_class.install_method (make_method (meta_class, "fevalStatic", class_fevalStatic, + "public", false)); + meta_class.install_method (make_method (meta_class, "getConstant", class_getConstant, + "public", false)); + meta_class.install_method (make_method (meta_class, "eq", class_eq)); + meta_class.install_method (make_method (meta_class, "ne", class_ne)); + meta_class.install_method (make_method (meta_class, "lt", class_lt)); + meta_class.install_method (make_method (meta_class, "le", class_le)); + meta_class.install_method (make_method (meta_class, "gt", class_gt)); + meta_class.install_method (make_method (meta_class, "ge", class_ge)); + + /* meta.method properties */ + meta_method.install_property (make_attribute (meta_method, "Abstract")); + meta_method.install_property (make_attribute (meta_method, "Access")); + meta_method.install_property (make_attribute (meta_method, "DefiningClass")); + meta_method.install_property (make_attribute (meta_method, "Description")); + meta_method.install_property (make_attribute (meta_method, "DetailedDescription")); + meta_method.install_property (make_attribute (meta_method, "Hidden")); + meta_method.install_property (make_attribute (meta_method, "Name")); + meta_method.install_property (make_attribute (meta_method, "Sealed")); + meta_method.install_property (make_attribute (meta_method, "Static")); + + /* meta.property properties */ + meta_property.install_property (make_attribute (meta_property, "Name")); + meta_property.install_property (make_attribute (meta_property, "Description")); + meta_property.install_property (make_attribute (meta_property, "DetailedDescription")); + meta_property.install_property (make_attribute (meta_property, "Abstract")); + meta_property.install_property (make_attribute (meta_property, "Constant")); + meta_property.install_property (make_attribute (meta_property, "GetAccess")); + meta_property.install_property (make_attribute (meta_property, "SetAccess")); + meta_property.install_property (make_attribute (meta_property, "Dependent")); + meta_property.install_property (make_attribute (meta_property, "Transient")); + meta_property.install_property (make_attribute (meta_property, "Hidden")); + meta_property.install_property (make_attribute (meta_property, "GetObservable")); + meta_property.install_property (make_attribute (meta_property, "SetObservable")); + meta_property.install_property (make_attribute (meta_property, "GetMethod")); + meta_property.install_property (make_attribute (meta_property, "SetMethod")); + meta_property.install_property (make_attribute (meta_property, "DefiningClass")); + meta_property.install_property + (make_property (meta_property, "DefaultValue", + make_fcn_handle (property_get_defaultvalue, "meta.property>get.DefaultValue"), + "public", Matrix (), "private")); + meta_property.install_property (make_attribute (meta_property, "HasDefault")); + /* meta.property events */ + // FIXME: add events + + /* handle methods */ + handle.install_method (make_method (handle, "delete", handle_delete)); + + /* meta.package properties */ + meta_package.install_property (make_attribute (meta_package, "Name")); + meta_package.install_property (make_property (meta_package, "ContainingPackage")); + meta_package.install_property + (make_property (meta_package, "ClassList", + make_fcn_handle (package_get_classes, "meta.package>get.ClassList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Classes", + make_fcn_handle (package_get_classes, "meta.package>get.Classes"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "FunctionList", + make_fcn_handle (package_get_functions, "meta.package>get.FunctionList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Functions", + make_fcn_handle (package_get_functions, "meta.package>get.Functions"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "PackageList", + make_fcn_handle (package_get_packages, "meta.package>get.PackageList"), + "public", Matrix (), "private")); + meta_package.install_property + (make_property (meta_package, "Packages", + make_fcn_handle (package_get_packages, "meta.package>get.Packages"), + "public", Matrix (), "private")); + meta_package.install_method (make_method (meta_package, "fromName", package_fromName, + "public", true)); + meta_package.install_method (make_method (meta_package, "getAllPackages", package_getAllPackages, + "public", true)); + + /* create "meta" package */ + cdef_package package_meta = cdef_package::_meta = make_package ("meta"); + package_meta.install_class (meta_class, "class"); + package_meta.install_class (meta_property, "property"); + package_meta.install_class (meta_method, "method"); + package_meta.install_class (meta_package, "package"); + package_meta.install_class (meta_event, "event"); + package_meta.install_class (meta_dynproperty, "dynproperty"); + + /* install built-in classes into the symbol table */ + symbol_table::install_built_in_function + ("meta.class", octave_value (meta_class.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.method", octave_value (meta_method.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.property", octave_value (meta_property.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.package", octave_value (meta_package.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.event", octave_value (meta_event.get_constructor_function ())); + symbol_table::install_built_in_function + ("meta.dynproperty", octave_value (meta_dynproperty.get_constructor_function ())); +} + +//---------------------------------------------------------------------------- + +cdef_manager* cdef_manager::instance = 0; + +void +cdef_manager::create_instance (void) +{ + instance = new cdef_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); +} + +cdef_class +cdef_manager::do_find_class (const std::string& name, + bool error_if_not_found, bool load_if_not_found) +{ + std::map::iterator it = all_classes.find (name); + + if (it == all_classes.end ()) + { + if (load_if_not_found) + { + octave_value ov_cls; + + size_t pos = name.rfind ('.'); + + if (pos == std::string::npos) + ov_cls = symbol_table::find (name); + else + { + std::string pack_name = name.substr (0, pos); + + cdef_package pack = do_find_package (pack_name, false, true); + + if (pack.ok ()) + ov_cls = pack.find (name.substr (pos+1)); + } + + if (ov_cls.is_defined ()) + it = all_classes.find (name); + } + } + + if (it == all_classes.end ()) + { + if (error_if_not_found) + error ("class not found: %s", name.c_str ()); + } + else + { + cdef_class cls = it->second; + + if (! cls.is_builtin ()) + cls = lookup_class (cls); + + if (cls.ok ()) + return cls; + else + all_classes.erase (it); + } + + return cdef_class (); +} + +octave_function* +cdef_manager::do_find_method_symbol (const std::string& method_name, + const std::string& class_name) +{ + octave_function *retval = 0; + + cdef_class cls = find_class (class_name, false, false); + + if (cls.ok ()) + { + cdef_method meth = cls.find_method (method_name); + + if (meth.ok ()) + retval = new octave_classdef_meta (meth); + } + + return retval; +} + +cdef_package +cdef_manager::do_find_package (const std::string& name, + bool error_if_not_found, + bool load_if_not_found) +{ + cdef_package retval; + + std::map::const_iterator it + = all_packages.find (name); + + if (it != all_packages.end ()) + { + retval = it->second; + + if (! retval.ok ()) + error ("invalid package `%s'", name.c_str ()); + } + else + { + if (load_if_not_found && load_path::find_package (name)) + { + size_t pos = name.find ('.'); + + if (pos == std::string::npos) + retval = make_package (name, std::string ()); + else + { + std::string parent_name = name.substr (0, pos); + + retval = make_package (name, parent_name); + } + } + else if (error_if_not_found) + error ("unknown package `%s'", name.c_str ()); + } + + return retval; +} + +octave_function* +cdef_manager::do_find_package_symbol (const std::string& pack_name) +{ + octave_function* retval = 0; + + cdef_package pack = find_package (pack_name, false); + + if (pack.ok ()) + retval = new octave_classdef_meta (pack); + + return retval; +} + +//---------------------------------------------------------------------------- + +DEFUN (__meta_get_package__, args, , "") +{ + octave_value retval; + + if (args.length () == 1) + { + std::string cname = args(0).string_value (); + + if (! error_state) + retval = to_ov (lookup_package (cname)); + else + error ("invalid package name, expected a string value"); + } + else + print_usage (); + + return retval; +} + +DEFUN (__superclass_reference__, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __superclass_reference__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + return octave_value (new octave_classdef_superclass_ref (args)); +} + +DEFUN (__meta_class_query__, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __meta_class_query__ ()\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + std::cerr << "__meta_class_query__ (" + << args(0).string_value () << ")" + << std::endl; + + if (args.length () == 1) + { + std::string cls = args(0).string_value (); + + if (! error_state) + retval = to_ov (lookup_class (cls)); + else + error ("invalid class name, expected a string value"); + } + else + print_usage (); + + return retval; +} + +DEFUN (metaclass, args, /* nargout */, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} metaclass (obj)\n\ +Returns the meta.class object corresponding to the class of @var{obj}.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + cdef_object obj = to_cdef (args(0)); + + if (! error_state) + retval = to_ov (obj.get_class ()); + else + print_usage (); + } + else + print_usage (); + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/octave-value/ov-classdef.h Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,1666 @@ +/* + +Copyright (C) 2012-2013 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_classdef_h) +#define octave_classdef_h 1 + +#include +#include +#include + +#include "oct-map.h" +#include "oct-refcount.h" +#include "ov-base.h" +#include "symtab.h" + +class cdef_object; +class cdef_class; +class cdef_property; +class cdef_method; +class cdef_package; + +class tree_classdef; + +// This is mainly a boostrap class to declare the expected interface. +// The actual base class is cdef_class_base, which is declared after +// cdef_object, such that it can contain cdef_object objects. +class +cdef_object_rep +{ +public: + friend class cdef_object; + +public: + cdef_object_rep (void) : refcount (1) { } + + virtual ~cdef_object_rep (void) { } + + virtual cdef_class get_class (void) const; + + virtual void set_class (const cdef_class&) + { gripe_invalid_object ("set_class"); } + + virtual cdef_object_rep* clone (void) const + { + gripe_invalid_object ("clone"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* empty_clone (void) const + { + gripe_invalid_object ("empty_clone"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* copy (void) const + { + gripe_invalid_object ("copy"); + return new cdef_object_rep (); + } + + virtual cdef_object_rep* make_array (void) const + { + gripe_invalid_object ("make_array"); + return new cdef_object_rep (); + } + + virtual bool is_array (void) const { return false; } + + virtual bool is_value_object (void) const { return false; } + + virtual bool is_handle_object (void) const { return false; } + + virtual bool is_meta_object (void) const { return false; } + + virtual Array array_value (void) const + { + gripe_invalid_object ("array_value"); + return Array (); + } + + virtual void put (const std::string&, const octave_value&) + { gripe_invalid_object ("put"); } + + virtual octave_value get (const std::string&) const + { + gripe_invalid_object ("get"); + return octave_value (); + } + + virtual octave_value_list + subsref (const std::string&, const std::list&, + int, size_t&, const cdef_class&, bool) + { + gripe_invalid_object ("subsref"); + return octave_value_list (); + } + + virtual octave_value + subsasgn (const std::string&, const std::list&, + const octave_value&) + { + gripe_invalid_object ("subsasgn"); + return octave_value (); + } + + virtual string_vector map_keys(void) const; + + virtual bool is_valid (void) const { return false; } + + std::string class_name (void) const; + + virtual void mark_for_construction (const cdef_class&) + { gripe_invalid_object ("mark_for_construction"); } + + virtual bool is_constructed_for (const cdef_class&) const + { + gripe_invalid_object ("is_constructed_for"); + return false; + } + + virtual bool is_partially_constructed_for (const cdef_class&) const + { + gripe_invalid_object ("is_partially_constructed_for"); + return false; + } + + virtual void mark_as_constructed (void) + { gripe_invalid_object ("mark_as_constructed"); } + + virtual void mark_as_constructed (const cdef_class&) + { gripe_invalid_object ("mark_as_constructed"); } + + virtual bool is_constructed (void) const + { + gripe_invalid_object ("is_constructed"); + return false; + } + + virtual octave_idx_type static_count (void) const { return 0; } + + virtual void destroy (void) { delete this; } + + void release (void) + { + if (--refcount == static_count ()) + destroy (); + } + + virtual dim_vector dims (void) const { return dim_vector (); } + +protected: + /* reference count */ + octave_refcount refcount; + +protected: + /* Restricted copying */ + cdef_object_rep (const cdef_object_rep&) + : refcount (1) { } + +private: + /* No assignment */ + cdef_object_rep& operator = (const cdef_object_rep& ); + + void gripe_invalid_object (const char *who) const + { error ("%s: invalid object", who); } +}; + +class +cdef_object +{ +public: + /* FIXME: use a null object */ + cdef_object (void) + : rep (new cdef_object_rep ()) { } + + cdef_object (const cdef_object& obj) + : rep (obj.rep) + { + rep->refcount++; + } + + cdef_object (cdef_object_rep *r) + : rep (r) { } + + virtual ~cdef_object (void) + { rep->release (); } + + cdef_object& operator = (const cdef_object& obj) + { + if (rep != obj.rep) + { + rep->release (); + + rep = obj.rep; + rep->refcount++; + } + + return *this; + } + + cdef_class get_class (void) const; + + void set_class (const cdef_class& cls) { rep->set_class (cls); } + + std::string class_name (void) const + { return rep->class_name (); } + + cdef_object clone (void) const + { return cdef_object (rep->clone ()); } + + cdef_object empty_clone (void) const + { return cdef_object (rep->empty_clone ()); } + + dim_vector dims (void) const { return rep->dims (); } + + cdef_object make_array (void) const + { return cdef_object (rep->make_array ()); } + + cdef_object copy (void) const + { return cdef_object (rep->copy ()); } + + bool is_array (void) const { return rep->is_array (); } + + bool is_value_object (void) const { return rep->is_value_object (); } + + bool is_handle_object (void) const { return rep->is_handle_object (); } + + bool is_meta_object (void) const { return rep->is_meta_object (); } + + Array array_value (void) const { return rep->array_value (); } + + void put (const std::string& pname, const octave_value& val) + { rep->put (pname, val); } + + octave_value get (const std::string& pname) const + { return rep->get (pname); } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add = false) + { return rep->subsref (type, idx, nargout, skip, context, auto_add); } + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs, int ignore_copies = 0) + { + make_unique (ignore_copies); + return rep->subsasgn (type, idx, rhs); + } + + string_vector map_keys (void) const { return rep->map_keys (); } + + const cdef_object_rep* get_rep (void) const { return rep; } + + bool ok (void) const { return rep->is_valid (); } + + void mark_for_construction (const cdef_class& cls) + { rep->mark_for_construction (cls); } + + bool is_constructed (void) const { return rep->is_constructed (); } + + bool is_constructed_for (const cdef_class& cls) const + { return rep->is_constructed_for (cls); } + + bool is_partially_constructed_for (const cdef_class& cls) const + { return rep->is_partially_constructed_for (cls); } + + void mark_as_constructed (void) { rep->mark_as_constructed (); } + + void mark_as_constructed (const cdef_class& cls) + { rep->mark_as_constructed (cls); } + + bool is (const cdef_object& obj) const { return rep == obj.rep; } + +protected: + cdef_object_rep* get_rep (void) { return rep; } + + void make_unique (int ignore_copies) + { + if (rep->refcount > ignore_copies + 1) + *this = clone (); + } + +private: + cdef_object_rep *rep; +}; + +class +cdef_object_base : public cdef_object_rep +{ +public: + cdef_object_base (void) + : cdef_object_rep (), klass () + { + register_object (); + } + + ~cdef_object_base (void) { unregister_object (); } + + cdef_class get_class (void) const; + + void set_class (const cdef_class& cls); + + cdef_object_rep* empty_clone (void) const + { return new cdef_object_base (*this); } + + cdef_object_rep* make_array (void) const; + +protected: + // Restricted copying! + cdef_object_base (const cdef_object_base& obj) + : cdef_object_rep (obj), klass (obj.klass) + { + register_object (); + } + +private: + void register_object (void); + + void unregister_object (void); + +private: + // The class of the object + cdef_object klass; + +private: + // No assignment! + cdef_object_base& operator = (const cdef_object_base&); +}; + +class +cdef_object_array : public cdef_object_base +{ +public: + cdef_object_array (void) : cdef_object_base () { } + + cdef_object_array (const Array& a) + : cdef_object_base (), array (a) { } + + cdef_object_rep* clone (void) const + { return new cdef_object_array (*this); } + + dim_vector dims (void) const { return array.dims (); } + + bool is_valid (void) const { return true; } + + bool is_array (void) const { return true; } + + Array array_value (void) const { return array; } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs); + +private: + Array array; + +private: + void fill_empty_values (void) { fill_empty_values (array); } + + void fill_empty_values (Array& arr); + + // Private copying! + cdef_object_array (const cdef_object_array& obj) + : cdef_object_base (obj), array (obj.array) { } + + // No assignment! + cdef_object_array& operator = (const cdef_object_array&); +}; + +class +cdef_object_scalar : public cdef_object_base +{ +public: + cdef_object_scalar (void) : cdef_object_base () { } + + ~cdef_object_scalar (void) { } + + dim_vector dims (void) const { return dim_vector (1, 1); } + + void put (const std::string& pname, const octave_value& val) + { map.assign (pname, val); } + + octave_value get (const std::string& pname) const + { + Cell val = map.contents (pname); + + if (val.numel () > 0) + return val(0, 0); + else + { + error ("get: unknown slot: %s", pname.c_str ()); + return octave_value (); + } + } + + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context, + bool auto_add); + + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs); + + void mark_for_construction (const cdef_class&); + + bool is_constructed_for (const cdef_class& cls) const; + + bool is_partially_constructed_for (const cdef_class& cls) const; + + void mark_as_constructed (void) { ctor_list.clear (); } + + void mark_as_constructed (const cdef_class& cls) { ctor_list.erase (cls); } + + bool is_constructed (void) const { return ctor_list.empty (); } + +protected: + // Object property values + octave_scalar_map map; + + // Internal/temporary structure used during object construction + std::map< cdef_class, std::list > ctor_list; + +protected: + // Restricted object copying! + cdef_object_scalar (const cdef_object_scalar& obj) + : cdef_object_base (obj), map (obj.map), ctor_list (obj.ctor_list) { } + +private: + // No assignment! + cdef_object_scalar& operator = (const cdef_object_scalar&); +}; + +class +handle_cdef_object : public cdef_object_scalar +{ +public: + handle_cdef_object (void) + : cdef_object_scalar () { } + + ~handle_cdef_object (void); + + cdef_object_rep* clone (void) const + { + handle_cdef_object *obj = const_cast (this); + obj->refcount++; + return obj; + } + + cdef_object_rep* copy (void) const + { return new handle_cdef_object (*this); } + + bool is_valid (void) const { return true; } + + bool is_handle_object (void) const { return true; } + +protected: + // Restricted copying! + handle_cdef_object (const handle_cdef_object& obj) + : cdef_object_scalar (obj) { } + +private: + // No assignment + handle_cdef_object& operator = (const handle_cdef_object&); +}; + +class +value_cdef_object : public cdef_object_scalar +{ +public: + value_cdef_object (void) + : cdef_object_scalar () { } + + ~value_cdef_object (void); + + cdef_object_rep* clone (void) const + { return new value_cdef_object (*this); } + + cdef_object_rep* copy (void) const { return clone (); } + + bool is_valid (void) const { return true; } + + bool is_value_object (void) const { return true; } + +private: + // Private copying! + value_cdef_object (const value_cdef_object& obj) + : cdef_object_scalar (obj) { } + + // No assignment! + value_cdef_object& operator = (const value_cdef_object&); +}; + +class +cdef_meta_object_rep : public handle_cdef_object +{ +public: + cdef_meta_object_rep (void) + : handle_cdef_object () { } + + ~cdef_meta_object_rep (void) { } + + cdef_object_rep* copy (void) const + { return new cdef_meta_object_rep (*this); } + + bool is_meta_object (void) const { return true; } + + virtual bool is_class (void) const { return false; } + + virtual bool is_property (void) const { return false; } + + virtual bool is_method (void) const { return false; } + + virtual bool is_package (void) const { return false; } + + virtual octave_value_list + meta_subsref (const std::string& /* type */, + const std::list& /* idx */, + int /* nargout */) + { + ::error ("subsref: invalid meta object"); + return octave_value_list (); + } + + virtual void meta_release (void) { } + + virtual bool meta_is_postfix_index_handled (char /* type */) const + { return false; } + +protected: + // Restricted copying! + cdef_meta_object_rep (const cdef_meta_object_rep& obj) + : handle_cdef_object (obj) { } + +private: + // No assignment! + cdef_meta_object_rep& operator = (const cdef_meta_object_rep&); +}; + +class +cdef_meta_object : public cdef_object +{ +public: + cdef_meta_object (void) + : cdef_object () { } + + cdef_meta_object (const cdef_meta_object& obj) + : cdef_object (obj) { } + + cdef_meta_object (cdef_meta_object_rep *r) + : cdef_object (r) { } + + // Object consistency is checked in sub-classes. + cdef_meta_object (const cdef_object& obj) + : cdef_object (obj) { } + + ~cdef_meta_object (void) { } + + bool is_class (void) const { return get_rep ()->is_class (); } + + bool is_property (void) const { return get_rep ()->is_property (); } + + bool is_method (void) const { return get_rep ()->is_method (); } + + bool is_package (void) const { return get_rep ()->is_package (); } + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout) + { return get_rep ()->meta_subsref (type, idx, nargout); } + + void meta_release (void) { get_rep ()->meta_release (); } + + bool meta_is_postfix_index_handled (char type) const + { return get_rep ()->meta_is_postfix_index_handled (type); } + +private: + cdef_meta_object_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_meta_object_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +class +cdef_class : public cdef_meta_object +{ +private: + + class + cdef_class_rep : public cdef_meta_object_rep + { + public: + cdef_class_rep (void) + : cdef_meta_object_rep (), member_count (0), handle_class (false), + object_count (0), meta (false) { } + + cdef_class_rep (const std::list& superclasses); + + cdef_object_rep* copy (void) const { return new cdef_class_rep (*this); } + + bool is_class (void) const { return true; } + + std::string get_name (void) const + { return get ("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_abstract (void) const { return get ("Abstract").bool_value (); } + + bool is_sealed (void) const { return get ("Sealed").bool_value (); } + + cdef_method find_method (const std::string& nm, bool local = false); + + void install_method (const cdef_method& meth); + + Cell get_methods (void); + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop); + + Cell get_properties (void); + + string_vector get_names (void); + + void set_directory (const std::string& dir) { directory = dir; } + + std::string get_directory (void) const { return directory; } + + void delete_object (cdef_object obj); + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + void meta_release (void); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '(' || type == '.'); } + + octave_value construct (const octave_value_list& args); + + cdef_object construct_object (const octave_value_list& args); + + void initialize_object (cdef_object& obj); + + void run_constructor (cdef_object& obj, const octave_value_list& args); + + void mark_as_handle_class (void) { handle_class = true; } + + bool is_handle_class (void) const { return handle_class; } + + void register_object (void) { object_count++; } + + void unregister_object (void) { object_count--; } + + octave_idx_type static_count (void) const { return member_count; } + + void destroy (void) + { + if (member_count) + { + refcount++; + cdef_class lock (this); + + member_count = 0; + method_map.clear (); + property_map.clear (); + } + else + delete this; + } + + void mark_as_meta_class (void) { meta = true; } + + bool is_meta_class (void) const { return meta; } + + private: + void load_all_methods (void); + + void find_names (std::set& names, bool all); + + void find_properties (std::map& props, + bool only_inherited); + + void find_methods (std::map& meths, + bool only_inherited); + + cdef_class wrap (void) + { + refcount++; + return cdef_class (this); + } + + private: + // The @-directory were this class is loaded from. + // (not used yet) + std::string directory; + + // The methods defined by this class. + std::map method_map; + + // The properties defined by this class. + std::map property_map; + + // The number of members in this class (methods, properties...) + octave_idx_type member_count; + + // TRUE if this class is a handle class. A class is a handle + // class when the abstract "handle" class is one of its superclasses. + bool handle_class; + + // The list of super-class constructors that are called implicitly by the + // the classdef engine when creating an object. These constructors are not + // called explicitly by the class constructor. + std::list implicit_ctor_list; + + // The number of objects of this class. + octave_refcount object_count; + + // TRUE if this class is a built-in meta class. + bool meta; + + // Utility iterator typedef's. + typedef std::map::iterator method_iterator; + typedef std::map::const_iterator method_const_iterator; + typedef std::map::iterator property_iterator; + typedef std::map::const_iterator property_const_iterator; + + private: + cdef_class_rep (const cdef_class_rep& c) + : cdef_meta_object_rep (c), directory (c.directory), + method_map (c.method_map), property_map (c.property_map), + member_count (c.member_count), handle_class (c.handle_class), + implicit_ctor_list (c.implicit_ctor_list), + object_count (c.object_count), meta (c.meta) { } + }; + +public: + // Create and invalid class object + cdef_class (void) + : cdef_meta_object () { } + + cdef_class (const std::string& nm, + const std::list& superclasses) + : cdef_meta_object (new cdef_class_rep (superclasses)) + { get_rep ()->set_name (nm); } + + cdef_class (const cdef_class& cls) + : cdef_meta_object (cls) { } + + cdef_class (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_class ()) + error ("internal error: invalid assignment from %s to meta.class object", + class_name ().c_str ()); + } + + cdef_class& operator = (const cdef_class& cls) + { + cdef_object::operator= (cls); + + return *this; + } + + cdef_method find_method (const std::string& nm, bool local = false); + + void install_method (const cdef_method& meth) + { get_rep ()->install_method (meth); } + + Cell get_methods (void) { return get_rep ()->get_methods (); } + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop) + { get_rep ()->install_property (prop); } + + Cell get_properties (void) { return get_rep ()->get_properties (); } + + string_vector get_names (void) { return get_rep ()->get_names (); } + + bool is_abstract (void) const { return get_rep ()->is_abstract (); } + + bool is_sealed (void) const { return get_rep ()->is_sealed (); } + + void set_directory (const std::string& dir) + { get_rep ()->set_directory (dir); } + + std::string get_directory (void) const + { return get_rep ()->get_directory (); } + + std::string get_name (void) const + { return get_rep ()->get_name (); } + + bool is_builtin (void) const + { return get_directory ().empty (); } + + void delete_object (cdef_object obj) + { get_rep ()->delete_object (obj); } + + static cdef_class make_meta_class (tree_classdef* t, + bool is_at_folder = false); + + octave_function* get_method_function (const std::string& nm); + + octave_function* get_constructor_function (void) + { return get_method_function (get_name ()); } + + octave_value construct (const octave_value_list& args) + { return get_rep ()->construct (args); } + + cdef_object construct_object (const octave_value_list& args) + { return get_rep ()->construct_object (args); } + + void initialize_object (cdef_object& obj) + { get_rep ()->initialize_object (obj); } + + void run_constructor (cdef_object& obj, const octave_value_list& args) + { get_rep ()->run_constructor (obj, args); } + + void mark_as_handle_class (void) + { get_rep ()->mark_as_handle_class (); } + + bool is_handle_class (void) const + { return get_rep ()->is_handle_class (); } + + void mark_as_meta_class (void) { get_rep ()->mark_as_meta_class (); } + + bool is_meta_class (void) const { return get_rep ()->is_meta_class (); } + + static const cdef_class& meta_class (void) { return _meta_class; } + static const cdef_class& meta_property (void) { return _meta_property; } + static const cdef_class& meta_method (void) { return _meta_method; } + static const cdef_class& meta_package (void) { return _meta_package; } + + void register_object (void) { get_rep ()->register_object (); } + + void unregister_object (void) { get_rep ()->unregister_object (); } + +private: + cdef_class_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_class_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } + + friend bool operator == (const cdef_class&, const cdef_class&); + friend bool operator != (const cdef_class&, const cdef_class&); + friend bool operator < (const cdef_class&, const cdef_class&); + +private: + static cdef_class _meta_class; + static cdef_class _meta_property; + static cdef_class _meta_method; + static cdef_class _meta_package; + + friend void install_classdef (void); +}; + +inline bool +operator == (const cdef_class& clsa, const cdef_class& clsb) +// FIXME: is this really the right way to check class equality? +{ return (clsa.get_rep () == clsb.get_rep ()); } + +inline bool +operator != (const cdef_class& clsa, const cdef_class& clsb) +{ return ! (clsa == clsb); } + +// This is only to be able to use cdef_class as map keys. +inline bool +operator < (const cdef_class& clsa, const cdef_class& clsb) +{ return clsa.get_rep () < clsb.get_rep (); } + +class +cdef_property : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_property_rep : public cdef_meta_object_rep + { + public: + cdef_property_rep (void) + : cdef_meta_object_rep () { } + + cdef_object_rep* copy (void) const { return new cdef_property_rep (*this); } + + bool is_property (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_constant (void) const { return get("Constant").bool_value (); } + + octave_value get_value (bool do_check_access = true, + const std::string& who = std::string ()); + + octave_value get_value (const cdef_object& obj, + bool do_check_access = true, + const std::string& who = std::string ()); + + void set_value (cdef_object& obj, const octave_value& val, + bool do_check_access = true, + const std::string& who = std::string ()); + + bool check_get_access (void) const; + + bool check_set_access (void) const; + + private: + cdef_property_rep (const cdef_property_rep& p) + : cdef_meta_object_rep (p) { } + + bool is_recursive_set (const cdef_object& obj) const; + + cdef_property wrap (void) + { + refcount++; + return cdef_property (this); + } + }; + +public: + cdef_property (void) : cdef_meta_object () { } + + cdef_property (const std::string& nm) + : cdef_meta_object (new cdef_property_rep ()) + { get_rep ()->set_name (nm); } + + cdef_property (const cdef_property& prop) + : cdef_meta_object (prop) { } + + cdef_property (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_property ()) + error ("internal error: invalid assignment from %s to meta.property object", + class_name ().c_str ()); + } + + cdef_property& operator = (const cdef_property& prop) + { + cdef_object::operator= (prop); + + return *this; + } + + octave_value get_value (const cdef_object& obj, bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->get_value (obj, do_check_access, who); } + + octave_value get_value (bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->get_value (do_check_access, who); } + + void set_value (cdef_object& obj, const octave_value& val, + bool do_check_access = true, + const std::string& who = std::string ()) + { get_rep ()->set_value (obj, val, do_check_access, who); } + + bool check_get_access (void) const + { return get_rep ()->check_get_access (); } + + bool check_set_access (void) const + { return get_rep ()->check_set_access (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + bool is_constant (void) const { return get_rep ()->is_constant (); } + +private: + cdef_property_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_property_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +class +cdef_method : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_method_rep : public cdef_meta_object_rep + { + public: + cdef_method_rep (void) + : cdef_meta_object_rep (), function (), dispatch_type () + { } + + cdef_object_rep* copy (void) const { return new cdef_method_rep(*this); } + + bool is_method (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + bool is_static (void) const { return get("Static").bool_value (); } + + octave_value get_function (void) const { return function; } + + void set_function (const octave_value& fcn) { function = fcn; } + + bool check_access (void) const; + + bool is_external (void) const { return ! dispatch_type.empty (); } + + void mark_as_external (const std::string& dtype) + { dispatch_type = dtype; } + + octave_value_list execute (const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()); + + octave_value_list execute (const cdef_object& obj, + const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()); + + bool is_constructor (void) const; + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '(' || type == '.'); } + + private: + cdef_method_rep (const cdef_method_rep& m) + : cdef_meta_object_rep (m), function (m.function), + dispatch_type (m.dispatch_type) + { } + + void check_method (void); + + cdef_method wrap (void) + { + refcount++; + return cdef_method (this); + } + + private: + octave_value function; + + // When non-empty, the method is externally defined and this member + // is used to cache the dispatch type to look for the method. + std::string dispatch_type; + }; + +public: + cdef_method (void) : cdef_meta_object () { } + + cdef_method (const std::string& nm) + : cdef_meta_object (new cdef_method_rep ()) + { get_rep ()->set_name (nm); } + + cdef_method (const cdef_method& meth) + : cdef_meta_object (meth) { } + + cdef_method (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_method ()) + error ("internal error: invalid assignment from %s to meta.method object", + class_name ().c_str ()); + } + + cdef_method& operator = (const cdef_method& meth) + { + cdef_object::operator= (meth); + + return *this; + } + + /* normal invokation */ + octave_value_list execute (const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->execute (args, nargout, do_check_access, who); } + + /* dot-invokation: object is pushed as 1st argument */ + octave_value_list execute (const cdef_object& obj, + const octave_value_list& args, int nargout, + bool do_check_access = true, + const std::string& who = std::string ()) + { return get_rep ()->execute (obj, args, nargout, do_check_access, who); } + + bool check_access (void) const { return get_rep ()->check_access (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + bool is_static (void) const { return get_rep ()->is_static (); } + + void set_function (const octave_value& fcn) + { get_rep ()->set_function (fcn); } + + octave_value get_function (void) const + { return get_rep ()->get_function (); } + + bool is_constructor (void) const + { return get_rep ()->is_constructor (); } + + bool is_external (void) const { return get_rep ()->is_external (); } + + void mark_as_external (const std::string& dtype) + { get_rep ()->mark_as_external (dtype); } + +private: + cdef_method_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_method_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } +}; + +inline cdef_class +cdef_object_rep::get_class (void) const +{ + gripe_invalid_object ("get_class"); + return cdef_class (); +} + +inline std::string +cdef_object_rep::class_name (void) const +{ return get_class ().get_name (); } + +inline cdef_class +cdef_object::get_class (void) const +{ return rep->get_class (); } + +inline cdef_class +cdef_object_base::get_class (void) const +{ return cdef_class (klass); } + +inline void +cdef_object_base::set_class (const cdef_class& cls) +{ + if ((klass.ok () && cls.ok () && cls != get_class ()) + || (klass.ok () && ! cls.ok ()) + || (! klass.ok () && cls.ok ())) + { + unregister_object (); + klass = cls; + register_object (); + } +} + +inline void +cdef_object_base::register_object (void) +{ + if (klass.ok ()) + { + cdef_class cls (get_class ()); + + if (! error_state && cls.ok ()) + cls.register_object (); + } +} + +inline void +cdef_object_base::unregister_object (void) +{ + if (klass.ok ()) + { + cdef_class cls (get_class ()); + + if (! error_state && cls.ok ()) + cls.unregister_object (); + } +} + +inline cdef_object_rep* +cdef_object_base::make_array (void) const +{ + cdef_object_rep* r = new cdef_object_array (); + + r->set_class (get_class ()); + + return r; +} + +inline cdef_method +cdef_class::find_method (const std::string& nm, bool local) +{ return get_rep ()->find_method (nm, local); } + +inline cdef_property +cdef_class::find_property (const std::string& nm) +{ return get_rep ()->find_property (nm); } + +class +cdef_package : public cdef_meta_object +{ + friend class cdef_class; + +private: + + class + cdef_package_rep : public cdef_meta_object_rep + { + public: + cdef_package_rep (void) + : cdef_meta_object_rep (), member_count (0) { } + + ~cdef_package_rep (void) { } + + cdef_object_rep* copy (void) const { return new cdef_package_rep (*this); } + + bool is_package (void) const { return true; } + + std::string get_name (void) const { return get("Name").string_value (); } + + void set_name (const std::string& nm) { put ("Name", nm); } + + void install_class (const cdef_class& cls, const std::string& nm); + + void install_function (const octave_value& fcn, const std::string& nm); + + void install_package (const cdef_package& pack, const std::string& nm); + + Cell get_classes (void) const; + + Cell get_functions (void) const; + + Cell get_packages (void) const; + + octave_idx_type static_count (void) const { return member_count; } + + void destroy (void) + { + if (member_count) + { + refcount++; + cdef_package lock (this); + + member_count = 0; + class_map.clear (); + package_map.clear (); + } + else + delete this; + } + + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + void meta_release (void); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '.'); } + + octave_value find (const std::string& nm); + + private: + std::string full_name; + std::map class_map; + std::map function_map; + std::map package_map; + + // The number of registered members in this package (classes, packages). + // This only accounts for the members that back-reference to this package. + octave_idx_type member_count; + + typedef std::map::iterator class_iterator; + typedef std::map::const_iterator class_const_iterator; + typedef std::map::iterator function_iterator; + typedef std::map::const_iterator function_const_iterator; + typedef std::map::iterator package_iterator; + typedef std::map::const_iterator package_const_iterator; + + private: + cdef_package_rep (const cdef_package_rep& p) + : cdef_meta_object_rep (p), full_name (p.full_name), + class_map (p.class_map), function_map (p.function_map), + package_map (p.package_map), member_count (p.member_count) + { } + + cdef_package wrap (void) + { + refcount++; + return cdef_package (this); + } + }; + +public: + cdef_package (void) : cdef_meta_object () { } + + cdef_package (const std::string& nm) + : cdef_meta_object (new cdef_package_rep ()) + { get_rep ()->set_name (nm); } + + cdef_package (const cdef_package& pack) + : cdef_meta_object (pack) { } + + cdef_package (const cdef_object& obj) + : cdef_meta_object (obj) + { + // This should never happen... + if (! is_package ()) + error ("internal error: invalid assignment from %s to meta.package object", + class_name ().c_str ()); + } + + cdef_package& operator = (const cdef_package& pack) + { + cdef_object::operator= (pack); + + return *this; + } + + void install_class (const cdef_class& cls, const std::string& nm) + { get_rep ()->install_class (cls, nm); } + + void install_function (const octave_value& fcn, const std::string& nm) + { get_rep ()->install_function (fcn, nm); } + + void install_package (const cdef_package& pack, const std::string& nm) + { get_rep ()->install_package (pack, nm); } + + Cell get_classes (void) const + { return get_rep ()->get_classes (); } + + Cell get_functions (void) const + { return get_rep ()->get_functions (); } + + Cell get_packages (void) const + { return get_rep ()->get_packages (); } + + std::string get_name (void) const { return get_rep ()->get_name (); } + + octave_value find (const std::string& nm) { return get_rep ()->find (nm); } + + static const cdef_package& meta (void) { return _meta; } + +private: + cdef_package_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_package_rep* get_rep (void) const + { return dynamic_cast (cdef_object::get_rep ()); } + +private: + static cdef_package _meta; + + friend void install_classdef (void); +}; + +class +octave_classdef : public octave_base_value +{ +public: + octave_classdef (void) + : octave_base_value (), object () { } + + octave_classdef (const cdef_object& obj) + : octave_base_value (), object (obj) { } + + octave_classdef (const octave_classdef& obj) + : octave_base_value (obj), object (obj.object) { } + + octave_base_value* clone (void) const + { return new octave_classdef (object.clone ()); } + + octave_base_value* empty_clone (void) const + { return new octave_classdef (object.empty_clone ()); } + + cdef_object get_object (void) const { return object; } + + cdef_object& get_object_ref (void) { return object; } + + bool is_defined (void) const { return true; } + + bool is_map (void) const { return true; } + + bool is_object (void) const { return true; } + + void print (std::ostream& os, bool pr_as_read_syntax = false); + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + + bool print_name_tag (std::ostream& os, const std::string& name) const; + + void print_with_name (std::ostream& os, const std::string& name, + bool print_padding = true); + + octave_value_list subsref (const std::string& type, + const std::list& idx, + int nargout); + + octave_value subsref (const std::string& type, + const std::list& idx) + { + octave_value_list retval = subsref (type, idx, 1); + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value subsref (const std::string& type, + const std::list& idx, + bool auto_add); + + octave_value subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + octave_value + undef_subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + string_vector map_keys (void) const { return object.map_keys (); } + + dim_vector dims (void) const { return object.dims (); } + +private: + cdef_object object; + +private: + DECLARE_OCTAVE_ALLOCATOR + +public: + int type_id (void) const { return t_id; } + std::string type_name (void) const { return t_name; } + std::string class_name (void) const { return object.class_name (); } + + static int static_type_id (void) { return t_id; } + static std::string static_type_name (void) { return t_name; } + static std::string static_class_name (void) { return ""; } + static void register_type (void); + +private: + static int t_id; + + static const std::string t_name; +}; + +inline octave_value +to_ov (const cdef_object& obj) +{ + if (obj.ok ()) + return octave_value (new octave_classdef (obj)); + else + return octave_value (Matrix ()); +} + +inline octave_value +to_ov (const octave_value& ov) +{ return ov; } + +inline cdef_object +to_cdef (const octave_value& val) +{ + if (val.type_name () == "object") + return dynamic_cast (val.internal_rep ())->get_object (); + else + { + error ("cannot convert `%s' into `object'", val.type_name().c_str ()); + return cdef_object (); + } +} + +inline cdef_object& +to_cdef_ref (const octave_value& val) +{ + static cdef_object empty; + + if (val.type_name () == "object") + return dynamic_cast (val.internal_rep ())->get_object_ref (); + else + { + error ("cannot convert `%s' into `object'", val.type_name().c_str ()); + return empty; + } +} + +inline cdef_object +to_cdef (const cdef_object& obj) +{ return obj; } + +OCTINTERP_API void install_classdef (void); + +class +cdef_manager +{ +public: + + static cdef_class find_class (const std::string& name, + bool error_if_not_found = true, + bool load_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_class (name, error_if_not_found, + load_if_not_found); + + return cdef_class (); + } + + static octave_function* find_method_symbol (const std::string& method_name, + const std::string& class_name) + { + if (instance_ok ()) + return instance->do_find_method_symbol (method_name, class_name); + + return 0; + } + + static cdef_package find_package (const std::string& name, + bool error_if_not_found = true, + bool load_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_package (name, error_if_not_found, + load_if_not_found); + + return cdef_package (); + } + + static octave_function* find_package_symbol (const std::string& pack_name) + { + if (instance_ok ()) + return instance->do_find_package_symbol (pack_name); + + return 0; + } + + static void register_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_register_class (cls); + } + + static void unregister_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_unregister_class (cls); + } + + static void register_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_register_package (pkg); + } + + static void unregister_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_unregister_package (pkg); + } + +private: + + cdef_manager (void) { } + + cdef_manager (const cdef_manager&); + + cdef_manager& operator = (const cdef_manager&); + + ~cdef_manager (void) { } + + static void create_instance (void); + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + create_instance (); + + if (! instance) + { + ::error ("unable to create cdef_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) + { + delete instance; + + instance = 0; + } + + cdef_class do_find_class (const std::string& name, bool error_if_not_found, + bool load_if_not_found); + + octave_function* do_find_method_symbol (const std::string& method_name, + const std::string& class_name); + + cdef_package do_find_package (const std::string& name, + bool error_if_not_found, + bool load_if_not_found); + + octave_function* do_find_package_symbol (const std::string& pack_name); + + void do_register_class (const cdef_class& cls) + { all_classes[cls.get_name ()] = cls; } + + void do_unregister_class (const cdef_class& cls) + { all_classes.erase(cls.get_name ()); } + + void do_register_package (const cdef_package& pkg) + { all_packages[pkg.get_name ()] = pkg; } + + void do_unregister_package (const cdef_package& pkg) + { all_packages.erase(pkg.get_name ()); } + +private: + + // The single cdef_manager instance + static cdef_manager *instance; + + // All registered/loaded classes + std::map all_classes; + + // All registered/loaded packages + std::map all_packages; +}; + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-colon.cc --- a/libinterp/octave-value/ov-colon.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-colon.cc Fri Mar 07 13:02:43 2014 -0500 @@ -35,7 +35,7 @@ "magic-colon", "magic-colon"); void -octave_magic_colon::print (std::ostream& os, bool) const +octave_magic_colon::print (std::ostream& os, bool) { indent (os); print_raw (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-colon.h --- a/libinterp/octave-value/ov-colon.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-colon.h Fri Mar 07 13:02:43 2014 -0500 @@ -67,7 +67,7 @@ bool is_magic_colon (void) const { return true; } - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-complex.cc --- a/libinterp/octave-value/ov-complex.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-complex.cc Fri Mar 07 13:02:43 2014 -0500 @@ -315,7 +315,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, type_hid = -1, data_hid = -1; + hid_t space_hid, type_hid, data_hid; + space_hid = type_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-cx-diag.cc --- a/libinterp/octave-value/ov-cx-diag.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-cx-diag.cc Fri Mar 07 13:02:43 2014 -0500 @@ -167,7 +167,8 @@ octave_complex_diag_matrix::save_binary (std::ostream& os, bool& save_as_floats) { - int32_t r = matrix.rows (), c = matrix.cols (); + int32_t r = matrix.rows (); + int32_t c = matrix.cols (); os.write (reinterpret_cast (&r), 4); os.write (reinterpret_cast (&c), 4); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-cx-mat.cc --- a/libinterp/octave-value/ov-cx-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-cx-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -561,7 +561,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1, type_hid = -1; + hid_t space_hid, data_hid, type_hid; + space_hid = data_hid = type_hid = -1; bool retval = true; ComplexNDArray m = complex_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-cx-sparse.cc --- a/libinterp/octave-value/ov-cx-sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-cx-sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -390,7 +390,8 @@ if (group_hid < 0) return false; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; SparseComplexMatrix m = sparse_complex_matrix_value (); octave_idx_type tmp; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-fcn-handle.cc --- a/libinterp/octave-value/ov-fcn-handle.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-fcn-handle.cc Fri Mar 07 13:02:43 2014 -0500 @@ -270,7 +270,7 @@ std::string dir_name = str.substr (0, xpos); octave_function *xfcn - = load_fcn_from_file (str, dir_name, "", nm); + = load_fcn_from_file (str, dir_name, "", "", nm); if (xfcn) { @@ -300,7 +300,7 @@ std::string dir_name = str.substr (0, xpos); - octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm); + octave_function *xfcn = load_fcn_from_file (str, dir_name, "", "", nm); if (xfcn) { @@ -323,7 +323,7 @@ std::string dir_name = fpath.substr (0, xpos); - octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm); + octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", "", nm); if (xfcn) { @@ -721,7 +721,8 @@ if (group_hid < 0) return false; - hid_t space_hid = -1, data_hid = -1, type_hid = -1;; + hid_t space_hid, data_hid, type_hid; + space_hid = data_hid = type_hid = -1; // attach the type of the variable type_hid = H5Tcopy (H5T_C_S1); @@ -1386,7 +1387,7 @@ */ void -octave_fcn_handle::print (std::ostream& os, bool pr_as_read_syntax) const +octave_fcn_handle::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); @@ -1572,7 +1573,8 @@ // for any class. if (local_funcs && fptr && (fptr->is_subfunction () || fptr->is_private_function () - || fptr->is_class_constructor ())) + || fptr->is_class_constructor () + || fptr->is_classdef_constructor ())) { // Locally visible function. retval = octave_value (new octave_fcn_handle (f, tnm)); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-fcn-handle.h --- a/libinterp/octave-value/ov-fcn-handle.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-fcn-handle.h Fri Mar 07 13:02:43 2014 -0500 @@ -153,7 +153,7 @@ bool load_hdf5 (hid_t loc_id, const char *name); #endif - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-fcn-inline.cc --- a/libinterp/octave-value/ov-fcn-inline.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-fcn-inline.cc Fri Mar 07 13:02:43 2014 -0500 @@ -291,7 +291,8 @@ if (len < ifargs(i).length ()) len = ifargs(i).length (); - hid_t space_hid = -1, data_hid = -1, type_hid = -1;; + hid_t space_hid, data_hid, type_hid; + space_hid = data_hid = type_hid = -1; bool retval = true; // FIXME: Is there a better way of saving string vectors, @@ -597,7 +598,7 @@ #endif void -octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) const +octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-fcn-inline.h --- a/libinterp/octave-value/ov-fcn-inline.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-fcn-inline.h Fri Mar 07 13:02:43 2014 -0500 @@ -86,7 +86,7 @@ bool load_hdf5 (hid_t loc_id, const char *name); #endif - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-fcn.h --- a/libinterp/octave-value/ov-fcn.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-fcn.h Fri Mar 07 13:02:43 2014 -0500 @@ -46,7 +46,8 @@ octave_function (void) : relative (false), locked (false), private_function (false), - xdispatch_class (), my_name (), my_dir_name (), doc () { } + xdispatch_class (), xpackage_name (), my_name (), my_dir_name (), + doc () { } ~octave_function (void) { } @@ -85,6 +86,10 @@ virtual bool is_class_constructor (const std::string& = std::string ()) const { return false; } + virtual bool + is_classdef_constructor (const std::string& = std::string ()) const + { return false; } + virtual bool is_class_method (const std::string& = std::string ()) const { return false; } @@ -96,6 +101,10 @@ std::string dispatch_class (void) const { return xdispatch_class; } + void stash_package_name (const std::string& pack) { xpackage_name = pack; } + + std::string package_name (void) const { return xpackage_name; } + virtual void mark_as_private_function (const std::string& cname = std::string ()) { @@ -152,6 +161,14 @@ std::string name (void) const { return my_name; } + std::string canonical_name (void) const + { + if (xpackage_name.empty ()) + return my_name; + else + return xpackage_name + "." + my_name; + } + void document (const std::string& ds) { doc = ds; } std::string doc_string (void) const { return doc; } @@ -160,6 +177,9 @@ virtual void accept (tree_walker&) { } + virtual bool is_postfix_index_handled (char type) const + { return (type == '(' || type == '{'); } + protected: octave_function (const std::string& nm, @@ -181,6 +201,10 @@ // to which the method belongs. std::string xdispatch_class; + // If this function is part of a package, this is the full name + // of the package to which the function belongs. + std::string xpackage_name; + // The name of this function. std::string my_name; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-float.cc --- a/libinterp/octave-value/ov-float.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-float.cc Fri Mar 07 13:02:43 2014 -0500 @@ -191,7 +191,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); @@ -326,8 +327,31 @@ SCALAR_MAPPER (isnan, xisnan); SCALAR_MAPPER (xsignbit, xsignbit); + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return scalar; + + case umap_xisalnum: + case umap_xisalpha: + case umap_xisascii: + case umap_xiscntrl: + case umap_xisdigit: + case umap_xisgraph: + case umap_xislower: + case umap_xisprint: + case umap_xispunct: + case umap_xisspace: + case umap_xisupper: + case umap_xisxdigit: + case umap_xtoascii: + { + octave_value str_conv = convert_to_str (true, true); + return error_state ? octave_value () : str_conv.map (umap); + } + default: - return octave_base_value::map (umap); + return octave_base_value::map (umap); } } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-flt-complex.cc --- a/libinterp/octave-value/ov-flt-complex.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-flt-complex.cc Fri Mar 07 13:02:43 2014 -0500 @@ -300,7 +300,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, type_hid = -1, data_hid = -1; + hid_t space_hid, type_hid, data_hid; + space_hid = type_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-flt-cx-diag.cc --- a/libinterp/octave-value/ov-flt-cx-diag.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-flt-cx-diag.cc Fri Mar 07 13:02:43 2014 -0500 @@ -150,7 +150,8 @@ bool& /* save_as_floats */) { - int32_t r = matrix.rows (), c = matrix.cols (); + int32_t r = matrix.rows (); + int32_t c = matrix.cols (); os.write (reinterpret_cast (&r), 4); os.write (reinterpret_cast (&c), 4); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-flt-cx-mat.cc --- a/libinterp/octave-value/ov-flt-cx-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-flt-cx-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -536,7 +536,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1, type_hid = -1; + hid_t space_hid, data_hid, type_hid; + space_hid = data_hid = type_hid = -1; bool retval = true; FloatComplexNDArray m = complex_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-flt-re-diag.cc --- a/libinterp/octave-value/ov-flt-re-diag.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-flt-re-diag.cc Fri Mar 07 13:02:43 2014 -0500 @@ -119,7 +119,8 @@ bool& /* save_as_floats*/) { - int32_t r = matrix.rows (), c = matrix.cols (); + int32_t r = matrix.rows (); + int32_t c = matrix.cols (); os.write (reinterpret_cast (&r), 4); os.write (reinterpret_cast (&c), 4); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-flt-re-mat.cc --- a/libinterp/octave-value/ov-flt-re-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-flt-re-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -563,7 +563,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; FloatNDArray m = array_value (); @@ -811,6 +812,29 @@ ARRAY_MAPPER (isna, bool, octave_is_NA); ARRAY_MAPPER (xsignbit, float, xsignbit); + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return matrix; + + case umap_xisalnum: + case umap_xisalpha: + case umap_xisascii: + case umap_xiscntrl: + case umap_xisdigit: + case umap_xisgraph: + case umap_xislower: + case umap_xisprint: + case umap_xispunct: + case umap_xisspace: + case umap_xisupper: + case umap_xisxdigit: + case umap_xtoascii: + { + octave_value str_conv = convert_to_str (true, true); + return error_state ? octave_value () : str_conv.map (umap); + } + default: return octave_base_value::map (umap); } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-intx.h --- a/libinterp/octave-value/ov-intx.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-intx.h Fri Mar 07 13:02:43 2014 -0500 @@ -358,8 +358,15 @@ case umap_finite: return boolNDArray (matrix.dims (), true); + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return matrix; + default: { + // FIXME: we should be able to do better than converting to + // double here. octave_matrix m (array_value ()); return m.map (umap); } @@ -658,6 +665,11 @@ case umap_finite: return true; + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return scalar; + default: { octave_scalar m (scalar_value ()); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-java.cc --- a/libinterp/octave-value/ov-java.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-java.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1150,7 +1150,8 @@ if (jni_env->IsInstanceOf (jobj, cls)) { jobjectArray jarr = reinterpret_cast (jobj); - int rows = jni_env->GetArrayLength (jarr), cols = 0; + int rows = jni_env->GetArrayLength (jarr); + int cols = 0; if (rows > 0) { @@ -1761,7 +1762,7 @@ } void -octave_java::print (std::ostream& os, bool) const +octave_java::print (std::ostream& os, bool) { print_raw (os); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-java.h --- a/libinterp/octave-value/ov-java.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-java.h Fri Mar 07 13:02:43 2014 -0500 @@ -149,7 +149,7 @@ dim_vector dims (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-lazy-idx.h --- a/libinterp/octave-value/ov-lazy-idx.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-lazy-idx.h Fri Mar 07 13:02:43 2014 -0500 @@ -128,7 +128,7 @@ bool print_as_scalar (void) const { return make_value ().print_as_scalar (); } - void print (std::ostream& os, bool pr_as_read_syntax = false) const + void print (std::ostream& os, bool pr_as_read_syntax = false) { make_value ().print (os, pr_as_read_syntax); } void print_info (std::ostream& os, const std::string& prefix) const diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-oncleanup.cc --- a/libinterp/octave-value/ov-oncleanup.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-oncleanup.cc Fri Mar 07 13:02:43 2014 -0500 @@ -170,7 +170,7 @@ #endif void -octave_oncleanup::print (std::ostream& os, bool pr_as_read_syntax) const +octave_oncleanup::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-oncleanup.h --- a/libinterp/octave-value/ov-oncleanup.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-oncleanup.h Fri Mar 07 13:02:43 2014 -0500 @@ -87,7 +87,7 @@ bool load_hdf5 (hid_t loc_id, const char *name); #endif - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-perm.cc --- a/libinterp/octave-value/ov-perm.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-perm.cc Fri Mar 07 13:02:43 2014 -0500 @@ -260,8 +260,6 @@ bool octave_perm_matrix::save_ascii (std::ostream& os) { - typedef octave_int idx_int_type; - os << "# size: " << matrix.rows () << "\n"; os << "# orient: " << (matrix.is_col_perm () ? 'c' : 'r') << '\n'; @@ -277,7 +275,6 @@ bool octave_perm_matrix::load_ascii (std::istream& is) { - typedef octave_int idx_int_type; octave_idx_type n; bool success = true; char orient; @@ -389,7 +386,7 @@ } void -octave_perm_matrix::print (std::ostream& os, bool pr_as_read_syntax) const +octave_perm_matrix::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-perm.h --- a/libinterp/octave-value/ov-perm.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-perm.h Fri Mar 07 13:02:43 2014 -0500 @@ -211,7 +211,7 @@ bool print_as_scalar (void) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_info (std::ostream& os, const std::string& prefix) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-range.cc --- a/libinterp/octave-value/ov-range.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-range.cc Fri Mar 07 13:02:43 2014 -0500 @@ -352,7 +352,7 @@ } void -octave_range::print (std::ostream& os, bool pr_as_read_syntax) const +octave_range::print (std::ostream& os, bool pr_as_read_syntax) { print_raw (os, pr_as_read_syntax); newline (os); @@ -549,7 +549,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, type_hid = -1, data_hid = -1; + hid_t space_hid, type_hid, data_hid; + space_hid = type_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-range.h --- a/libinterp/octave-value/ov-range.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-range.h Fri Mar 07 13:02:43 2014 -0500 @@ -249,7 +249,7 @@ octave_value convert_to_str_internal (bool pad, bool force, char type) const; - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-re-diag.cc --- a/libinterp/octave-value/ov-re-diag.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-re-diag.cc Fri Mar 07 13:02:43 2014 -0500 @@ -179,7 +179,8 @@ octave_diag_matrix::save_binary (std::ostream& os, bool& save_as_floats) { - int32_t r = matrix.rows (), c = matrix.cols (); + int32_t r = matrix.rows (); + int32_t c = matrix.cols (); os.write (reinterpret_cast (&r), 4); os.write (reinterpret_cast (&c), 4); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-re-mat.cc --- a/libinterp/octave-value/ov-re-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-re-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -675,7 +675,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; NDArray m = array_value (); @@ -934,13 +935,30 @@ ARRAY_MAPPER (isna, bool, octave_is_NA); ARRAY_MAPPER (xsignbit, double, xsignbit); + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return matrix; + + case umap_xisalnum: + case umap_xisalpha: + case umap_xisascii: + case umap_xiscntrl: + case umap_xisdigit: + case umap_xisgraph: + case umap_xislower: + case umap_xisprint: + case umap_xispunct: + case umap_xisspace: + case umap_xisupper: + case umap_xisxdigit: + case umap_xtoascii: + { + octave_value str_conv = convert_to_str (true, true); + return error_state ? octave_value () : str_conv.map (umap); + } + default: - if (umap >= umap_xisalnum && umap <= umap_xtoupper) - { - octave_value str_conv = convert_to_str (true, true); - return error_state ? octave_value () : str_conv.map (umap); - } - else return octave_base_value::map (umap); } } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-re-sparse.cc --- a/libinterp/octave-value/ov-re-sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-re-sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -421,7 +421,8 @@ if (group_hid < 0) return false; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; SparseMatrix m = sparse_matrix_value (); octave_idx_type tmp; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-scalar.cc --- a/libinterp/octave-value/ov-scalar.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-scalar.cc Fri Mar 07 13:02:43 2014 -0500 @@ -206,7 +206,8 @@ bool /* save_as_floats */) { hsize_t dimens[3]; - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; space_hid = H5Screate_simple (0, dimens, 0); @@ -342,14 +343,31 @@ SCALAR_MAPPER (isnan, xisnan); SCALAR_MAPPER (xsignbit, xsignbit); + // Special cases for Matlab compatibility. + case umap_xtolower: + case umap_xtoupper: + return scalar; + + case umap_xisalnum: + case umap_xisalpha: + case umap_xisascii: + case umap_xiscntrl: + case umap_xisdigit: + case umap_xisgraph: + case umap_xislower: + case umap_xisprint: + case umap_xispunct: + case umap_xisspace: + case umap_xisupper: + case umap_xisxdigit: + case umap_xtoascii: + { + octave_value str_conv = convert_to_str (true, true); + return error_state ? octave_value () : str_conv.map (umap); + } + default: - if (umap >= umap_xisalnum && umap <= umap_xtoupper) - { - octave_value str_conv = convert_to_str (true, true); - return error_state ? octave_value () : str_conv.map (umap); - } - else - return octave_base_value::map (umap); + return octave_base_value::map (umap); } } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-str-mat.cc --- a/libinterp/octave-value/ov-str-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-str-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -583,7 +583,8 @@ return (empty > 0); int rank = dv.length (); - hid_t space_hid = -1, data_hid = -1; + hid_t space_hid, data_hid; + space_hid = data_hid = -1; bool retval = true; charNDArray m = char_array_value (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-struct.cc --- a/libinterp/octave-value/ov-struct.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-struct.cc Fri Mar 07 13:02:43 2014 -0500 @@ -648,7 +648,7 @@ } void -octave_struct::print (std::ostream& os, bool) const +octave_struct::print (std::ostream& os, bool) { print_raw (os); } @@ -1359,7 +1359,7 @@ } void -octave_scalar_struct::print (std::ostream& os, bool) const +octave_scalar_struct::print (std::ostream& os, bool) { print_raw (os); } @@ -2066,9 +2066,9 @@ return retval; } -DEFUN (nfields, args, , +DEFUN (numfields, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} nfields (@var{s})\n\ +@deftypefn {Built-in Function} {} numfields (@var{s})\n\ Return the number of fields of the structure @var{s}.\n\ @seealso{fieldnames}\n\ @end deftypefn") diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-struct.h --- a/libinterp/octave-value/ov-struct.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-struct.h Fri Mar 07 13:02:43 2014 -0500 @@ -126,7 +126,7 @@ string_vector map_keys (void) const { return map.fieldnames (); } - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; @@ -249,7 +249,7 @@ string_vector map_keys (void) const { return map.fieldnames (); } - void print (std::ostream& os, bool pr_as_read_syntax = false) const; + void print (std::ostream& os, bool pr_as_read_syntax = false); void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-usr-fcn.cc Fri Mar 07 13:02:43 2014 -0500 @@ -203,7 +203,7 @@ num_named_args (param_list ? param_list->length () : 0), subfunction (false), inline_function (false), anonymous_function (false), nested_function (false), - class_constructor (false), class_method (false), + class_constructor (none), class_method (false), parent_scope (-1), local_scope (sid), curr_unwind_protect_frame (0) #ifdef HAVE_LLVM @@ -470,7 +470,7 @@ octave_value_list octave_user_function::do_multi_index_op (int nargout, - const octave_value_list& args, + const octave_value_list& _args, const std::list* lvalue_list) { octave_value_list retval; @@ -481,6 +481,23 @@ if (! cmd_list) return retval; + // If this function is a classdef constructor, extract the first input + // argument, which must be the partially constructed object instance. + + octave_value_list args (_args); + octave_value_list ret_args; + + if (is_classdef_constructor ()) + { + if (args.length () > 0) + { + ret_args = args.slice (0, 1, true); + args = args.slice (1, args.length () - 1, true); + } + else + panic_impossible (); + } + #ifdef HAVE_LLVM if (is_special_expr () && tree_jit::execute (*this, args, retval)) @@ -524,6 +541,25 @@ return retval; } + // For classdef constructor, pre-populate the output arguments + // with the pre-initialized object instance, extracted above. + + if (is_classdef_constructor ()) + { + if (ret_list) + { + ret_list->define_from_arg_vector (ret_args); + if (error_state) + return retval; + } + else + { + ::error ("%s: invalid classdef constructor, no output argument defined", + dispatch_class ().c_str ()); + return retval; + } + } + // Force parameter list to be undefined when this function exits. // Doing so decrements the reference counts on the values of local // variables that are also named function parameters. @@ -743,7 +779,8 @@ { // Only assign the hidden variable if black holes actually present. Matrix bh (1, nbh); - octave_idx_type k = 0, l = 0; + octave_idx_type k = 0; + octave_idx_type l = 0; for (std::list::const_iterator p = lvalue_list->begin (); p != lvalue_list->end (); p++) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov-usr-fcn.h --- a/libinterp/octave-value/ov-usr-fcn.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov-usr-fcn.h Fri Mar 07 13:02:43 2014 -0500 @@ -327,12 +327,20 @@ void mark_as_nested_function (void) { nested_function = true; } - void mark_as_class_constructor (void) { class_constructor = true; } + void mark_as_class_constructor (void) { class_constructor = legacy; } + + void mark_as_classdef_constructor (void) { class_constructor = classdef; } bool is_class_constructor (const std::string& cname = std::string ()) const { - return class_constructor - ? (cname.empty () ? true : cname == dispatch_class ()) : false; + return class_constructor == legacy + ? (cname.empty () ? true : cname == dispatch_class ()) : false; + } + + bool is_classdef_constructor (const std::string& cname = std::string ()) const + { + return class_constructor == classdef + ? (cname.empty () ? true : cname == dispatch_class ()) : false; } void mark_as_class_method (void) { class_method = true; } @@ -408,6 +416,13 @@ private: + enum class_ctor_type + { + none, + legacy, + classdef + }; + // List of arguments for this function. These are local variables. tree_parameter_list *param_list; @@ -470,8 +485,8 @@ // TRUE means this is a nested function. (either a child or parent) bool nested_function; - // TRUE means this function is the constructor for class object. - bool class_constructor; + // Enum describing whether this function is the constructor for class object. + class_ctor_type class_constructor; // TRUE means this function is a method for a class. bool class_method; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov.cc --- a/libinterp/octave-value/ov.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov.cc Fri Mar 07 13:02:43 2014 -0500 @@ -65,6 +65,7 @@ #include "ov-range.h" #include "ov-struct.h" #include "ov-class.h" +#include "ov-classdef.h" #include "ov-oncleanup.h" #include "ov-cs-list.h" #include "ov-colon.h" @@ -1193,13 +1194,14 @@ { } -octave_value::octave_value (const Octave_map& m) - : rep (new octave_struct (m)) +octave_value::octave_value (const octave_map& m, const std::string& id, + const std::list& plist) + : rep (new octave_class (m, id, plist)) { maybe_mutate (); } -octave_value::octave_value (const Octave_map& m, const std::string& id, +octave_value::octave_value (const octave_scalar_map& m, const std::string& id, const std::list& plist) : rep (new octave_class (m, id, plist)) { @@ -1951,7 +1953,9 @@ int t2 = v2.type_id (); if (t1 == octave_class::static_type_id () - || t2 == octave_class::static_type_id ()) + || t2 == octave_class::static_type_id () + || t1 == octave_classdef::static_type_id () + || t2 == octave_classdef::static_type_id ()) { octave_value_typeinfo::binary_class_op_fcn f = octave_value_typeinfo::lookup_binary_class_op (op); @@ -2207,7 +2211,9 @@ int t2 = v2.type_id (); if (t1 == octave_class::static_type_id () - || t2 == octave_class::static_type_id ()) + || t2 == octave_class::static_type_id () + || t1 == octave_classdef::static_type_id () + || t2 == octave_classdef::static_type_id ()) { octave_value_typeinfo::binary_class_op_fcn f = octave_value_typeinfo::lookup_binary_class_op (op); @@ -2381,7 +2387,8 @@ int t = v.type_id (); - if (t == octave_class::static_type_id ()) + if (t == octave_class::static_type_id () + || t == octave_classdef::static_type_id ()) { octave_value_typeinfo::unary_class_op_fcn f = octave_value_typeinfo::lookup_unary_class_op (op); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave-value/ov.h --- a/libinterp/octave-value/ov.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave-value/ov.h Fri Mar 07 13:02:43 2014 -0500 @@ -46,7 +46,6 @@ class mxArray; class octave_map; class octave_scalar_map; -class Octave_map; class octave_stream; class octave_function; class octave_user_function; @@ -285,8 +284,9 @@ octave_value (const Range& r); octave_value (const octave_map& m); octave_value (const octave_scalar_map& m); - octave_value (const Octave_map& m); - octave_value (const Octave_map& m, const std::string& id, + octave_value (const octave_map& m, const std::string& id, + const std::list& plist); + octave_value (const octave_scalar_map& m, const std::string& id, const std::list& plist); octave_value (const octave_value_list& m, bool = false); octave_value (octave_value::magic_colon); @@ -1017,7 +1017,7 @@ bool print_as_scalar (void) const { return rep->print_as_scalar (); } - void print (std::ostream& os, bool pr_as_read_syntax = false) const + void print (std::ostream& os, bool pr_as_read_syntax = false) { rep->print (os, pr_as_read_syntax); } void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const diff -r de76baa76aa1 -r b83fca22bb4c libinterp/octave.cc --- a/libinterp/octave.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/octave.cc Fri Mar 07 13:02:43 2014 -0500 @@ -68,6 +68,7 @@ #include "ops.h" #include "options-usage.h" #include "ov.h" +#include "ov-classdef.h" #include "ov-range.h" #include "toplev.h" #include "parse.h" @@ -754,6 +755,8 @@ install_builtins (); + install_classdef (); + for (std::list::const_iterator it = command_line_path.begin (); it != command_line_path.end (); it++) load_path::set_command_line_path (*it); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/operators/op-b-b.cc --- a/libinterp/operators/op-b-b.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/operators/op-b-b.cc Fri Mar 07 13:02:43 2014 -0500 @@ -33,6 +33,7 @@ #include "ov-float.h" #include "ov-re-mat.h" #include "ov-typeinfo.h" +#include "ov-null-mat.h" #include "ops.h" #include "xdiv.h" #include "xpow.h" @@ -92,4 +93,8 @@ INSTALL_CATOP (octave_float_scalar, octave_bool, f_b); INSTALL_ASSIGNCONV (octave_bool, octave_bool, octave_bool_matrix); + + INSTALL_ASSIGNCONV (octave_bool, octave_null_matrix, octave_bool_matrix); + INSTALL_ASSIGNCONV (octave_bool, octave_null_str, octave_bool_matrix); + INSTALL_ASSIGNCONV (octave_bool, octave_null_sq_str, octave_bool_matrix); } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/operators/op-int.h --- a/libinterp/operators/op-int.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/operators/op-int.h Fri Mar 07 13:02:43 2014 -0500 @@ -1160,7 +1160,10 @@ #define OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS(TYPE) \ INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_matrix, TYPE ## null_assign) \ INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_str, TYPE ## null_assign) \ - INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_sq_str, TYPE ## null_assign) + INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_sq_str, TYPE ## null_assign) \ + INSTALL_ASSIGNCONV (octave_ ## TYPE ## _scalar, octave_null_matrix, octave_ ## TYPE ## _matrix) \ + INSTALL_ASSIGNCONV (octave_## TYPE ## _scalar, octave_null_str, octave_ ## TYPE ## _matrix) \ + INSTALL_ASSIGNCONV (octave_## TYPE ## _scalar, octave_null_sq_str, octave_ ## TYPE ## _matrix) #define OCTAVE_INSTALL_INT_OPS(TYPE) \ OCTAVE_INSTALL_SS_INT_OPS (TYPE) \ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/lex.h --- a/libinterp/parse-tree/lex.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/lex.h Fri Mar 07 13:02:43 2014 -0500 @@ -261,7 +261,9 @@ looking_at_matrix_or_assign_lhs (false), looking_for_object_index (false), looking_at_indirect_ref (false), parsing_class_method (false), - maybe_classdef_get_set_method (false), parsing_classdef (false), + parsing_classdef (false), maybe_classdef_get_set_method (false), + parsing_classdef_get_method (false), + parsing_classdef_set_method (false), quote_is_transpose (false), force_script (false), reading_fcn_file (false), reading_script_file (false), reading_classdef_file (false), @@ -341,13 +343,19 @@ // true means we are parsing a class method in function or classdef file. bool parsing_class_method; + // true means we are parsing a classdef file + bool parsing_classdef; + // true means we are parsing a class method declaration line in a // classdef file and can accept a property get or set method name. // for example, "get.propertyname" is recognized as a function name. bool maybe_classdef_get_set_method; - // true means we are parsing a classdef file - bool parsing_classdef; + // TRUE means we are parsing a classdef get.method. + bool parsing_classdef_get_method; + + // TRUE means we are parsing a classdef set.method. + bool parsing_classdef_set_method; // return transpose or start a string? bool quote_is_transpose; @@ -572,6 +580,8 @@ int is_keyword_token (const std::string& s); + bool fq_identifier_contains_keyword (const std::string& s); + bool whitespace_is_significant (void); void handle_number (void); @@ -590,6 +600,8 @@ int handle_meta_identifier (void); + int handle_fq_identifier (void); + int handle_identifier (void); void maybe_warn_separator_insert (char sep); @@ -675,6 +687,8 @@ int show_token (int tok); + void enable_fq_identifier (void); + protected: std::stack start_state_stack; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/lex.ll --- a/libinterp/parse-tree/lex.ll Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/lex.ll Fri Mar 07 13:02:43 2014 -0500 @@ -54,6 +54,8 @@ %x DQ_STRING_START %x SQ_STRING_START +%x FQ_IDENT_START + %{ #include @@ -254,6 +256,43 @@ } \ while (0) +#define HANDLE_IDENTIFIER(pattern, get_set) \ + do \ + { \ + curr_lexer->lexer_debug (pattern); \ + \ + int tok = curr_lexer->previous_token_value (); \ + \ + if (curr_lexer->whitespace_is_significant () \ + && curr_lexer->space_follows_previous_token () \ + && ! (tok == '[' || tok == '{' \ + || curr_lexer->previous_token_is_binop ())) \ + { \ + yyless (0); \ + unput (','); \ + } \ + else \ + { \ + if (! curr_lexer->looking_at_decl_list \ + && curr_lexer->previous_token_may_be_command ()) \ + { \ + yyless (0); \ + curr_lexer->push_start_state (COMMAND_START); \ + } \ + else \ + { \ + if (get_set) \ + curr_lexer->maybe_classdef_get_set_method = false; \ + \ + int id_tok = curr_lexer->handle_identifier (); \ + \ + if (id_tok >= 0) \ + return curr_lexer->count_token_internal (id_tok); \ + } \ + } \ + } \ + while (0) + static bool Vdisplay_tokens = false; static unsigned int Vtoken_count = 0; @@ -274,6 +313,7 @@ Im [iIjJ] CCHAR [#%] IDENT ([_$a-zA-Z][_$a-zA-Z0-9]*) +FQIDENT ({IDENT}(\.{IDENT})*) EXPON ([DdEe][+-]?{D}+) NUMBER (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+)) @@ -994,6 +1034,35 @@ } %{ +// Fully-qualified identifiers (used for classdef). +%} + +{FQIDENT} { + curr_lexer->lexer_debug ("{FQIDENT}"); + curr_lexer->pop_start_state (); + + int id_tok = curr_lexer->handle_fq_identifier (); + + if (id_tok >= 0) + { + curr_lexer->looking_for_object_index = true; + + return curr_lexer->count_token_internal (id_tok); + } + } + +{S}+ { + curr_lexer->current_input_column += yyleng; + + curr_lexer->mark_previous_token_trailing_space (); + } + +. { + yyless (0); + curr_lexer->pop_start_state (); + } + +%{ // Imaginary numbers. %} @@ -1114,46 +1183,25 @@ %{ // Identifiers. + +// Don't allow get and set to be recognized as keywords if they are +// followed by "(". %} +(set|get)/{S}*\( { + HANDLE_IDENTIFIER ("(set|get)/{S}*\\(", true); + } + {IDENT} { - curr_lexer->lexer_debug ("{IDENT}"); - - int tok = curr_lexer->previous_token_value (); - - if (curr_lexer->whitespace_is_significant () - && curr_lexer->space_follows_previous_token () - && ! (tok == '[' || tok == '{' - || curr_lexer->previous_token_is_binop ())) - { - yyless (0); - unput (','); - } - else - { - if (! curr_lexer->looking_at_decl_list - && curr_lexer->previous_token_may_be_command ()) - { - yyless (0); - curr_lexer->push_start_state (COMMAND_START); - } - else - { - int id_tok = curr_lexer->handle_identifier (); - - if (id_tok >= 0) - return curr_lexer->count_token_internal (id_tok); - } - } + HANDLE_IDENTIFIER ("{IDENT}", false); } %{ // Superclass method identifiers. %} -{IDENT}@{IDENT} | -{IDENT}@{IDENT}.{IDENT} { - curr_lexer->lexer_debug ("{IDENT}@{IDENT}|{IDENT}@{IDENT}.{IDENT}"); +{IDENT}@{FQIDENT} { + curr_lexer->lexer_debug ("{IDENT}@{FQIDENT}"); if (curr_lexer->previous_token_may_be_command ()) { @@ -1168,7 +1216,7 @@ { curr_lexer->looking_for_object_index = true; - return curr_lexer->count_token_internal (SUPERCLASSREF); + return curr_lexer->count_token_internal (id_tok); } } } @@ -1177,9 +1225,8 @@ // Metaclass query %} -\?{IDENT} | -\?{IDENT}\.{IDENT} { - curr_lexer->lexer_debug ("\\?{IDENT}|\\?{IDENT}\\.{IDENT}"); +\?{FQIDENT} { + curr_lexer->lexer_debug ("\\?{FQIDENT}"); if (curr_lexer->previous_token_may_be_command () && curr_lexer->space_follows_previous_token ()) @@ -1195,7 +1242,7 @@ { curr_lexer->looking_for_object_index = true; - return curr_lexer->count_token_internal (METAQUERY); + return curr_lexer->count_token_internal (id_tok); } } } @@ -1943,8 +1990,10 @@ looking_for_object_index = false; looking_at_indirect_ref = false; parsing_class_method = false; + parsing_classdef = false; maybe_classdef_get_set_method = false; - parsing_classdef = false; + parsing_classdef_get_method = false; + parsing_classdef_set_method = false; force_script = false; reading_fcn_file = false; reading_script_file = false; @@ -2346,20 +2395,6 @@ at_beginning_of_statement = true; break; - case static_kw: - if ((reading_fcn_file || reading_script_file - || reading_classdef_file) - && ! fcn_file_full_name.empty ()) - warning_with_id ("Octave:deprecated-keyword", - "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d of file '%s'", - input_line_number, - fcn_file_full_name.c_str ()); - else - warning_with_id ("Octave:deprecated-keyword", - "the 'static' keyword is obsolete and will be removed from a future version of Octave; please use 'persistent' instead; near line %d", - input_line_number); - // fall through ... - case persistent_kw: case global_kw: looking_at_decl_list = true; @@ -2372,10 +2407,9 @@ case end_kw: if (inside_any_object_index () - || (! reading_classdef_file - && (defining_func - && ! (looking_at_return_list - || parsed_function_name.top ())))) + || (defining_func + && ! (looking_at_return_list + || parsed_function_name.top ()))) { at_beginning_of_statement = previous_at_bos; return 0; @@ -2561,6 +2595,34 @@ } bool +octave_base_lexer::fq_identifier_contains_keyword (const std::string& s) +{ + size_t p1 = 0; + size_t p2; + + std::string s_part; + + do + { + p2 = s.find ('.', p1); + + if (p2 != std::string::npos) + { + s_part = s.substr (p1, p2 - p1); + p1 = p2 + 1; + } + else + s_part = s.substr (p1); + + if (is_keyword_token (s_part)) + return true; + } + while (p2 != std::string::npos); + + return false; +} + +bool octave_base_lexer::whitespace_is_significant (void) { return (nesting_level.is_bracket () @@ -2732,36 +2794,23 @@ int octave_base_lexer::handle_superclass_identifier (void) { - std::string pkg; - char *yytxt = flex_yytext (); - std::string meth = strip_trailing_whitespace (yytxt); + std::string meth = flex_yytext (); + size_t pos = meth.find ("@"); - std::string cls = meth.substr (pos).substr (1); - meth = meth.substr (0, pos - 1); - - pos = cls.find ("."); - if (pos != std::string::npos) - { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); - } - - int kw_token = (is_keyword_token (meth) || is_keyword_token (cls) - || is_keyword_token (pkg)); + std::string cls = meth.substr (pos + 1); + meth = meth.substr (0, pos); + + bool kw_token = (is_keyword_token (meth) + || fq_identifier_contains_keyword (cls)); + if (kw_token) { - error ("method, class and package names may not be keywords"); + error ("method, class, and package names may not be keywords"); return LEXICAL_ERROR; } - symbol_table::scope_id sid = symtab_context.curr_scope (); - - push_token (new token - (SUPERCLASSREF, - meth.empty () ? 0 : &(symbol_table::insert (meth, sid)), - cls.empty () ? 0 : &(symbol_table::insert (cls, sid)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg, sid)), - input_line_number, current_input_column)); + push_token (new token (SUPERCLASSREF, meth, cls, + input_line_number, current_input_column)); current_input_column += flex_yyleng (); @@ -2771,37 +2820,41 @@ int octave_base_lexer::handle_meta_identifier (void) { - std::string pkg; - char *yytxt = flex_yytext (); - std::string cls = strip_trailing_whitespace (yytxt).substr (1); - size_t pos = cls.find ("."); - - if (pos != std::string::npos) + std::string cls = std::string(flex_yytext ()).substr (1); + + if (fq_identifier_contains_keyword (cls)) { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); - } - - int kw_token = is_keyword_token (cls) || is_keyword_token (pkg); - if (kw_token) - { - error ("class and package names may not be keywords"); + error ("class and package names may not be keywords"); return LEXICAL_ERROR; } - symbol_table::scope_id sid = symtab_context.curr_scope (); - - push_token (new token - (METAQUERY, - cls.empty () ? 0 : &(symbol_table::insert (cls, sid)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg, sid)), - input_line_number, current_input_column)); + push_token (new token (METAQUERY, cls, input_line_number, + current_input_column)); current_input_column += flex_yyleng (); return METAQUERY; } +int +octave_base_lexer::handle_fq_identifier (void) +{ + std::string tok = flex_yytext (); + + if (fq_identifier_contains_keyword (tok)) + { + error ("function, method, class, and package names may not be keywords"); + return LEXICAL_ERROR; + } + + push_token (new token (FQ_IDENT, tok, input_line_number, + current_input_column)); + + current_input_column += flex_yyleng (); + + return FQ_IDENT; +} + // Figure out exactly what kind of token to return when we have seen // an identifier. Handles keywords. Return -1 if the identifier // should be ignored. @@ -3359,6 +3412,12 @@ return tok; } +void +octave_base_lexer::enable_fq_identifier (void) +{ + push_start_state (FQ_IDENT_START); +} + int octave_lexer::fill_flex_buffer (char *buf, unsigned max_size) { diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/module.mk --- a/libinterp/parse-tree/module.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/module.mk Fri Mar 07 13:02:43 2014 -0500 @@ -21,6 +21,7 @@ parse-tree/pt-cbinop.h \ parse-tree/pt-cell.h \ parse-tree/pt-check.h \ + parse-tree/pt-classdef.h \ parse-tree/pt-cmd.h \ parse-tree/pt-colon.h \ parse-tree/pt-const.h \ @@ -29,6 +30,7 @@ parse-tree/pt-except.h \ parse-tree/pt-exp.h \ parse-tree/pt-fcn-handle.h \ + parse-tree/pt-funcall.h \ parse-tree/pt-id.h \ parse-tree/pt-idx.h \ parse-tree/pt-jump.h \ @@ -52,6 +54,7 @@ parse-tree/pt-cbinop.cc \ parse-tree/pt-cell.cc \ parse-tree/pt-check.cc \ + parse-tree/pt-classdef.cc \ parse-tree/pt-cmd.cc \ parse-tree/pt-colon.cc \ parse-tree/pt-const.cc \ @@ -60,6 +63,7 @@ parse-tree/pt-except.cc \ parse-tree/pt-exp.cc \ parse-tree/pt-fcn-handle.cc \ + parse-tree/pt-funcall.cc \ parse-tree/pt-id.cc \ parse-tree/pt-idx.cc \ parse-tree/pt-jump.cc \ diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/oct-parse.in.yy --- a/libinterp/parse-tree/oct-parse.in.yy Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/oct-parse.in.yy Fri Mar 07 13:02:43 2014 -0500 @@ -62,6 +62,7 @@ #include "load-path.h" #include "oct-hist.h" #include "oct-map.h" +#include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "ov-null-mat.h" @@ -70,6 +71,7 @@ #include "parse.h" #include "pt-all.h" #include "pt-eval.h" +#include "pt-funcall.h" #include "symtab.h" #include "token.h" #include "unwind-prot.h" @@ -164,6 +166,8 @@ tree_expression *tree_expression_type; tree_constant *tree_constant_type; tree_fcn_handle *tree_fcn_handle_type; + tree_funcall *tree_funcall_type; + tree_function_def *tree_function_def_type; tree_anon_fcn_handle *tree_anon_fcn_handle_type; tree_identifier *tree_identifier_type; tree_index_expression *tree_index_expression_type; @@ -183,7 +187,24 @@ tree_statement *tree_statement_type; tree_statement_list *tree_statement_list_type; octave_user_function *octave_user_function_type; - void *dummy_type; + + tree_classdef *tree_classdef_type; + tree_classdef_attribute* tree_classdef_attribute_type; + tree_classdef_attribute_list* tree_classdef_attribute_list_type; + tree_classdef_superclass* tree_classdef_superclass_type; + tree_classdef_superclass_list* tree_classdef_superclass_list_type; + tree_classdef_body* tree_classdef_body_type; + tree_classdef_property* tree_classdef_property_type; + tree_classdef_property_list* tree_classdef_property_list_type; + tree_classdef_properties_block* tree_classdef_properties_block_type; + tree_classdef_methods_list* tree_classdef_methods_list_type; + tree_classdef_methods_block* tree_classdef_methods_block_type; + tree_classdef_event* tree_classdef_event_type; + tree_classdef_events_list* tree_classdef_events_list_type; + tree_classdef_events_block* tree_classdef_events_block_type; + tree_classdef_enum* tree_classdef_enum_type; + tree_classdef_enum_list* tree_classdef_enum_list_type; + tree_classdef_enum_block* tree_classdef_enum_block_type; } // Tokens with line and column information. @@ -210,21 +231,22 @@ %token TRY CATCH %token GLOBAL PERSISTENT %token FCN_HANDLE +%token CLASSDEF %token PROPERTIES METHODS EVENTS ENUMERATION %token METAQUERY %token SUPERCLASSREF +%token FQ_IDENT %token GET SET %token FCN // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token INPUT_FILE CLASSDEF +%token INPUT_FILE // %token VARARGIN VARARGOUT // Nonterminals we construct. -%type function_beg -%type stash_comment classdef_beg -%type properties_beg methods_beg events_beg enum_beg +%type stash_comment +%type function_beg classdef_beg %type sep_no_nl opt_sep_no_nl nl opt_nl sep opt_sep %type input %type string constant magic_colon @@ -236,18 +258,19 @@ %type primary_expr oper_expr power_expr %type simple_expr colon_expr assign_expr expression %type identifier fcn_name magic_tilde -%type superclass_identifier meta_identifier -%type function1 function2 classdef1 +%type superclass_identifier meta_identifier +%type function1 function2 %type word_list_cmd %type colon_expr1 %type arg_list word_list assign_lhs %type cell_or_matrix_row %type param_list param_list1 param_list2 %type return_list return_list1 -%type superclasses opt_superclasses %type command select_command loop_command -%type jump_command except_command function -%type file classdef +%type jump_command except_command +%type function +%type classdef +%type file %type if_command %type elseif_clause else_clause %type if_cmd_list1 if_cmd_list @@ -257,25 +280,27 @@ %type decl2 param_list_elt %type decl1 %type declaration -%type statement function_end classdef_end +%type statement function_end %type simple_list simple_list1 list list1 %type opt_list -// These types need to be specified. -%type attr -%type class_event -%type class_enum -%type class_property -%type properties_list -%type properties_block -%type methods_list -%type methods_block -%type opt_attr_list -%type attr_list -%type events_list -%type events_block -%type enum_list -%type enum_block -%type class_body +%type attr +%type attr_list opt_attr_list +%type superclass +%type superclass_list opt_superclass_list +%type class_body +%type class_property +%type property_list +%type properties_block +%type methods_list +%type methods_block +%type class_event +%type events_list +%type events_block +%type class_enum +%type enum_list +%type enum_block +%type method_decl method +%type method_decl1 // Precedence and associativity. %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ @@ -312,6 +337,8 @@ %destructor { delete $$; } %destructor { delete $$; } %destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } %destructor { delete $$; } %destructor { delete $$; } %destructor { delete $$; } @@ -332,6 +359,24 @@ %destructor { delete $$; } %destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } +%destructor { delete $$; } + %destructor { warning_with_id ("Octave:parser-destructor", @@ -439,11 +484,23 @@ superclass_identifier : SUPERCLASSREF - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string method_nm = $1->superclass_method_name (); + std::string class_nm = $1->superclass_class_name (); + + $$ = parser.make_superclass_ref + (method_nm, class_nm, + $1->line (), $1->column ()); + } ; meta_identifier : METAQUERY - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string class_nm = $1->text (); + + $$ = parser.make_meta_class_query (class_nm, $1->line (), + $1->column ()); + } ; string : DQ_STRING @@ -867,8 +924,6 @@ { $$ = $1; } | file { $$ = $1; } - | classdef - { $$ = $1; } ; // ===================== @@ -1294,6 +1349,13 @@ $$ = 0; } + | INPUT_FILE opt_nl classdef opt_sep END_OF_INPUT + { + if (lexer.reading_classdef_file) + parser.classdef_object = $3; + + $$ = 0; + } ; // =================== @@ -1336,12 +1398,14 @@ { lexer.parsed_function_name.top () = true; lexer.maybe_classdef_get_set_method = false; + lexer.parsing_classdef_get_method = true; $$ = $3; } | SET '.' identifier { lexer.parsed_function_name.top () = true; lexer.maybe_classdef_get_set_method = false; + lexer.parsing_classdef_set_method = true; $$ = $3; } ; @@ -1352,6 +1416,14 @@ delete $1; + if (lexer.parsing_classdef_get_method) + fname.insert (0, "get."); + else if (lexer.parsing_classdef_set_method) + fname.insert (0, "set."); + + lexer.parsing_classdef_get_method = false; + lexer.parsing_classdef_set_method = false; + $$ = parser.frob_function (fname, $2); } ; @@ -1411,158 +1483,299 @@ // Classdef // ======== -classdef_beg : CLASSDEF stash_comment +classdef_beg : CLASSDEF { - $$ = 0; + if (! lexer.reading_classdef_file) + { + parser.bison_error ("classdef must appear inside a file containing only a class definition"); + YYABORT; + } + lexer.parsing_classdef = true; + $$ = $1; } ; -classdef_end : END +classdef : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END { lexer.parsing_classdef = false; - if (parser.end_token_ok ($1, token::classdef_end)) - $$ = parser.make_end ("endclassdef", false, - $1->line (), $1->column ()); - else - ABORT_PARSE; + if (! ($$ = parser.make_classdef ($1, $3, $4, $5, $7, $9, $2))) + { + // make_classdef deleted $3, $4, $5, and $7. + ABORT_PARSE; + } } - ; - -classdef1 : classdef_beg opt_attr_list identifier opt_superclasses - { $$ = 0; } - ; - -classdef : classdef1 opt_sep class_body opt_sep stash_comment classdef_end - { $$ = 0; } + | classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep END + { + lexer.parsing_classdef = false; + + if (! ($$ = parser.make_classdef ($1, $3, $4, $5, 0, $7, $2))) + { + // make_classdef deleted $3, $4, and $5. + ABORT_PARSE; + } + } ; opt_attr_list : // empty { $$ = 0; } | '(' attr_list ')' - { $$ = 0; } + { $$ = $2; } ; attr_list : attr - { $$ = 0; } + { $$ = new tree_classdef_attribute_list ($1); } | attr_list ',' attr - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; attr : identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($1); } | identifier '=' decl_param_init expression - { $$ = 0; } + { + lexer.looking_at_initializer_expression = false; + $$ = new tree_classdef_attribute ($1, $4); + } | EXPR_NOT identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($2, false); } ; -opt_superclasses +opt_superclass_list : // empty { $$ = 0; } - | superclasses - { $$ = 0; } + | superclass_list + { $$ = $1; } ; -superclasses : EXPR_LT identifier '.' identifier - { $$ = 0; } - | EXPR_LT identifier - { $$ = 0; } - | superclasses EXPR_AND identifier '.' identifier - { $$ = 0; } - | superclasses EXPR_AND identifier - { $$ = 0; } +superclass_list : EXPR_LT + { lexer.enable_fq_identifier (); } + superclass + { $$ = new tree_classdef_superclass_list ($3); } + | superclass_list EXPR_AND + { lexer.enable_fq_identifier (); } + superclass + { + $1->append ($4); + $$ = $1; + } + ; + +superclass : FQ_IDENT + { $$ = new tree_classdef_superclass ($1->text ()); } ; class_body : properties_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | methods_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | events_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | enum_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | class_body opt_sep properties_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep methods_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep events_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep enum_block - { $$ = 0; } - ; - -properties_beg : PROPERTIES stash_comment - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; properties_block - : properties_beg opt_attr_list opt_sep properties_list opt_sep END - { $$ = 0; } + : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END + { + if (! ($$ = parser.make_classdef_properties_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_properties_block delete $3 and $5. + ABORT_PARSE; + } + } + | PROPERTIES stash_comment opt_attr_list opt_sep END + { + if (! ($$ = parser.make_classdef_properties_block + ($1, $3, 0, $5, $2))) + { + // make_classdef_properties_block delete $3. + ABORT_PARSE; + } + } ; -properties_list +property_list : class_property - { $$ = 0; } - | properties_list opt_sep class_property - { $$ = 0; } + { $$ = new tree_classdef_property_list ($1); } + | property_list opt_sep class_property + { + $1->append ($3); + $$ = $1; + } ; class_property : identifier - { $$ = 0; } + { $$ = new tree_classdef_property ($1); } | identifier '=' decl_param_init expression ';' - { $$ = 0; } + { + lexer.looking_at_initializer_expression = false; + $$ = new tree_classdef_property ($1, $4); + } ; -methods_beg : METHODS stash_comment - { $$ = 0; } +methods_block : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END + { + if (! ($$ = parser.make_classdef_methods_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_methods_block deleted $3 and $5. + ABORT_PARSE; + } + } + | METHODS stash_comment opt_attr_list opt_sep END + { + if (! ($$ = parser.make_classdef_methods_block + ($1, $3, 0, $5, $2))) + { + // make_classdef_methods_block deleted $3. + ABORT_PARSE; + } + } ; - -methods_block : methods_beg opt_attr_list opt_sep methods_list opt_sep END - { $$ = 0; } + ; + +method_decl1 : identifier + { + if (! ($$ = parser.start_classdef_external_method ($1, 0))) + ABORT_PARSE; + } + | identifier param_list + { + if (! ($$ = parser.start_classdef_external_method ($1, $2))) + ABORT_PARSE; + } ; -methods_list : function - { $$ = 0; } - | methods_list opt_sep function - { $$ = 0; } +method_decl : stash_comment method_decl1 + { $$ = parser.finish_classdef_external_method ($2, 0, $1); } + | stash_comment return_list '=' + { + lexer.defining_func++; + lexer.parsed_function_name.push (false); + } + method_decl1 + { + lexer.defining_func--; + lexer.parsed_function_name.pop (); + $$ = parser.finish_classdef_external_method ($5, $2, $1); + } + ; + +method : method_decl + { $$ = $1; } + | function + { $$ = $1; } ; -events_beg : EVENTS stash_comment - { $$ = 0; } +methods_list : method + { + octave_value fcn; + if ($1) + fcn = $1->function (); + delete $1; + $$ = new tree_classdef_methods_list (fcn); + } + | methods_list opt_sep method + { + octave_value fcn; + if ($3) + fcn = $3->function (); + delete $3; + + $1->append (fcn); + $$ = $1; + } ; -events_block : events_beg opt_attr_list opt_sep events_list opt_sep END - { $$ = 0; } +events_block : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END + { + if (! ($$ = parser.make_classdef_events_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_events_block deleted $3 and $5. + ABORT_PARSE; + } + } + | EVENTS stash_comment opt_attr_list opt_sep END + { + if (! ($$ = parser.make_classdef_events_block + ($1, $3, 0, $5, $2))) + { + // make_classdef_events_block deleted $3. + ABORT_PARSE; + } + } ; events_list : class_event - { $$ = 0; } + { $$ = new tree_classdef_events_list ($1); } | events_list opt_sep class_event - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_event : identifier - { $$ = 0; } + { $$ = new tree_classdef_event ($1); } ; -enum_beg : ENUMERATION stash_comment - { $$ = 0; } - ; - -enum_block : enum_beg opt_attr_list opt_sep enum_list opt_sep END - { $$ = 0; } +enum_block : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END + { + if (! ($$ = parser.make_classdef_enum_block + ($1, $3, $5, $7, $2))) + { + // make_classdef_enum_block deleted $3 and $5. + ABORT_PARSE; + } + } + | ENUMERATION stash_comment opt_attr_list opt_sep END + { + if (! ($$ = parser.make_classdef_enum_block + ($1, $3, 0, $5, $2))) + { + // make_classdef_enum_block deleted $3. + ABORT_PARSE; + } + } ; enum_list : class_enum - { $$ = 0; } + { $$ = new tree_classdef_enum_list ($1); } | enum_list opt_sep class_enum - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_enum : identifier '(' expression ')' - { $$ = 0; } + { $$ = new tree_classdef_enum ($1, $3); } ; // ============= @@ -1660,6 +1873,7 @@ curr_fcn_depth = 0; primary_fcn_scope = -1; curr_class_name = ""; + curr_package_name = ""; function_scopes.clear (); primary_fcn_ptr = 0; subfunction_names.clear (); @@ -1831,95 +2045,6 @@ } } -static tree_expression * -fold (tree_binary_expression *e) -{ - tree_expression *retval = e; - - unwind_protect frame; - - frame.protect_var (error_state); - frame.protect_var (warning_state); - - frame.protect_var (discard_error_messages); - frame.protect_var (discard_warning_messages); - - discard_error_messages = true; - discard_warning_messages = true; - - tree_expression *op1 = e->lhs (); - tree_expression *op2 = e->rhs (); - - if (op1->is_constant () && op2->is_constant ()) - { - octave_value tmp = e->rvalue1 (); - - if (! (error_state || warning_state)) - { - tree_constant *tc_retval - = new tree_constant (tmp, op1->line (), op1->column ()); - - std::ostringstream buf; - - tree_print_code tpc (buf); - - e->accept (tpc); - - tc_retval->stash_original_text (buf.str ()); - - delete e; - - retval = tc_retval; - } - } - - return retval; -} - -static tree_expression * -fold (tree_unary_expression *e) -{ - tree_expression *retval = e; - - unwind_protect frame; - - frame.protect_var (error_state); - frame.protect_var (warning_state); - - frame.protect_var (discard_error_messages); - frame.protect_var (discard_warning_messages); - - discard_error_messages = true; - discard_warning_messages = true; - - tree_expression *op = e->operand (); - - if (op->is_constant ()) - { - octave_value tmp = e->rvalue1 (); - - if (! (error_state || warning_state)) - { - tree_constant *tc_retval - = new tree_constant (tmp, op->line (), op->column ()); - - std::ostringstream buf; - - tree_print_code tpc (buf); - - e->accept (tpc); - - tc_retval->stash_original_text (buf.str ()); - - delete e; - - retval = tc_retval; - } - } - - return retval; -} - // Finish building a range. tree_expression * @@ -1975,8 +2100,6 @@ e->preserve_base (); delete e; - // FIXME -- need to attempt constant folding here - // too (we need a generic way to do that). retval = base; } } @@ -2189,10 +2312,7 @@ int l = tok_val->line (); int c = tok_val->column (); - tree_binary_expression *e - = maybe_compound_binary_expression (op1, op2, l, c, t); - - return fold (e); + return maybe_compound_binary_expression (op1, op2, l, c, t); } // Build a boolean expression. @@ -2221,10 +2341,7 @@ int l = tok_val->line (); int c = tok_val->column (); - tree_boolean_expression *e - = new tree_boolean_expression (op1, op2, l, c, t); - - return fold (e); + return new tree_boolean_expression (op1, op2, l, c, t); } // Build a prefix expression. @@ -2265,10 +2382,7 @@ int l = tok_val->line (); int c = tok_val->column (); - tree_prefix_expression *e - = new tree_prefix_expression (op1, l, c, t); - - return fold (e); + return new tree_prefix_expression (op1, l, c, t); } // Build a postfix expression. @@ -2305,10 +2419,7 @@ int l = tok_val->line (); int c = tok_val->column (); - tree_postfix_expression *e - = new tree_postfix_expression (op1, l, c, t); - - return fold (e); + return new tree_postfix_expression (op1, l, c, t); } // Build an unwind-protect command. @@ -3002,6 +3113,274 @@ lexer.looking_at_parameter_list = false; } +tree_funcall * +octave_base_parser::make_superclass_ref (const std::string& method_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(1) = class_nm; + args(0) = method_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__superclass_reference__"); + + return new tree_funcall (fcn, args); +} + +tree_funcall * +octave_base_parser::make_meta_class_query (const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(0) = class_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__meta_class_query__"); + + return new tree_funcall (fcn, args); +} + +// A CLASSDEF block defines a class that has a constructor and other +// methods, but it is not an executable command. Parsing the block +// makes some changes in the symbol table (inserting the constructor +// and methods, and adding to the list of known objects) and creates +// a parse tree containing meta information about the class. + +tree_classdef * +octave_base_parser::make_classdef (token *tok_val, + tree_classdef_attribute_list *a, + tree_identifier *id, + tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc) +{ + tree_classdef *retval = 0; + + std::string cls_name = id->name (); + + std::string nm = lexer.fcn_file_name; + + size_t pos = nm.find_last_of (file_ops::dir_sep_chars ()); + + if (pos != std::string::npos) + nm = lexer.fcn_file_name.substr (pos+1); + + if (nm != cls_name) + bison_error ("invalid classdef definition, the class name must match the file name"); + else if (end_token_ok (end_tok, token::classdef_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! body) + body = new tree_classdef_body (); + + retval = new tree_classdef (a, id, sc, body, lc, tc, + curr_package_name, l, c); + } + + if (! retval) + { + delete a; + delete id; + delete sc; + delete body; + } + + return retval; +} + +tree_classdef_properties_block * +octave_base_parser::make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_properties_block *retval = 0; + + if (end_token_ok (end_tok, token::properties_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! plist) + plist = new tree_classdef_property_list (); + + retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); + } + else + { + delete a; + delete plist; + } + + return retval; +} + +tree_classdef_methods_block * +octave_base_parser::make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_methods_block *retval = 0; + + if (end_token_ok (end_tok, token::methods_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! mlist) + mlist = new tree_classdef_methods_list (); + + retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); + } + else + { + delete a; + delete mlist; + } + + return retval; +} + +tree_classdef_events_block * +octave_base_parser::make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_events_block *retval = 0; + + if (end_token_ok (end_tok, token::events_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! elist) + elist = new tree_classdef_events_list (); + + retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + } + + return retval; +} + +tree_classdef_enum_block * +octave_base_parser::make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, + octave_comment_list *lc) +{ + tree_classdef_enum_block *retval = 0; + + if (end_token_ok (end_tok, token::enumeration_end)) + { + octave_comment_list *tc = lexer.comment_buf.get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + if (! elist) + elist = new tree_classdef_enum_list (); + + retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); + } + else + { + delete a; + delete elist; + } + + return retval; +} + +octave_user_function* +octave_base_parser::start_classdef_external_method (tree_identifier *id, + tree_parameter_list *pl) +{ + octave_user_function* retval = 0; + + // External methods are only allowed within @-folders. In this case, + // curr_class_name will be non-empty. + + if (! curr_class_name.empty ()) + { + + std::string mname = id->name (); + + // Methods that cannot be declared outside the classdef file: + // - methods with '.' character (e.g. property accessors) + // - class constructor + // - `delete' + + if (mname.find_first_of (".") == std::string::npos + && mname != "delete" + && mname != curr_class_name) + { + // Create a dummy function that is used until the real method + // is loaded. + + retval = new octave_user_function (-1, pl); + + retval->stash_function_name (mname); + + int l = id->line (); + int c = id->column (); + + retval->stash_fcn_location (l, c); + } + else + bison_error ("invalid external method declaration, an external " + "method cannot be the class constructor, `delete' " + "or have a dot (.) character in its name"); + } + else + bison_error ("external methods are only allowed in @-folders"); + + if (! retval) + delete id; + + return retval; +} + +tree_function_def * +octave_base_parser::finish_classdef_external_method (octave_user_function *fcn, + tree_parameter_list *ret_list, + octave_comment_list *cl) +{ + if (ret_list) + fcn->define_ret_list (ret_list); + + if (cl) + fcn->stash_leading_comment (cl); + + int l = fcn->beginning_line (); + int c = fcn->beginning_column (); + + return new tree_function_def (fcn, l, c); +} + // Make an index expression. tree_index_expression * @@ -3024,7 +3403,8 @@ int l = expr->line (); int c = expr->column (); - expr->mark_postfix_indexed (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index (type); if (expr->is_index_expression ()) { @@ -3051,6 +3431,9 @@ int l = expr->line (); int c = expr->column (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + if (expr->is_index_expression ()) { tree_index_expression *tmp = static_cast (expr); @@ -3070,13 +3453,17 @@ // Make an indirect reference expression with dynamic field name. tree_index_expression * -octave_base_parser::make_indirect_ref (tree_expression *expr, tree_expression *elt) +octave_base_parser::make_indirect_ref (tree_expression *expr, + tree_expression *elt) { tree_index_expression *retval = 0; int l = expr->line (); int c = expr->column (); + if (! expr->is_postfix_indexed ()) + expr->set_postfix_index ('.'); + if (expr->is_index_expression ()) { tree_index_expression *tmp = static_cast (expr); @@ -3464,6 +3851,7 @@ static octave_function * parse_fcn_file (const std::string& full_file, const std::string& file, const std::string& dispatch_type, + const std::string& package_name, bool require_file, bool force_script, bool autoload, bool relative_lookup, const std::string& warn_for) { @@ -3497,6 +3885,7 @@ octave_parser parser (ffile); parser.curr_class_name = dispatch_type; + parser.curr_package_name = package_name; parser.autoloading = autoload; parser.fcn_file_from_relative_lookup = relative_lookup; @@ -3511,20 +3900,37 @@ fcn_ptr = parser.primary_fcn_ptr; - if (fcn_ptr) + if (status == 0) { - fcn_ptr->maybe_relocate_end (); - - if (parser.parsing_subfunctions) + if (parser.lexer.reading_classdef_file + && parser.classdef_object) { - if (! parser.endfunction_found) - parser.subfunction_names.reverse (); - - fcn_ptr->stash_subfunction_names (parser.subfunction_names); + // Convert parse tree for classdef object to + // meta.class info (and stash it in the symbol + // table?). Return pointer to constructor? + + if (fcn_ptr) + panic_impossible (); + + bool is_at_folder = ! dispatch_type.empty (); + + fcn_ptr = + parser.classdef_object->make_meta_class (is_at_folder); + } + else if (fcn_ptr) + { + fcn_ptr->maybe_relocate_end (); + + if (parser.parsing_subfunctions) + { + if (! parser.endfunction_found) + parser.subfunction_names.reverse (); + + fcn_ptr->stash_subfunction_names (parser.subfunction_names); + } } } - - if (status != 0) + else error ("parse error while reading file %s", full_file.c_str ()); } else if (require_file) @@ -3565,7 +3971,8 @@ symbol_found = true; octave_function *fcn - = parse_fcn_file (full_file, file, "", true, false, false, false, ""); + = parse_fcn_file (full_file, file, "", "", true, false, false, false, + ""); if (fcn) { @@ -3629,6 +4036,7 @@ octave_function * load_fcn_from_file (const std::string& file_name, const std::string& dir_name, const std::string& dispatch_type, + const std::string& package_name, const std::string& fcn_name, bool autoload) { octave_function *retval = 0; @@ -3676,7 +4084,8 @@ // to get the help-string to use. octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2), - nm, dispatch_type, false, + nm, dispatch_type, + package_name, false, autoload, autoload, relative_lookup, ""); @@ -3688,13 +4097,14 @@ } else if (len > 2) { - retval = parse_fcn_file (file, nm, dispatch_type, true, autoload, - autoload, relative_lookup, ""); + retval = parse_fcn_file (file, nm, dispatch_type, package_name, true, + autoload, autoload, relative_lookup, ""); } if (retval) { retval->stash_dir_name (dir_name); + retval->stash_package_name (package_name); if (retval->is_user_function ()) { @@ -3904,7 +4314,7 @@ if (! error_state) { octave_function *fcn = parse_fcn_file (file_full_name, file_name, - "", require_file, true, + "", "", require_file, true, false, false, warn_for); if (! error_state) @@ -4635,7 +5045,7 @@ if (nargin == 2) octave_stdout << "parsing " << full_file << std::endl; - octave_function *fcn = parse_fcn_file (full_file, file, "", + octave_function *fcn = parse_fcn_file (full_file, file, "", "", true, false, false, false, "__parse_file__"); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/octave.gperf --- a/libinterp/parse-tree/octave.gperf Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/octave.gperf Fri Mar 07 13:02:43 2014 -0500 @@ -64,7 +64,6 @@ properties_kw, return_kw, set_kw, - static_kw, switch_kw, try_kw, until_kw, @@ -111,7 +110,6 @@ properties, PROPERTIES, properties_kw return, FUNC_RET, return_kw set, SET, set_kw -static, PERSISTENT, static_kw switch, SWITCH, switch_kw try, TRY, try_kw until, UNTIL, until_kw diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/parse.h --- a/libinterp/parse-tree/parse.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/parse.h Fri Mar 07 13:02:43 2014 -0500 @@ -43,6 +43,18 @@ class tree_argument_list; class tree_array_list; class tree_cell; +class tree_classdef; +class tree_classdef_attribute_list; +class tree_classdef_body; +class tree_classdef_enum_block; +class tree_classdef_enum_list; +class tree_classdef_events_block; +class tree_classdef_events_list; +class tree_classdef_methods_block; +class tree_classdef_methods_list; +class tree_classdef_properties_block; +class tree_classdef_property_list; +class tree_classdef_superclass_list; class tree_colon_expression; class tree_command; class tree_constant; @@ -50,6 +62,7 @@ class tree_decl_init_list; class tree_expression; class tree_fcn_handle; +class tree_funcall; class tree_function_def; class tree_identifier; class tree_if_clause; @@ -92,6 +105,7 @@ load_fcn_from_file (const std::string& file_name, const std::string& dir_name = std::string (), const std::string& dispatch_type = std::string (), + const std::string& package_name = std::string (), const std::string& fcn_name = std::string (), bool autoload = false); @@ -136,9 +150,9 @@ autoloading (false), fcn_file_from_relative_lookup (false), parsing_subfunctions (false), max_fcn_depth (0), curr_fcn_depth (0), primary_fcn_scope (-1), - curr_class_name (), function_scopes (), primary_fcn_ptr (0), - subfunction_names (), stmt_list (0), - lexer (lxr) + curr_class_name (), curr_package_name (), function_scopes (), + primary_fcn_ptr (0), subfunction_names (), classdef_object (0), + stmt_list (0), lexer (lxr) { } ~octave_base_parser (void); @@ -284,6 +298,54 @@ void recover_from_parsing_function (void); + tree_funcall * + make_superclass_ref (const std::string& method_nm, + const std::string& class_nm, + int l, int c); + + tree_funcall * + make_meta_class_query (const std::string& class_nm, + int l, int c); + + tree_classdef * + make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc); + + tree_classdef_properties_block * + make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_methods_block * + make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_events_block * + make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc); + + tree_classdef_enum_block * + make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, octave_comment_list *lc); + + octave_user_function * + start_classdef_external_method (tree_identifier *id, + tree_parameter_list *pl); + + tree_function_def * + finish_classdef_external_method (octave_user_function *fcn, + tree_parameter_list *ret_list, + octave_comment_list *cl); + // Make an index expression. tree_index_expression * make_index_expression (tree_expression *expr, @@ -372,6 +434,10 @@ // constructors. std::string curr_class_name; + // Name of the current package when we are parsing an element contained + // in a package directory (+-directory). + std::string curr_package_name; + // A stack holding the nested function scopes being parsed. // We don't use std::stack, because we want the clear method. Also, we // must access one from the top @@ -385,6 +451,9 @@ // file. Eventually stashed in the primary function object. std::list subfunction_names; + // Pointer to the classdef object we just parsed, if any. + tree_classdef *classdef_object; + // Result of parsing input. tree_statement_list *stmt_list; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-all.h --- a/libinterp/parse-tree/pt-all.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-all.h Fri Mar 07 13:02:43 2014 -0500 @@ -30,6 +30,7 @@ #include "pt-binop.h" #include "pt-cbinop.h" #include "pt-check.h" +#include "pt-classdef.h" #include "pt-cmd.h" #include "pt-colon.h" #include "pt-const.h" @@ -37,6 +38,7 @@ #include "pt-except.h" #include "pt-exp.h" #include "pt-fcn-handle.h" +#include "pt-funcall.h" #include "pt-id.h" #include "pt-idx.h" #include "pt-jump.h" diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-bp.cc --- a/libinterp/parse-tree/pt-bp.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-bp.cc Fri Mar 07 13:02:43 2014 -0500 @@ -293,6 +293,12 @@ } void +tree_breakpoint::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_breakpoint::visit_parameter_list (tree_parameter_list&) { panic_impossible (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-bp.h --- a/libinterp/parse-tree/pt-bp.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-bp.h Fri Mar 07 13:02:43 2014 -0500 @@ -106,6 +106,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-cbinop.cc --- a/libinterp/parse-tree/pt-cbinop.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-cbinop.cc Fri Mar 07 13:02:43 2014 -0500 @@ -162,7 +162,8 @@ maybe_compound_binary_expression (tree_expression *a, tree_expression *b, int l, int c, octave_value::binary_op t) { - tree_expression *ca = a, *cb = b; + tree_expression *ca = a; + tree_expression *cb = b; octave_value::compound_binary_op ct; switch (t) diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-check.cc --- a/libinterp/parse-tree/pt-check.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-check.cc Fri Mar 07 13:02:43 2014 -0500 @@ -357,6 +357,11 @@ } void +tree_checker::visit_funcall (tree_funcall& /* fc */) +{ +} + +void tree_checker::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-check.h --- a/libinterp/parse-tree/pt-check.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-check.h Fri Mar 07 13:02:43 2014 -0500 @@ -91,6 +91,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-classdef.cc Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,259 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-classdef.h" +#include "pt-classdef.h" + +// Classdef attribute + +void +tree_classdef_attribute::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute (*this); +} + +// Classdef attribute_list + +tree_classdef_attribute_list::~tree_classdef_attribute_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_attribute_list::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute_list (*this); +} + +// Classdef superclass + +void +tree_classdef_superclass::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass (*this); +} + +// Classdef superclass_list + +tree_classdef_superclass_list::~tree_classdef_superclass_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_superclass_list::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass_list (*this); +} + +// Classdef property + +void +tree_classdef_property::accept (tree_walker& tw) +{ + tw.visit_classdef_property (*this); +} + +// Classdef property_list + +tree_classdef_property_list::~tree_classdef_property_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_property_list::accept (tree_walker& tw) +{ + tw.visit_classdef_property_list (*this); +} + +// Classdef properties_block + +void +tree_classdef_properties_block::accept (tree_walker& tw) +{ + tw.visit_classdef_properties_block (*this); +} + +// Classdef methods_list + +void +tree_classdef_methods_list::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_list (*this); +} + +// Classdef methods_block + +void +tree_classdef_methods_block::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_block (*this); +} + +// Classdef event + +void +tree_classdef_event::accept (tree_walker& tw) +{ + tw.visit_classdef_event (*this); +} + +// Classdef events_list + +tree_classdef_events_list::~tree_classdef_events_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_events_list::accept (tree_walker& tw) +{ + tw.visit_classdef_events_list (*this); +} + +// Classdef events_block + +void +tree_classdef_events_block::accept (tree_walker& tw) +{ + tw.visit_classdef_events_block (*this); +} + +// Classdef enum + +void +tree_classdef_enum::accept (tree_walker& tw) +{ + tw.visit_classdef_enum (*this); +} + +// Classdef enum_list + +tree_classdef_enum_list::~tree_classdef_enum_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_enum_list::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_list (*this); +} + +// Classdef enum_block + +void +tree_classdef_enum_block::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_block (*this); +} + +// Classdef body + +tree_classdef_body::~tree_classdef_body (void) +{ + while (! properties_lst.empty ()) + { + properties_list_iterator p = properties_lst.begin (); + delete *p; + properties_lst.erase (p); + } + + while (! methods_lst.empty ()) + { + methods_list_iterator p = methods_lst.begin (); + delete *p; + methods_lst.erase (p); + } + + while (! events_lst.empty ()) + { + events_list_iterator p = events_lst.begin (); + delete *p; + events_lst.erase (p); + } + + while (! enum_lst.empty ()) + { + enum_list_iterator p = enum_lst.begin (); + delete *p; + enum_lst.erase (p); + } +} + +// Classdef + +octave_function* +tree_classdef::make_meta_class (bool is_at_folder) +{ + octave_value retval; + cdef_class cls = cdef_class::make_meta_class (this, is_at_folder); + + if (cls.ok ()) + return cls.get_constructor_function (); + + return 0; +} + +tree_classdef * +tree_classdef::dup (symbol_table::scope_id, + symbol_table::context_id) const +{ + // FIXME + return 0; +} + +void +tree_classdef::accept (tree_walker& tw) +{ + tw.visit_classdef (*this); +} diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-classdef.h Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,653 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_tree_classdef_h) +#define octave_tree_classdef_h 1 + +class octave_value; + +class tree_walker; + +#include "pt-cmd.h" +#include "pt-exp.h" +#include "pt-id.h" + +#include "base-list.h" + +#include + +class tree_classdef_attribute +{ +public: + + tree_classdef_attribute (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e), neg (false) { } + + tree_classdef_attribute (tree_identifier *i, bool b) + : id (i), expr (0), neg (b) { } + + ~tree_classdef_attribute (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + bool negate (void) { return neg; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + bool neg; + + // No copying! + + tree_classdef_attribute (const tree_classdef_attribute&); + + tree_classdef_attribute& operator = (const tree_classdef_attribute&); +}; + +class tree_classdef_attribute_list : public octave_base_list +{ +public: + + tree_classdef_attribute_list (void) { } + + tree_classdef_attribute_list (tree_classdef_attribute *a) { append (a); } + + tree_classdef_attribute_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_attribute_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_attribute_list (const tree_classdef_attribute_list&); + + tree_classdef_attribute_list& operator = (const tree_classdef_attribute_list&); +}; + +class tree_classdef_superclass +{ +public: + + tree_classdef_superclass (const std::string& cname) + : cls_name (cname) { } + + ~tree_classdef_superclass (void) { } + + std::string class_name (void) { return cls_name; } + + void accept (tree_walker&); + +private: + + std::string cls_name; + + // No copying! + + tree_classdef_superclass (const tree_classdef_superclass&); + + tree_classdef_superclass& operator = (const tree_classdef_superclass&); +}; + +class tree_classdef_superclass_list : public octave_base_list +{ +public: + + tree_classdef_superclass_list (void) { } + + tree_classdef_superclass_list (tree_classdef_superclass *sc) { append (sc); } + + tree_classdef_superclass_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_superclass_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_superclass_list (const tree_classdef_superclass_list&); + + tree_classdef_superclass_list& operator = (const tree_classdef_superclass_list&); +}; + +template +class tree_classdef_element : public tree +{ +public: + + tree_classdef_element (tree_classdef_attribute_list *a, + octave_base_list *elist, + octave_comment_list *lc, octave_comment_list *tc, + int l = -1, int c = -1) + : tree (l, c), attr_list (a), elt_list (elist), + lead_comm (lc), trail_comm (tc) + { } + + ~tree_classdef_element (void) + { + delete attr_list; + delete elt_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + octave_base_list *element_list (void) { return elt_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + + octave_comment_list *trailing_comment (void) { return trail_comm; } + + void accept (tree_walker&) { } + +private: + + // List of attributes that apply to this class. + tree_classdef_attribute_list *attr_list; + + // The list of objects contained in this block. + octave_base_list *elt_list; + + // Comment preceding the token marking the beginning of the block. + octave_comment_list *lead_comm; + + // Comment preceding END token. + octave_comment_list *trail_comm; + + // No copying! + + tree_classdef_element (const tree_classdef_element&); + + tree_classdef_element& operator = (const tree_classdef_element&); +}; + +class tree_classdef_property +{ +public: + + tree_classdef_property (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e) { } + + ~tree_classdef_property (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_property (const tree_classdef_property&); + + tree_classdef_property& operator = (const tree_classdef_property&); +}; + +class tree_classdef_property_list : public octave_base_list +{ +public: + + tree_classdef_property_list (void) { } + + tree_classdef_property_list (tree_classdef_property* p) { append (p); } + + tree_classdef_property_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_property_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_property_list (const tree_classdef_property_list&); + + tree_classdef_property_list& operator = (const tree_classdef_property_list&); +}; + +class tree_classdef_properties_block + : public tree_classdef_element +{ +public: + + tree_classdef_properties_block (tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + octave_comment_list *lc, + octave_comment_list *tc, + int l = -1, int c = -1) + : tree_classdef_element (a, plist, lc, tc, l, c) { } + + ~tree_classdef_properties_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_properties_block (const tree_classdef_properties_block&); + + tree_classdef_properties_block& operator = (const tree_classdef_properties_block&); +}; + +class tree_classdef_methods_list : public octave_base_list +{ +public: + + tree_classdef_methods_list (void) { } + + tree_classdef_methods_list (const octave_value& f) { append (f); } + + tree_classdef_methods_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_methods_list (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_list (const tree_classdef_methods_list&); + + tree_classdef_methods_list& operator = (const tree_classdef_methods_list&); +}; + +class tree_classdef_methods_block : public tree_classdef_element +{ +public: + + tree_classdef_methods_block (tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, mlist, lc, tc, l, c) { } + + ~tree_classdef_methods_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_block (const tree_classdef_methods_block&); + + tree_classdef_methods_block& operator = (const tree_classdef_methods_block&); +}; + +class tree_classdef_event +{ +public: + + tree_classdef_event (tree_identifier *i = 0) : id (i) { } + + ~tree_classdef_event (void) + { + delete id; + } + + tree_identifier *ident (void) { return id; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + + // No copying! + + tree_classdef_event (const tree_classdef_event&); + + tree_classdef_event& operator = (const tree_classdef_event&); +}; + +class tree_classdef_events_list : public octave_base_list +{ +public: + + tree_classdef_events_list (void) { } + + tree_classdef_events_list (tree_classdef_event *e) { append (e); } + + tree_classdef_events_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_events_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_list (const tree_classdef_events_list&); + + tree_classdef_events_list& operator = (const tree_classdef_events_list&); +}; + +class tree_classdef_events_block + : public tree_classdef_element +{ +public: + + tree_classdef_events_block (tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_events_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_block (const tree_classdef_events_block&); + + tree_classdef_events_block& operator = (const tree_classdef_events_block&); +}; + +class tree_classdef_enum +{ +public: + + tree_classdef_enum (void) : id (0), expr (0) { } + + tree_classdef_enum (tree_identifier *i, tree_expression *e) + : id (i), expr (e) { } + + ~tree_classdef_enum (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_enum (const tree_classdef_enum&); + + tree_classdef_enum& operator = (const tree_classdef_enum&); +}; + +class tree_classdef_enum_list : public octave_base_list +{ +public: + + tree_classdef_enum_list (void) { } + + tree_classdef_enum_list (tree_classdef_enum *e) { append (e); } + + tree_classdef_enum_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_enum_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_list (const tree_classdef_enum_list&); + + tree_classdef_enum_list& operator = (const tree_classdef_enum_list&); +}; + +class tree_classdef_enum_block + : public tree_classdef_element +{ +public: + + tree_classdef_enum_block (tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_enum_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_block (const tree_classdef_enum_block&); + + tree_classdef_enum_block& operator = (const tree_classdef_enum_block&); +}; + +class tree_classdef_body +{ +public: + + typedef std::list::iterator properties_list_iterator; + typedef std::list::const_iterator properties_list_const_iterator; + + typedef std::list::iterator methods_list_iterator; + typedef std::list::const_iterator methods_list_const_iterator; + + typedef std::list::iterator events_list_iterator; + typedef std::list::const_iterator events_list_const_iterator; + + typedef std::list::iterator enum_list_iterator; + typedef std::list::const_iterator enum_list_const_iterator; + + tree_classdef_body (void) + : properties_lst (), methods_lst (), events_lst (), enum_lst () { } + + tree_classdef_body (tree_classdef_properties_block *pb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (pb); + } + + tree_classdef_body (tree_classdef_methods_block *mb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (mb); + } + + tree_classdef_body (tree_classdef_events_block *evb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (evb); + } + + tree_classdef_body (tree_classdef_enum_block *enb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (enb); + } + + ~tree_classdef_body (void); + + void append (tree_classdef_properties_block *pb) + { + properties_lst.push_back (pb); + } + + void append (tree_classdef_methods_block *mb) + { + methods_lst.push_back (mb); + } + + void append (tree_classdef_events_block *evb) + { + events_lst.push_back (evb); + } + + void append (tree_classdef_enum_block *enb) + { + enum_lst.push_back (enb); + } + + std::list properties_list (void) + { + return properties_lst; + } + + std::list methods_list (void) + { + return methods_lst; + } + + std::list events_list (void) + { + return events_lst; + } + + std::list enum_list (void) + { + return enum_lst; + } + + void accept (tree_walker&); + +private: + + std::list properties_lst; + + std::list methods_lst; + + std::list events_lst; + + std::list enum_lst; + + // No copying! + + tree_classdef_body (const tree_classdef_body&); + + tree_classdef_body& operator = (const tree_classdef_body&); +}; + +// Classdef definition. + +class tree_classdef : public tree_command +{ +public: + + tree_classdef (tree_classdef_attribute_list *a, tree_identifier *i, + tree_classdef_superclass_list *sc, + tree_classdef_body *b, octave_comment_list *lc, + octave_comment_list *tc, + const std::string& pn = std::string (), int l = -1, + int c = -1) + : tree_command (l, c), attr_list (a), id (i), + supclass_list (sc), element_list (b), lead_comm (lc), trail_comm (tc), + pack_name (pn) { } + + ~tree_classdef (void) + { + delete attr_list; + delete id; + delete supclass_list; + delete element_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + tree_identifier *ident (void) { return id; } + + tree_classdef_superclass_list *superclass_list (void) { return supclass_list; } + + tree_classdef_body *body (void) { return element_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + octave_comment_list *trailing_comment (void) { return trail_comm; } + + const std::string& package_name (void) const { return pack_name; } + + octave_function* make_meta_class (bool is_at_folder = false); + + tree_classdef *dup (symbol_table::scope_id scope, + symbol_table::context_id context) const; + + void accept (tree_walker& tw); + +private: + + tree_classdef_attribute_list *attr_list; + + tree_identifier *id; + + tree_classdef_superclass_list *supclass_list; + + tree_classdef_body *element_list; + + octave_comment_list *lead_comm; + octave_comment_list *trail_comm; + + std::string pack_name; + + // No copying! + + tree_classdef (const tree_classdef&); + + tree_classdef& operator = (const tree_classdef&); +}; + +#endif diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-eval.cc --- a/libinterp/parse-tree/pt-eval.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-eval.cc Fri Mar 07 13:02:43 2014 -0500 @@ -379,7 +379,8 @@ dim_vector dv = rhs.dims ().redim (2); - octave_idx_type nrows = dv(0), steps = dv(1); + octave_idx_type nrows = dv(0); + octave_idx_type steps = dv(1); if (steps > 0) { @@ -637,6 +638,12 @@ } void +tree_evaluator::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_evaluator::visit_parameter_list (tree_parameter_list&) { panic_impossible (); @@ -1114,6 +1121,11 @@ if (error_state) return; +#if HAVE_LLVM + if (tree_jit::execute (cmd)) + return; +#endif + unwind_protect frame; frame.protect_var (in_loop_command); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-eval.h --- a/libinterp/parse-tree/pt-eval.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-eval.h Fri Mar 07 13:02:43 2014 -0500 @@ -102,6 +102,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-exp.h --- a/libinterp/parse-tree/pt-exp.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-exp.h Fri Mar 07 13:02:43 2014 -0500 @@ -40,7 +40,7 @@ public: tree_expression (int l = -1, int c = -1) - : tree (l, c), num_parens (0), postfix_indexed (false), + : tree (l, c), num_parens (0), postfix_index_type ('\0'), print_flag (false) { } virtual ~tree_expression (void) { } @@ -87,7 +87,9 @@ int paren_count (void) const { return num_parens; } - bool is_postfix_indexed (void) const { return postfix_indexed; } + bool is_postfix_indexed (void) const { return (postfix_index_type != '\0'); } + + char postfix_index (void) const { return postfix_index_type; } // Check if the result of the expression should be printed. // Should normally be used in conjunction with @@ -108,9 +110,9 @@ return this; } - tree_expression *mark_postfix_indexed (void) + tree_expression *set_postfix_index (char type) { - postfix_indexed = true; + postfix_index_type = type; return this; } @@ -123,7 +125,7 @@ virtual void copy_base (const tree_expression& e) { num_parens = e.num_parens; - postfix_indexed = e.postfix_indexed; + postfix_index_type = e.postfix_index_type; print_flag = e.print_flag; } @@ -137,9 +139,10 @@ // ==> 0 for expression e2 int num_parens; - // A flag that says whether this expression has an index associated - // with it. See the code in tree_identifier::rvalue for the rationale. - bool postfix_indexed; + // The first index type associated with this expression. This field + // is 0 (character '\0') if the expression has no associated index. + // See the code in tree_identifier::rvalue for the rationale. + char postfix_index_type; // Print result of rvalue for this expression? bool print_flag; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-funcall.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-funcall.cc Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,110 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-fcn.h" +#include "pt-funcall.h" +#include "pt-walk.h" + +// Function call objects. + +void +tree_funcall::print (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + print_raw (os, pr_as_read_syntax, pr_orig_text); +} + +void +tree_funcall::print_raw (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + if (pr_orig_text) + { + os << original_text (); + } + else + { + octave_function *fp = fcn.function_value (); + std::string nm = fp ? fp->name () : std::string (""); + + os << nm << " ("; + + octave_idx_type len = args.length (); + for (octave_idx_type i = 0; i < len; i++) + { + args(i).print_raw (os, pr_as_read_syntax); + + if (i < len - 1) + os << ", "; + } + + os << ")"; + } +} + +tree_funcall * +tree_funcall::dup (symbol_table::scope_id, symbol_table::context_id) const +{ + tree_funcall *new_fc = new tree_funcall (fcn, args, line (), column ()); + + new_fc->copy_base (*new_fc); + + return new_fc; +} + +void +tree_funcall::accept (tree_walker& tw) +{ + tw.visit_funcall (*this); +} + +octave_value_list +tree_funcall::rvalue (int nargout) +{ + octave_value_list retval; + + retval = feval (fcn.function_value (), args, nargout); + + if (retval.length () == 1 && retval(0).is_function ()) + { + // The return object is a function. We may need to re-index it using the + // same logic as for identifier. This is primarily used for superclass + // references in classdef. + + octave_value val = retval(0); + octave_function *f = val.function_value (true); + + if (f && ! (is_postfix_indexed () + && f->is_postfix_index_handled (postfix_index ()))) + { + octave_value_list tmp_args; + + retval = val.do_multi_index_op (nargout, tmp_args); + } + } + + return retval; +} diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-funcall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/parse-tree/pt-funcall.h Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,98 @@ +/* + +Copyright (C) 2012-2013 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_tree_funcall_h) +#define octave_tree_funcall_h 1 + +#include "ov.h" +#include "oct-obj.h" +#include "parse.h" +#include "pt-exp.h" + +// Function call. This class only represents function calls that have +// known functions (most useful for calls to built-in functions that +// are generated by the parser) and fixed argument lists, known at +// compile time. + +class +tree_funcall : public tree_expression +{ +public: + + tree_funcall (const octave_value& f, const octave_value_list& a, + int l = -1, int c = -1) + : tree_expression (l, c), fcn (f), args (a) + { + if (! fcn.is_function ()) + error ("tree_funcall: invalid function"); + } + + ~tree_funcall (void) { } + + bool has_magic_end (void) const { return false; } + + void print (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + tree_funcall *dup (symbol_table::scope_id, + symbol_table::context_id context) const; + + octave_value rvalue1 (int nargout) + { + octave_value retval; + + const octave_value_list tmp = rvalue (nargout); + + if (! tmp.empty ()) + retval = tmp(0); + + return retval; + } + + octave_value_list rvalue (int nargout); + + octave_value function (void) const { return fcn; } + + octave_value_list arguments (void) const { return args; } + + void accept (tree_walker& tw); + +private: + + // Function to call. Error if not a valid function at time of + // construction. + octave_value fcn; + + // Argument list. + octave_value_list args; + + // No copying! + + tree_funcall (const tree_funcall&); + + tree_funcall& operator = (const tree_funcall&); +}; + +#endif diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-id.cc --- a/libinterp/parse-tree/pt-id.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-id.cc Fri Mar 07 13:02:43 2014 -0500 @@ -76,13 +76,19 @@ // // If this identifier refers to a function, we need to know // whether it is indexed so that we can do the same thing - // for 'f' and 'f()'. If the index is present, return the - // function object and let tree_index_expression::rvalue - // handle indexing. Otherwise, arrange to call the function - // here, so that we don't return the function definition as - // a value. + // for 'f' and 'f()'. If the index is present and the function + // object declares it can handle it, return the function object + // and let tree_index_expression::rvalue handle indexing. + // Otherwise, arrange to call the function here, so that we don't + // return the function definition as a value. - if (val.is_function () && ! is_postfix_indexed ()) + octave_function *fcn = 0; + + if (val.is_function ()) + fcn = val.function_value (true); + + if (fcn && ! (is_postfix_indexed () + && fcn->is_postfix_index_handled (postfix_index ()))) { octave_value_list tmp_args; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-id.h --- a/libinterp/parse-tree/pt-id.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-id.h Fri Mar 07 13:02:43 2014 -0500 @@ -32,6 +32,7 @@ class tree_walker; +#include "oct-lvalue.h" #include "pt-bp.h" #include "pt-exp.h" #include "symtab.h" diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-idx.cc --- a/libinterp/parse-tree/pt-idx.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-idx.cc Fri Mar 07 13:02:43 2014 -0500 @@ -363,7 +363,7 @@ // that argument list so we can pass the appropriate // value to the built-in end function. - const octave_value_list tmp_list + octave_value_list tmp_list = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout); tmp = tmp_list.length () ? tmp_list(0) : octave_value (); @@ -375,6 +375,26 @@ if (error_state) break; + + if (tmp.is_function ()) + { + octave_function *fcn = tmp.function_value (true); + + if (fcn && ! fcn->is_postfix_index_handled (type[i])) + { + octave_value_list empty_args; + + tmp_list = tmp.do_multi_index_op (1, empty_args); + tmp = (tmp_list.length () + ? tmp_list(0) : octave_value ()); + + if (tmp.is_cs_list ()) + gripe_indexed_cs_list (); + + if (error_state) + break; + } + } } } @@ -412,8 +432,27 @@ } if (! error_state) - retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, - lvalue_list); + { + retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout, + lvalue_list); + + octave_value val = retval.length () ? retval(0) : octave_value (); + + if (! error_state && val.is_function ()) + { + octave_function *fcn = val.function_value (true); + + if (fcn) + { + octave_value_list empty_args; + + retval = (lvalue_list + ? val.do_multi_index_op (nargout, empty_args, + lvalue_list) + : val.do_multi_index_op (nargout, empty_args)); + } + } + } } return retval; diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-mat.cc --- a/libinterp/parse-tree/pt-mat.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-mat.cc Fri Mar 07 13:02:43 2014 -0500 @@ -683,7 +683,8 @@ single_type_concat (Array& result, tm_const& tmp) { - octave_idx_type r = 0, c = 0; + octave_idx_type r = 0; + octave_idx_type c = 0; for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) { @@ -753,7 +754,8 @@ return; } - octave_idx_type ncols = row.length (), i = 0; + octave_idx_type ncols = row.length (); + octave_idx_type i = 0; OCTAVE_LOCAL_BUFFER (Array, array_list, ncols); for (tm_row_const::iterator q = row.begin (); @@ -791,12 +793,14 @@ // Sparse matrices require preallocation for efficient indexing; besides, // only horizontal concatenation can be efficiently handled by indexing. // So we just cat all rows through liboctave, then cat the final column. - octave_idx_type nrows = tmp.length (), j = 0; + octave_idx_type nrows = tmp.length (); + octave_idx_type j = 0; OCTAVE_LOCAL_BUFFER (Sparse, sparse_row_list, nrows); for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) { tm_row_const row = *p; - octave_idx_type ncols = row.length (), i = 0; + octave_idx_type ncols = row.length (); + octave_idx_type i = 0; OCTAVE_LOCAL_BUFFER (Sparse, sparse_list, ncols); for (tm_row_const::iterator q = row.begin (); @@ -829,12 +833,14 @@ return; } - octave_idx_type nrows = tmp.length (), j = 0; + octave_idx_type nrows = tmp.length (); + octave_idx_type j = 0; OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows); for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) { tm_row_const row = *p; - octave_idx_type ncols = row.length (), i = 0; + octave_idx_type ncols = row.length (); + octave_idx_type i = 0; OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols); for (tm_row_const::iterator q = row.begin (); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-pr-code.cc --- a/libinterp/parse-tree/pt-pr-code.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-pr-code.cc Fri Mar 07 13:02:43 2014 -0500 @@ -749,6 +749,18 @@ } void +tree_print_code::visit_funcall (tree_funcall& fc) +{ + indent (); + + print_parens (fc, "("); + + fc.print_raw (os, true, print_original_text); + + print_parens (fc, ")"); +} + +void tree_print_code::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); @@ -1144,7 +1156,7 @@ indent (); - os << "until"; + os << "until "; tree_expression *expr = cmd.condition (); @@ -1188,10 +1200,7 @@ } } -// Each print_code() function should call this before printing -// anything. -// -// This doesn't need to be fast, but isn't there a better way? +// Each print_code() function should call this before printing anything. void tree_print_code::indent (void) @@ -1202,8 +1211,7 @@ { os << prefix; - for (int i = 0; i < curr_print_indent_level; i++) - os << " "; + os << std::string (curr_print_indent_level, ' '); beginning_of_line = false; } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-pr-code.h --- a/libinterp/parse-tree/pt-pr-code.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-pr-code.h Fri Mar 07 13:02:43 2014 -0500 @@ -109,6 +109,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/pt-walk.h --- a/libinterp/parse-tree/pt-walk.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/pt-walk.h Fri Mar 07 13:02:43 2014 -0500 @@ -52,6 +52,7 @@ class tree_no_op_command; class tree_constant; class tree_fcn_handle; +class tree_funcall; class tree_parameter_list; class tree_postfix_expression; class tree_prefix_expression; @@ -65,6 +66,24 @@ class tree_while_command; class tree_do_until_command; +class tree_classdef_attribute; +class tree_classdef_attribute_list; +class tree_classdef_superclass; +class tree_classdef_superclass_list; +class tree_classdef_property; +class tree_classdef_property_list; +class tree_classdef_properties_block; +class tree_classdef_methods_list; +class tree_classdef_methods_block; +class tree_classdef_event; +class tree_classdef_events_list; +class tree_classdef_events_block; +class tree_classdef_enum; +class tree_classdef_enum_list; +class tree_classdef_enum_block; +class tree_classdef_body; +class tree_classdef; + class tree_walker { @@ -158,6 +177,9 @@ visit_fcn_handle (tree_fcn_handle&) = 0; virtual void + visit_funcall (tree_funcall&) = 0; + + virtual void visit_parameter_list (tree_parameter_list&) = 0; virtual void @@ -193,6 +215,57 @@ virtual void visit_do_until_command (tree_do_until_command&) = 0; + virtual void + visit_classdef_attribute (tree_classdef_attribute&) { } /* = 0; */ + + virtual void + visit_classdef_attribute_list (tree_classdef_attribute_list&) { } /* = 0; */ + + virtual void + visit_classdef_superclass (tree_classdef_superclass&) { } /* = 0; */ + + virtual void + visit_classdef_superclass_list (tree_classdef_superclass_list&) { } /* = 0; */ + + virtual void + visit_classdef_property (tree_classdef_property&) { } /* = 0; */ + + virtual void + visit_classdef_property_list (tree_classdef_property_list&) { } /* = 0; */ + + virtual void + visit_classdef_properties_block (tree_classdef_properties_block&) { } /* = 0; */ + + virtual void + visit_classdef_methods_list (tree_classdef_methods_list&) { } /* = 0; */ + + virtual void + visit_classdef_methods_block (tree_classdef_methods_block&) { } /* = 0; */ + + virtual void + visit_classdef_event (tree_classdef_event&) { } /* = 0; */ + + virtual void + visit_classdef_events_list (tree_classdef_events_list&) { } /* = 0; */ + + virtual void + visit_classdef_events_block (tree_classdef_events_block&) { } /* = 0; */ + + virtual void + visit_classdef_enum (tree_classdef_enum&) { } /* = 0; */ + + virtual void + visit_classdef_enum_list (tree_classdef_enum_list&) { } /* = 0; */ + + virtual void + visit_classdef_enum_block (tree_classdef_enum_block&) { } /* = 0; */ + + virtual void + visit_classdef_body (tree_classdef_body&) { } /* = 0; */ + + virtual void + visit_classdef (tree_classdef&) { } /* = 0; */ + protected: tree_walker (void) { } diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/token.cc --- a/libinterp/parse-tree/token.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/token.cc Fri Mar 07 13:02:43 2014 -0500 @@ -97,38 +97,29 @@ sr = s; } -token::token (int tv, symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) +token::token (int tv, const std::string& mth, const std::string& cls, + int l, int c) { maybe_cmd = false; tspc = false; line_num = l; column_num = c; tok_val = tv; - type_tag = meta_rec_token; - mc.cr = cls; - mc.pr = pkg; -} - -token::token (int tv, symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) -{ - maybe_cmd = false; - tspc = false; - line_num = l; - column_num = c; - tok_val = tv; - type_tag = scls_rec_token; - sc.mr = mth; - sc.cr = cls; - sc.pr = pkg; + type_tag = scls_name_token; + sc.method_nm = new std::string (mth); + sc.class_nm = new std::string (cls); } token::~token (void) { if (type_tag == string_token) delete str; + + if (type_tag == scls_name_token) + { + delete sc.method_nm; + delete sc.class_nm; + } } std::string @@ -172,39 +163,18 @@ return sr; } -symbol_table::symbol_record * -token::method_rec (void) +std::string +token::superclass_method_name (void) { - assert (type_tag == scls_rec_token); - return sc.mr; -} - -symbol_table::symbol_record * -token::class_rec (void) -{ - assert (type_tag == scls_rec_token); - return sc.cr; + assert (type_tag == scls_name_token); + return *sc.method_nm; } -symbol_table::symbol_record * -token::package_rec (void) -{ - assert (type_tag == scls_rec_token); - return sc.pr; -} - -symbol_table::symbol_record * -token::meta_class_rec (void) +std::string +token::superclass_class_name (void) { - assert (type_tag == meta_rec_token); - return mc.cr; -} - -symbol_table::symbol_record * -token::meta_package_rec (void) -{ - assert (type_tag == meta_rec_token); - return mc.pr; + assert (type_tag == scls_name_token); + return *sc.class_nm; } std::string diff -r de76baa76aa1 -r b83fca22bb4c libinterp/parse-tree/token.h --- a/libinterp/parse-tree/token.h Fri Mar 07 12:54:16 2014 -0500 +++ b/libinterp/parse-tree/token.h Fri Mar 07 13:02:43 2014 -0500 @@ -40,8 +40,7 @@ double_token, ettype_token, sym_rec_token, - scls_rec_token, - meta_rec_token + scls_name_token, }; enum end_tok_type @@ -69,11 +68,8 @@ int l = -1, int c = -1); token (int tv, end_tok_type t, int l = -1, int c = -1); token (int tv, symbol_table::symbol_record *s, int l = -1, int c = -1); - token (int tv, symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); - token (int tv, symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); + token (int tv, const std::string& mth, const std::string& cls, + int l = -1, int c = -1); ~token (void); @@ -106,12 +102,8 @@ end_tok_type ettype (void) const; symbol_table::symbol_record *sym_rec (void); - symbol_table::symbol_record *method_rec (void); - symbol_table::symbol_record *class_rec (void); - symbol_table::symbol_record *package_rec (void); - - symbol_table::symbol_record *meta_class_rec (void); - symbol_table::symbol_record *meta_package_rec (void); + std::string superclass_method_name (void); + std::string superclass_class_name (void); std::string text_rep (void); @@ -137,15 +129,9 @@ symbol_table::symbol_record *sr; struct { - symbol_table::symbol_record *mr; - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; + std::string *method_nm; + std::string *class_nm; } sc; - struct - { - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; - } mc; }; std::string orig_text; }; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/Array.cc --- a/liboctave/array/Array.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/Array.cc Fri Mar 07 13:02:43 2014 -0500 @@ -688,9 +688,9 @@ } else { - octave_idx_type sd = sext[lev-1]; - octave_idx_type dd = dext[lev-1]; - octave_idx_type k; + octave_idx_type sd, dd, k; + sd = sext[lev-1]; + dd = dext[lev-1]; for (k = 0; k < cext[lev]; k++) do_resize_fill (src + k * sd, dest + k * dd, rfv, lev - 1); @@ -2571,9 +2571,8 @@ d.xelem (i) = elem (i, i); } } - else - (*current_liboctave_error_handler) - ("diag: requested diagonal out of range"); + else // Matlab returns [] 0x1 for out-of-range diagonal + d.resize (dim_vector (0, 1)); } else { diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/CDiagMatrix.cc --- a/liboctave/array/CDiagMatrix.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/CDiagMatrix.cc Fri Mar 07 13:02:43 2014 -0500 @@ -383,7 +383,7 @@ } ComplexDiagMatrix -ComplexDiagMatrix::pseudo_inverse (void) const +ComplexDiagMatrix::pseudo_inverse (double tol) const { octave_idx_type r = rows (); octave_idx_type c = cols (); @@ -393,10 +393,11 @@ for (octave_idx_type i = 0; i < len; i++) { - if (elem (i, i) != 0.0) + double val = std::abs (elem (i, i)); + if (val < tol || val == 0.0) + retval.elem (i, i) = 0.0; + else retval.elem (i, i) = 1.0 / elem (i, i); - else - retval.elem (i, i) = 0.0; } return retval; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/CDiagMatrix.h --- a/liboctave/array/CDiagMatrix.h Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/CDiagMatrix.h Fri Mar 07 13:02:43 2014 -0500 @@ -116,7 +116,7 @@ ComplexDiagMatrix inverse (octave_idx_type& info) const; ComplexDiagMatrix inverse (void) const; - ComplexDiagMatrix pseudo_inverse (void) const; + ComplexDiagMatrix pseudo_inverse (double tol = 0.0) const; bool all_elements_are_real (void) const; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/CSparse.cc --- a/liboctave/array/CSparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/CSparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -7688,87 +7688,85 @@ { SparseComplexMatrix r; - if ((a.rows () == b.rows ()) && (a.cols () == b.cols ())) + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (a_nr == b_nr && a_nc == b_nc) { - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (a_nr == 0 || b_nc == 0 || a.nnz () == 0 || b.nnz () == 0) - return SparseComplexMatrix (a_nr, a_nc); - - if (a_nr != b_nr || a_nc != b_nc) - gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); - else + r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); + + octave_idx_type jx = 0; + r.cidx (0) = 0; + for (octave_idx_type i = 0 ; i < a_nc ; i++) { - r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); - - octave_idx_type jx = 0; - r.cidx (0) = 0; - for (octave_idx_type i = 0 ; i < a_nc ; i++) - { - octave_idx_type ja = a.cidx (i); - octave_idx_type ja_max = a.cidx (i+1); - bool ja_lt_max= ja < ja_max; - - octave_idx_type jb = b.cidx (i); - octave_idx_type jb_max = b.cidx (i+1); - bool jb_lt_max = jb < jb_max; - - while (ja_lt_max || jb_lt_max ) - { - octave_quit (); - if ((! jb_lt_max) || - (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + octave_idx_type ja = a.cidx (i); + octave_idx_type ja_max = a.cidx (i+1); + bool ja_lt_max= ja < ja_max; + + octave_idx_type jb = b.cidx (i); + octave_idx_type jb_max = b.cidx (i+1); + bool jb_lt_max = jb < jb_max; + + while (ja_lt_max || jb_lt_max ) + { + octave_quit (); + if ((! jb_lt_max) || + (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + { + Complex tmp = xmin (a.data (ja), 0.); + if (tmp != 0.) { - Complex tmp = xmin (a.data (ja), 0.); - if (tmp != 0.) - { - r.ridx (jx) = a.ridx (ja); - r.data (jx) = tmp; - jx++; - } - ja++; - ja_lt_max= ja < ja_max; + r.ridx (jx) = a.ridx (ja); + r.data (jx) = tmp; + jx++; } - else if (( !ja_lt_max ) || - (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + ja++; + ja_lt_max= ja < ja_max; + } + else if (( !ja_lt_max ) || + (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + { + Complex tmp = xmin (0., b.data (jb)); + if (tmp != 0.) { - Complex tmp = xmin (0., b.data (jb)); - if (tmp != 0.) - { - r.ridx (jx) = b.ridx (jb); - r.data (jx) = tmp; - jx++; - } - jb++; - jb_lt_max= jb < jb_max; + r.ridx (jx) = b.ridx (jb); + r.data (jx) = tmp; + jx++; } - else + jb++; + jb_lt_max= jb < jb_max; + } + else + { + Complex tmp = xmin (a.data (ja), b.data (jb)); + if (tmp != 0.) { - Complex tmp = xmin (a.data (ja), b.data (jb)); - if (tmp != 0.) - { - r.data (jx) = tmp; - r.ridx (jx) = a.ridx (ja); - jx++; - } - ja++; - ja_lt_max= ja < ja_max; - jb++; - jb_lt_max= jb < jb_max; + r.data (jx) = tmp; + r.ridx (jx) = a.ridx (ja); + jx++; } - } - r.cidx (i+1) = jx; - } - - r.maybe_compress (); + ja++; + ja_lt_max= ja < ja_max; + jb++; + jb_lt_max= jb < jb_max; + } + } + r.cidx (i+1) = jx; } + + r.maybe_compress (); } else - (*current_liboctave_error_handler) ("matrix size mismatch"); + { + if (a_nr == 0 || a_nc == 0) + r.resize (a_nr, a_nc); + else if (b_nr == 0 || b_nc == 0) + r.resize (b_nr, b_nc); + else + gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); + } return r; } @@ -7808,91 +7806,85 @@ { SparseComplexMatrix r; - if ((a.rows () == b.rows ()) && (a.cols () == b.cols ())) + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (a_nr == b_nr && a_nc == b_nc) { - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (a_nr == 0 || b_nc == 0) - return SparseComplexMatrix (a_nr, a_nc); - if (a.nnz () == 0) - return SparseComplexMatrix (b); - if (b.nnz () == 0) - return SparseComplexMatrix (a); - - if (a_nr != b_nr || a_nc != b_nc) - gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); - else + r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); + + octave_idx_type jx = 0; + r.cidx (0) = 0; + for (octave_idx_type i = 0 ; i < a_nc ; i++) { - r = SparseComplexMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); - - octave_idx_type jx = 0; - r.cidx (0) = 0; - for (octave_idx_type i = 0 ; i < a_nc ; i++) - { - octave_idx_type ja = a.cidx (i); - octave_idx_type ja_max = a.cidx (i+1); - bool ja_lt_max= ja < ja_max; - - octave_idx_type jb = b.cidx (i); - octave_idx_type jb_max = b.cidx (i+1); - bool jb_lt_max = jb < jb_max; - - while (ja_lt_max || jb_lt_max ) - { - octave_quit (); - if ((! jb_lt_max) || - (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + octave_idx_type ja = a.cidx (i); + octave_idx_type ja_max = a.cidx (i+1); + bool ja_lt_max= ja < ja_max; + + octave_idx_type jb = b.cidx (i); + octave_idx_type jb_max = b.cidx (i+1); + bool jb_lt_max = jb < jb_max; + + while (ja_lt_max || jb_lt_max ) + { + octave_quit (); + if ((! jb_lt_max) || + (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + { + Complex tmp = xmax (a.data (ja), 0.); + if (tmp != 0.) { - Complex tmp = xmax (a.data (ja), 0.); - if (tmp != 0.) - { - r.ridx (jx) = a.ridx (ja); - r.data (jx) = tmp; - jx++; - } - ja++; - ja_lt_max= ja < ja_max; + r.ridx (jx) = a.ridx (ja); + r.data (jx) = tmp; + jx++; } - else if (( !ja_lt_max ) || - (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + ja++; + ja_lt_max= ja < ja_max; + } + else if (( !ja_lt_max ) || + (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + { + Complex tmp = xmax (0., b.data (jb)); + if (tmp != 0.) { - Complex tmp = xmax (0., b.data (jb)); - if (tmp != 0.) - { - r.ridx (jx) = b.ridx (jb); - r.data (jx) = tmp; - jx++; - } - jb++; - jb_lt_max= jb < jb_max; + r.ridx (jx) = b.ridx (jb); + r.data (jx) = tmp; + jx++; } - else + jb++; + jb_lt_max= jb < jb_max; + } + else + { + Complex tmp = xmax (a.data (ja), b.data (jb)); + if (tmp != 0.) { - Complex tmp = xmax (a.data (ja), b.data (jb)); - if (tmp != 0.) - { - r.data (jx) = tmp; - r.ridx (jx) = a.ridx (ja); - jx++; - } - ja++; - ja_lt_max= ja < ja_max; - jb++; - jb_lt_max= jb < jb_max; + r.data (jx) = tmp; + r.ridx (jx) = a.ridx (ja); + jx++; } - } - r.cidx (i+1) = jx; - } - - r.maybe_compress (); + ja++; + ja_lt_max= ja < ja_max; + jb++; + jb_lt_max= jb < jb_max; + } + } + r.cidx (i+1) = jx; } + + r.maybe_compress (); } else - (*current_liboctave_error_handler) ("matrix size mismatch"); + { + if (a_nr == 0 || a_nc == 0) + r.resize (a_nr, a_nc); + else if (b_nr == 0 || b_nc == 0) + r.resize (b_nr, b_nc); + else + gripe_nonconformant ("max", a_nr, a_nc, b_nr, b_nc); + } return r; } diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/DiagArray2.cc --- a/liboctave/array/DiagArray2.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/DiagArray2.cc Fri Mar 07 13:02:43 2014 -0500 @@ -66,9 +66,8 @@ d = Array (dim_vector (std::min (cols () - k, rows ()), 1), T ()); else if (k < 0 && -k < rows ()) d = Array (dim_vector (std::min (rows () + k, cols ()), 1), T ()); - else - (*current_liboctave_error_handler) - ("diag: requested diagonal out of range"); + else // Matlab returns [] 0x1 for out-of-range diagonal + d.resize (dim_vector (0, 1)); return d; } diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/Sparse.cc --- a/liboctave/array/Sparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/Sparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -2491,8 +2491,15 @@ } } else - (*current_liboctave_error_handler) - ("diag: requested diagonal out of range"); + { + // Matlab returns [] 0x1 for out-of-range diagonal + + octave_idx_type nr = 0; + octave_idx_type nc = 1; + octave_idx_type nz = 0; + + d = Sparse (nr, nc, nz); + } } else if (nnr != 0 && nnc != 0) { diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/dDiagMatrix.cc --- a/liboctave/array/dDiagMatrix.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/dDiagMatrix.cc Fri Mar 07 13:02:43 2014 -0500 @@ -292,7 +292,7 @@ } DiagMatrix -DiagMatrix::pseudo_inverse (void) const +DiagMatrix::pseudo_inverse (double tol) const { octave_idx_type r = rows (); octave_idx_type c = cols (); @@ -302,10 +302,11 @@ for (octave_idx_type i = 0; i < len; i++) { - if (elem (i, i) != 0.0) + double val = std::abs (elem (i, i)); + if (val < tol || val == 0.0) + retval.elem (i, i) = 0.0; + else retval.elem (i, i) = 1.0 / elem (i, i); - else - retval.elem (i, i) = 0.0; } return retval; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/dDiagMatrix.h --- a/liboctave/array/dDiagMatrix.h Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/dDiagMatrix.h Fri Mar 07 13:02:43 2014 -0500 @@ -98,7 +98,7 @@ DiagMatrix inverse (void) const; DiagMatrix inverse (octave_idx_type& info) const; - DiagMatrix pseudo_inverse (void) const; + DiagMatrix pseudo_inverse (double tol = 0.0) const; // other operations diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/dSparse.cc --- a/liboctave/array/dSparse.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/dSparse.cc Fri Mar 07 13:02:43 2014 -0500 @@ -7801,84 +7801,85 @@ { SparseMatrix r; - if ((a.rows () == b.rows ()) && (a.cols () == b.cols ())) + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (a_nr == b_nr && a_nc == b_nc) { - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (a_nr != b_nr || a_nc != b_nc) - gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); - else + r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); + + octave_idx_type jx = 0; + r.cidx (0) = 0; + for (octave_idx_type i = 0 ; i < a_nc ; i++) { - r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); - - octave_idx_type jx = 0; - r.cidx (0) = 0; - for (octave_idx_type i = 0 ; i < a_nc ; i++) - { - octave_idx_type ja = a.cidx (i); - octave_idx_type ja_max = a.cidx (i+1); - bool ja_lt_max= ja < ja_max; - - octave_idx_type jb = b.cidx (i); - octave_idx_type jb_max = b.cidx (i+1); - bool jb_lt_max = jb < jb_max; - - while (ja_lt_max || jb_lt_max ) - { - octave_quit (); - if ((! jb_lt_max) || - (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + octave_idx_type ja = a.cidx (i); + octave_idx_type ja_max = a.cidx (i+1); + bool ja_lt_max= ja < ja_max; + + octave_idx_type jb = b.cidx (i); + octave_idx_type jb_max = b.cidx (i+1); + bool jb_lt_max = jb < jb_max; + + while (ja_lt_max || jb_lt_max ) + { + octave_quit (); + if ((! jb_lt_max) || + (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + { + double tmp = xmin (a.data (ja), 0.); + if (tmp != 0.) { - double tmp = xmin (a.data (ja), 0.); - if (tmp != 0.) - { - r.ridx (jx) = a.ridx (ja); - r.data (jx) = tmp; - jx++; - } - ja++; - ja_lt_max= ja < ja_max; + r.ridx (jx) = a.ridx (ja); + r.data (jx) = tmp; + jx++; } - else if (( !ja_lt_max ) || - (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + ja++; + ja_lt_max= ja < ja_max; + } + else if (( !ja_lt_max ) || + (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + { + double tmp = xmin (0., b.data (jb)); + if (tmp != 0.) { - double tmp = xmin (0., b.data (jb)); - if (tmp != 0.) - { - r.ridx (jx) = b.ridx (jb); - r.data (jx) = tmp; - jx++; - } - jb++; - jb_lt_max= jb < jb_max; + r.ridx (jx) = b.ridx (jb); + r.data (jx) = tmp; + jx++; } - else + jb++; + jb_lt_max= jb < jb_max; + } + else + { + double tmp = xmin (a.data (ja), b.data (jb)); + if (tmp != 0.) { - double tmp = xmin (a.data (ja), b.data (jb)); - if (tmp != 0.) - { - r.data (jx) = tmp; - r.ridx (jx) = a.ridx (ja); - jx++; - } - ja++; - ja_lt_max= ja < ja_max; - jb++; - jb_lt_max= jb < jb_max; + r.data (jx) = tmp; + r.ridx (jx) = a.ridx (ja); + jx++; } - } - r.cidx (i+1) = jx; - } - - r.maybe_compress (); + ja++; + ja_lt_max= ja < ja_max; + jb++; + jb_lt_max= jb < jb_max; + } + } + r.cidx (i+1) = jx; } + + r.maybe_compress (); } else - (*current_liboctave_error_handler) ("matrix size mismatch"); + { + if (a_nr == 0 || a_nc == 0) + r.resize (a_nr, a_nc); + else if (b_nr == 0 || b_nc == 0) + r.resize (b_nr, b_nc); + else + gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); + } return r; } @@ -7951,84 +7952,85 @@ { SparseMatrix r; - if ((a.rows () == b.rows ()) && (a.cols () == b.cols ())) + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (a_nr == b_nr && a_nc == b_nc) { - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (a_nr != b_nr || a_nc != b_nc) - gripe_nonconformant ("min", a_nr, a_nc, b_nr, b_nc); - else + r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); + + octave_idx_type jx = 0; + r.cidx (0) = 0; + for (octave_idx_type i = 0 ; i < a_nc ; i++) { - r = SparseMatrix (a_nr, a_nc, (a.nnz () + b.nnz ())); - - octave_idx_type jx = 0; - r.cidx (0) = 0; - for (octave_idx_type i = 0 ; i < a_nc ; i++) - { - octave_idx_type ja = a.cidx (i); - octave_idx_type ja_max = a.cidx (i+1); - bool ja_lt_max= ja < ja_max; - - octave_idx_type jb = b.cidx (i); - octave_idx_type jb_max = b.cidx (i+1); - bool jb_lt_max = jb < jb_max; - - while (ja_lt_max || jb_lt_max ) - { - octave_quit (); - if ((! jb_lt_max) || - (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + octave_idx_type ja = a.cidx (i); + octave_idx_type ja_max = a.cidx (i+1); + bool ja_lt_max= ja < ja_max; + + octave_idx_type jb = b.cidx (i); + octave_idx_type jb_max = b.cidx (i+1); + bool jb_lt_max = jb < jb_max; + + while (ja_lt_max || jb_lt_max ) + { + octave_quit (); + if ((! jb_lt_max) || + (ja_lt_max && (a.ridx (ja) < b.ridx (jb)))) + { + double tmp = xmax (a.data (ja), 0.); + if (tmp != 0.) { - double tmp = xmax (a.data (ja), 0.); - if (tmp != 0.) - { - r.ridx (jx) = a.ridx (ja); - r.data (jx) = tmp; - jx++; - } - ja++; - ja_lt_max= ja < ja_max; + r.ridx (jx) = a.ridx (ja); + r.data (jx) = tmp; + jx++; } - else if (( !ja_lt_max ) || - (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + ja++; + ja_lt_max= ja < ja_max; + } + else if (( !ja_lt_max ) || + (jb_lt_max && (b.ridx (jb) < a.ridx (ja)) ) ) + { + double tmp = xmax (0., b.data (jb)); + if (tmp != 0.) { - double tmp = xmax (0., b.data (jb)); - if (tmp != 0.) - { - r.ridx (jx) = b.ridx (jb); - r.data (jx) = tmp; - jx++; - } - jb++; - jb_lt_max= jb < jb_max; + r.ridx (jx) = b.ridx (jb); + r.data (jx) = tmp; + jx++; } - else + jb++; + jb_lt_max= jb < jb_max; + } + else + { + double tmp = xmax (a.data (ja), b.data (jb)); + if (tmp != 0.) { - double tmp = xmax (a.data (ja), b.data (jb)); - if (tmp != 0.) - { - r.data (jx) = tmp; - r.ridx (jx) = a.ridx (ja); - jx++; - } - ja++; - ja_lt_max= ja < ja_max; - jb++; - jb_lt_max= jb < jb_max; + r.data (jx) = tmp; + r.ridx (jx) = a.ridx (ja); + jx++; } - } - r.cidx (i+1) = jx; - } - - r.maybe_compress (); + ja++; + ja_lt_max= ja < ja_max; + jb++; + jb_lt_max= jb < jb_max; + } + } + r.cidx (i+1) = jx; } + + r.maybe_compress (); } else - (*current_liboctave_error_handler) ("matrix size mismatch"); + { + if (a_nr == 0 || a_nc == 0) + r.resize (a_nr, a_nc); + else if (b_nr == 0 || b_nc == 0) + r.resize (b_nr, b_nc); + else + gripe_nonconformant ("max", a_nr, a_nc, b_nr, b_nc); + } return r; } diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/fCDiagMatrix.cc --- a/liboctave/array/fCDiagMatrix.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/fCDiagMatrix.cc Fri Mar 07 13:02:43 2014 -0500 @@ -387,7 +387,7 @@ } FloatComplexDiagMatrix -FloatComplexDiagMatrix::pseudo_inverse (void) const +FloatComplexDiagMatrix::pseudo_inverse (float tol) const { octave_idx_type r = rows (); octave_idx_type c = cols (); @@ -397,10 +397,11 @@ for (octave_idx_type i = 0; i < len; i++) { - if (elem (i, i) != 0.0f) + float val = std::abs (elem (i, i)); + if (val < tol || val == 0.0f) + retval.elem (i, i) = 0.0f; + else retval.elem (i, i) = 1.0f / elem (i, i); - else - retval.elem (i, i) = 0.0f; } return retval; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/fCDiagMatrix.h --- a/liboctave/array/fCDiagMatrix.h Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/fCDiagMatrix.h Fri Mar 07 13:02:43 2014 -0500 @@ -122,7 +122,7 @@ FloatComplexDiagMatrix inverse (octave_idx_type& info) const; FloatComplexDiagMatrix inverse (void) const; - FloatComplexDiagMatrix pseudo_inverse (void) const; + FloatComplexDiagMatrix pseudo_inverse (float tol = 0.0f) const; bool all_elements_are_real (void) const; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/fDiagMatrix.cc --- a/liboctave/array/fDiagMatrix.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/fDiagMatrix.cc Fri Mar 07 13:02:43 2014 -0500 @@ -292,7 +292,7 @@ } FloatDiagMatrix -FloatDiagMatrix::pseudo_inverse (void) const +FloatDiagMatrix::pseudo_inverse (float tol) const { octave_idx_type r = rows (); octave_idx_type c = cols (); @@ -302,10 +302,11 @@ for (octave_idx_type i = 0; i < len; i++) { - if (elem (i, i) != 0.0f) + float val = std::abs (elem (i, i)); + if (val < tol || val == 0.0f) + retval.elem (i, i) = 0.0f; + else retval.elem (i, i) = 1.0f / elem (i, i); - else - retval.elem (i, i) = 0.0f; } return retval; diff -r de76baa76aa1 -r b83fca22bb4c liboctave/array/fDiagMatrix.h --- a/liboctave/array/fDiagMatrix.h Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/array/fDiagMatrix.h Fri Mar 07 13:02:43 2014 -0500 @@ -99,7 +99,7 @@ FloatDiagMatrix inverse (void) const; FloatDiagMatrix inverse (octave_idx_type& info) const; - FloatDiagMatrix pseudo_inverse (void) const; + FloatDiagMatrix pseudo_inverse (float tol = 0.0f) const; // other operations diff -r de76baa76aa1 -r b83fca22bb4c liboctave/operators/mx-inlines.cc --- a/liboctave/operators/mx-inlines.cc Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/operators/mx-inlines.cc Fri Mar 07 13:02:43 2014 -0500 @@ -1345,8 +1345,8 @@ inline T mx_inline_xsum (const T *v, octave_idx_type n) { - T s = 0; - T e = 0; + T s, e; + s = e = 0; for (octave_idx_type i = 0; i < n; i++) twosum_accum (s, e, v[i]); diff -r de76baa76aa1 -r b83fca22bb4c liboctave/system/module.mk --- a/liboctave/system/module.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/system/module.mk Fri Mar 07 13:02:43 2014 -0500 @@ -18,10 +18,6 @@ system/sysdir.h \ system/syswait.h -SYSTEM_C_SRC = \ - system/tempnam.c \ - system/tempname.c - SYSTEM_SRC = \ system/dir-ops.cc \ system/file-ops.cc \ @@ -33,8 +29,7 @@ system/oct-passwd.cc \ system/oct-syscalls.cc \ system/oct-time.cc \ - system/oct-uname.cc \ - $(SYSTEM_C_SRC) + system/oct-uname.cc noinst_LTLIBRARIES += system/libsystem.la diff -r de76baa76aa1 -r b83fca22bb4c liboctave/system/tempnam.c --- a/liboctave/system/tempnam.c Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 51 Franklin Street, -Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef HAVE_TEMPNAM - -#include -#include -#include -#include - -extern char *__stdio_gen_tempname (const char *dir, const char *pfx, - int dir_search, size_t *lenptr, - FILE **streamptr); - -/* Generate a unique temporary filename using up to five characters of PFX - if it is not NULL. The directory to put this file in is searched for - as follows: First the environment variable "TMPDIR" is checked. - If it contains the name of a writable directory, that directory is used. - If not and if DIR is not NULL, that value is checked. If that fails, - P_tmpdir is tried and finally "/tmp". The storage for the filename - is allocated by `malloc'. */ -char * -tempnam (const char *dir, const char *pfx) -{ - size_t len; - register char *s; - register char *t = __stdio_gen_tempname (dir, pfx, 1, &len, (FILE **) NULL); - - if (t == NULL) - return NULL; - - s = (char *) malloc (len); - if (s == NULL) - return NULL; - - (void) memcpy (s, t, len); - return s; -} - -#endif diff -r de76baa76aa1 -r b83fca22bb4c liboctave/system/tempname.c --- a/liboctave/system/tempname.c Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,207 +0,0 @@ -/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public -License along with the GNU C Library; see the file COPYING. If -not, write to the Free Software Foundation, Inc., 51 Franklin Street, -Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef HAVE_TEMPNAM - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "statdefs.h" - -#ifndef FILENAME_MAX -#ifdef MAXPATHLEN -#define FILENAME_MAX MAXPATHLEN -#else -#define FILENAME_MAX 1024 -#endif -#endif - -#ifndef P_tmpdir -#define P_tmpdir "/usr/tmp/" -#endif - -/* Return nonzero if DIR is an existent directory. */ -static int -diraccess (const char *dir) -{ - struct stat buf; - return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode); -} - -/* Return nonzero if FILE exists. */ -static int -exists (const char *file) -{ - /* We can stat the file even if we can't read its data. */ - struct stat st; - int save = errno; - if (stat (file, &st) == 0) - return 1; - else - { - /* We report that the file exists if stat failed for a reason other - than nonexistence. In this case, it may or may not exist, and we - don't know; but reporting that it does exist will never cause any - trouble, while reporting that it doesn't exist when it does would - violate the interface of __stdio_gen_tempname. */ - int exists = errno != ENOENT; - errno = save; - return exists; - } -} - - -/* These are the characters used in temporary filenames. */ -static const char letters[] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -/* Generate a temporary filename and return it (in a static buffer). If - STREAMPTR is not NULL, open a stream "w+b" on the file and set - *STREAMPTR to it. If DIR_SEARCH is nonzero, DIR and PFX are used as - described for tempnam. If not, a temporary filename in P_tmpdir with no - special prefix is generated. If LENPTR is not NULL, *LENPTR is set the - to length (including the terminating '\0') of the resultant filename, - which is returned. This goes through a cyclic pattern of all possible - filenames consisting of five decimal digits of the current pid and three - of the characters in `letters'. Data for tempnam and tmpnam is kept - separate, but when tempnam is using P_tmpdir and no prefix (i.e, it is - identical to tmpnam), the same data is used. Each potential filename is - tested for an already-existing file of the same name, and no name of an - existing file will be returned. When the cycle reaches its end - (12345ZZZ), NULL is returned. */ -char * -__stdio_gen_tempname (const char *dir, const char *pfx, - int dir_search, size_t *lenptr, - FILE **streamptr) -{ - int saverrno = errno; - static const char tmpdir[] = P_tmpdir; - static size_t indices[2]; - size_t *idx; - static char buf[FILENAME_MAX]; - static pid_t oldpid = (pid_t) 0; - pid_t pid = getpid (); - register size_t len, plen, dlen; - - if (dir_search) - { - register const char *d = getenv ("TMPDIR"); - if (d != NULL && !diraccess (d)) - d = NULL; - if (d == NULL && dir != NULL && diraccess (dir)) - d = dir; - if (d == NULL && diraccess (tmpdir)) - d = tmpdir; - if (d == NULL && diraccess ("/tmp")) - d = "/tmp"; - if (d == NULL) - { - errno = ENOENT; - return NULL; - } - dir = d; - } - else - dir = tmpdir; - - dlen = strlen (dir); - - /* Remove trailing slashes from the directory name. */ - while (dlen > 1 && dir[dlen - 1] == '/') - --dlen; - - if (pfx != NULL && *pfx != '\0') - { - plen = strlen (pfx); - if (plen > 5) - plen = 5; - } - else - plen = 0; - - if (dir != tmpdir && !strcmp (dir, tmpdir)) - dir = tmpdir; - idx = &indices[(plen == 0 && dir == tmpdir) ? 1 : 0]; - - if (pid != oldpid) - { - oldpid = pid; - indices[0] = indices[1] = 0; - } - - len = dlen + 1 + plen + 5 + 3; - for (; *idx < ((sizeof (letters) - 1) * (sizeof (letters) - 1) * - (sizeof (letters) - 1)); - ++*idx) - { - /* Construct a file name and see if it already exists. - - We use a single counter in *IDX to cycle each of three - character positions through each of 62 possible letters. */ - - if (sizeof (buf) < len) - return NULL; - - sprintf (buf, "%.*s/%.*s%.5d%c%c%c", - (int) dlen, dir, (int) plen, - pfx, pid % 100000, - letters[*idx - % (sizeof (letters) - 1)], - letters[(*idx / (sizeof (letters) - 1)) - % (sizeof (letters) - 1)], - letters[(*idx / ((sizeof (letters) - 1) * - (sizeof (letters) - 1))) - % (sizeof (letters) - 1)] - ); - - if (! buf || strlen (buf) != (int) len) - return NULL; - - if (streamptr != NULL) - abort (); - else if (exists (buf)) - continue; - - /* If the file already existed we have continued the loop above, - so we only get here when we have a winning name to return. */ - - errno = saverrno; - - if (lenptr != NULL) - *lenptr = len + 1; - return buf; - } - - /* We got out of the loop because we ran out of combinations to try. */ - errno = EEXIST; /* ? */ - return NULL; -} - -#endif diff -r de76baa76aa1 -r b83fca22bb4c liboctave/util/base-list.h --- a/liboctave/util/base-list.h Fri Mar 07 12:54:16 2014 -0500 +++ b/liboctave/util/base-list.h Fri Mar 07 13:02:43 2014 -0500 @@ -104,8 +104,6 @@ // For backward compatibility. void append (const elt_type& s) { lst.push_back (s); } -protected: - octave_base_list (void) : lst () { } octave_base_list (const std::list& l) : lst (l) { } diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/default_save_options.m --- a/scripts/deprecated/default_save_options.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -## Copyright (C) 2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{val} =} default_save_options () -## @deftypefnx {Built-in Function} {@var{old_val} =} default_save_options (@var{new_val}) -## @deftypefnx {Built-in Function} {} default_save_options (@var{new_val}, "local") -## This function has been deprecated. Use @code{@file{save_default_options}} -## instead. -## @seealso{save_default_options} -## @end deftypefn - -## Deprecated in 3.8 - -function retval = default_save_options (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "default_save_options is obsolete and will be removed from a future version of Octave, please use save_default_options instead"); - endif - - retval = save_default_options (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/find_dir_in_path.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/deprecated/find_dir_in_path.m Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,40 @@ +## Copyright (C) 2013 John W. Eaton +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Built-in Function} {} find_dir_in_path (@var{dir}) +## @deftypefnx {Built-in Function} {} find_dir_in_path (@var{dir}, "all") +## This function has been deprecated. Use @code{dir_in_loadpath} instead. +## @seealso{dir_in_loadpath} +## @end deftypefn + +## Deprecated in version 4.2 + +function retval = find_dir_in_path (varargin) + + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "find_dir_in_path is obsolete and will be removed from a future version of Octave, please use dir_in_loadpath instead"); + endif + + retval = dir_in_loadpath (varargin{:}); + +endfunction + diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/gen_doc_cache.m --- a/scripts/deprecated/gen_doc_cache.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -## Copyright (C) 2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Function File} {} gen_doc_cache (@var{out_file}, @var{directory}) -## This function has been deprecated. Use @code{doc_cache_create} instead. -## @seealso{doc_cache_create} -## @end deftypefn - -## Deprecated in 3.8 - -function gen_doc_cache (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "gen_doc_cache is obsolete and will be removed from a future version of Octave, please use doc_cache_create instead"); - endif - - doc_cache_create (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/interp1q.m --- a/scripts/deprecated/interp1q.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -## Copyright (C) 2008-2013 David Bateman -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{yi} =} interp1q (@var{x}, @var{y}, @var{xi}) -## One-dimensional linear interpolation without error checking. -## Interpolates @var{y}, defined at the points @var{x}, at the points -## @var{xi}. The sample points @var{x} must be a strictly monotonically -## increasing column vector. If @var{y} is a matrix or an N-dimensional -## array, the interpolation is performed on each column of @var{y}. If -## @var{y} is a vector, it must be a column vector of the same length as -## @var{x}. -## -## Values of @var{xi} beyond the endpoints of the interpolation result -## in NA being returned. -## -## Note that the error checking is only a significant portion of the -## execution time of this @code{interp1} if the size of the input arguments -## is relatively small. Therefore, the benefit of using @code{interp1q} -## is relatively small. -## @seealso{interp1} -## @end deftypefn - -function yi = interp1q (x, y, xi) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "interp1q is obsolete and will be removed from a future version of Octave; use interp1 instead"); - endif - - x = x(:); - nx = rows (x); - szy = size (y); - y = y(:,:); - [ny, nc] = size (y); - szx = size (xi); - xi = xi (:); - dy = diff (y); - dx = diff (x); - idx = lookup (x, xi, "lr"); - s = (xi - x (idx)) ./ dx (idx); - yi = bsxfun (@times, s, dy(idx,:)) + y(idx,:); - range = xi < x(1) | !(xi <= x(nx)); - yi(range,:) = NA; - if (length (szx) == 2 && any (szx == 1)) - yi = reshape (yi, [max(szx), szy(2:end)]); - else - yi = reshape (yi, [szx, szy(2:end)]); - endif -endfunction - - -%!shared xp, yp, xi, yi -%! xp = [0:2:10].'; yp = sin (2*pi*xp/5); -%! xi = [-1; 0; 2.2; 4; 6.6; 10; 11]; -%! yi = interp1 (xp,yp,xi); -%!assert (interp1q (xp,yp, [min(xp)-1; max(xp)+1]), [NA; NA]); -%!assert (interp1q (xp,yp,xp), yp, 100*eps); -%!assert (isempty (interp1q (xp,yp,[]))); -%!assert (interp1q (xp,yp,xi), yi); -%!assert (interp1q (xp,[yp,yp],xi), [yi, yi]); -%!assert (interp1q (xp,yp,[xi,xi]), [yi, yi]); -%!assert (interp1q (xp,[yp,yp],[xi,xi]), cat (3, [yi, yi], [yi, yi])); - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/isequalwithequalnans.m --- a/scripts/deprecated/isequalwithequalnans.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -## Copyright (C) 2005-2013 William Poetra Yoga Hadisoeseno -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Function File} {} isequalwithequalnans (@var{x1}, @var{x2}, @dots{}) -## This function has been deprecated. Use @code{@file{isequaln}} instead. -## @seealso{isequaln} -## @end deftypefn - -## Deprecated in 3.8 - -function retval = isequalwithequalnans (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "isequalwithequalnans is obsolete and will be removed from a future version of Octave, please use isequaln instead"); - endif - - retval = isequaln (varargin{:}); - -endfunction - - -## test for equality -%!assert (isequalwithequalnans ({1,2,NaN,4},{1,2,NaN,4}), true) -%!assert (isequalwithequalnans ([1,2,NaN,4],[1,2,NaN,4]), true) -## test for inequality -%!assert (isequalwithequalnans ([1,2,NaN,4],[1,NaN,3,4]), false) -%!assert (isequalwithequalnans ([1,2,NaN,4],[1,2,3,4]), false) -## test for equality (struct) -%!assert (isequalwithequalnans (struct ('a',NaN,'b',2),struct ('a',NaN,'b',2),struct ('a',NaN,'b',2)), true) -%!assert (isequalwithequalnans (1,2,1), false) - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_convert_matrix.m --- a/scripts/deprecated/java_convert_matrix.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -## Copyright (C) 2012-2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{val} =} java_convert_matrix () -## @deftypefnx {Built-in Function} {@var{old_val} =} java_convert_matrix (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_convert_matrix (@var{new_val}, "local") -## Query or set the internal variable that controls whether Java arrays are -## automatically converted to Octave matrices. The default value is false. -## -## When called from inside a function with the @qcode{"local"} option, the -## variable is changed locally for the function and any subroutines it calls. -## The original variable value is restored when exiting the function. -## @seealso{java_matrix_autoconversion, java_unsigned_conversion, java_debug} -## @end deftypefn - -function old_val = java_convert_matrix (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_convert_matrix is obsolete and will be removed from a future version of Octave; use java_matrix_autoconversion instead"); - endif - - if (nargin > 2) - print_usage (); - endif - - old_val = java_matrix_autoconversion (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_debug.m --- a/scripts/deprecated/java_debug.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -## Copyright (C) 2012-2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{val} =} java_debug () -## @deftypefnx {Built-in Function} {@var{old_val} =} java_debug (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_debug (@var{new_val}, "local") -## Query or set the internal variable that determines whether extra debugging -## information regarding the initialization of the JVM and any Java exceptions -## is printed. -## -## When called from inside a function with the @qcode{"local"} option, the -## variable is changed locally for the function and any subroutines it calls. -## The original variable value is restored when exiting the function. -## @seealso{debug_java, java_convert_matrix, java_unsigned_conversion} -## @end deftypefn - -function old_val = java_debug (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_debug is obsolete and will be removed from a future version of Octave; use debug_java instead"); - endif - - if (nargin > 2) - print_usage (); - endif - - old_val = debug_java (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_get.m --- a/scripts/deprecated/java_get.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -## Copyright (C) 2012-2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{val} =} java_get (@var{obj}, @var{name}) -## Get the value of the field @var{name} of the Java object @var{obj}. For -## static fields, @var{obj} can be a string representing the fully qualified -## name of the corresponding class. -## -## When @var{obj} is a regular Java object, structure-like indexing can be -## used as a shortcut syntax. For instance, the two following statements are -## equivalent -## -## @example -## @group -## java_get (x, "field1") -## x.field1 -## @end group -## @end example -## -## @seealso{java_set, javaMethod, javaObject} -## @end deftypefn - -function retval = java_get (obj, name) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_get is obsolete and will be removed from a future version of Octave; use structure-like indexing instead"); - endif - - if (nargin != 2) - print_usage (); - endif - - if (isjava (obj)) - retval = obj.(name); - elseif (ischar (obj)) - ## FIXME: Need a solution for getting static fields of class - ## which does not depend on __java_get__ which will be removed. - retval = __java_get__ (obj, name); - else - error ("java_get: OBJ must be a Java object"); - endif - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_invoke.m --- a/scripts/deprecated/java_invoke.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -## Copyright (C) 2007, 2013 Michael Goffioul -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{ret} =} java_invoke (@var{obj}, @var{methodname}) -## @deftypefnx {Built-in Function} {@var{ret} =} java_invoke (@var{obj}, @var{methodname}, @var{arg1}, @dots{}) -## Invoke the method @var{methodname} on the Java object @var{obj} with the -## arguments @var{arg1}, @dots{} For static methods, @var{obj} can be a -## string representing the fully qualified name of the corresponding class. -## The function returns the result of the method invocation. -## -## When @var{obj} is a regular Java object, structure-like indexing can be -## used as a shortcut syntax. For instance, the two following statements are -## equivalent -## -## @example -## @group -## ret = java_invoke (x, "method1", 1.0, "a string") -## ret = x.method1 (1.0, "a string") -## @end group -## @end example -## -## @seealso{javaMethod, javaObject} -## @end deftypefn - -function retval = java_invoke (obj, methodname, varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_invoke is obsolete and will be removed from a future version of Octave, please use javaMethod instead"); - endif - - if (nargin < 2) - print_usage (); - endif - - retval = javaMethod (methodname, obj, varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_set.m --- a/scripts/deprecated/java_set.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -## Copyright (C) 2012-2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Loadable Function} {@var{obj} =} java_set (@var{obj}, @var{name}, @var{val}) -## Set the value of the field @var{name} of the Java object @var{obj} to -## @var{val}. For static fields, @var{obj} can be a string representing the -## fully qualified named of the corresponding Java class. -## -## When @var{obj} is a regular Java object, structure-like indexing can be -## used as a shortcut syntax. For instance, the two following statements are -## equivalent -## -## @example -## @group -## java_set (x, "field1", val) -## x.field1 = val -## @end group -## @end example -## -## @seealso{java_get, javaMethod, javaObject} -## @end deftypefn - -function retval = java_set (obj, name, val) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_set is obsolete and will be removed from a future version of Octave; use structure-like indexing instead"); - endif - - if (nargin != 3) - print_usage (); - endif - - if (isjava (obj)) - obj.(name) = val; - elseif (ischar (obj)) - ## FIXME: Need a solution for getting static fields of class - ## which does not depend on __java_set__ which will be removed. - retval = __java_set__ (obj, name, val); - else - error ("java_set: OBJ must be a Java object"); - endif - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/java_unsigned_conversion.m --- a/scripts/deprecated/java_unsigned_conversion.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -## Copyright (C) 2012-2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{val} =} java_unsigned_conversion () -## @deftypefnx {Built-in Function} {@var{old_val} =} java_unsigned_conversion (@var{new_val}) -## @deftypefnx {Built-in Function} {} java_unsigned_conversion (@var{new_val}, "local") -## Query or set the internal variable that controls how integer classes are -## converted when Java matrix autoconversion is enabled. When enabled, Java -## arrays of class Byte or Integer are converted to matrices of class uint8 or -## uint32 respectively. -## -## When called from inside a function with the @qcode{"local"} option, the -## variable is changed locally for the function and any subroutines it calls. -## The original variable value is restored when exiting the function. -## @seealso{java_unsigned_autoconversion, java_convert_matrix, debug_java} -## @end deftypefn - -function old_val = java_unsigned_conversion (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "java_unsigned_conversion is obsolete and will be removed from a future version of Octave; use java_unsigned_autoconversion instead"); - endif - - if (nargin > 2) - print_usage (); - endif - - old_val = java_unsigned_autoconversion (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/javafields.m --- a/scripts/deprecated/javafields.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -## Copyright (C) 2007, 2013 Michael Goffioul -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Function File} {} javafields (@var{javaobj}) -## @deftypefnx {Function File} {} javafields ("@var{classname}") -## @deftypefnx {Function File} {@var{fld_names} =} javafields (@dots{}) -## Return the fields of a Java object or Java class in the form of a cell -## array of strings. If no output is requested, print the result -## to the standard output. -## @seealso{fieldnames, methods, javaObject} -## @end deftypefn - -function fld_names = javafields (javaobj) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "javafields is obsolete and will be removed from a future version of Octave, please use fieldnames instead"); - endif - - if (nargin != 1) - print_usage (); - endif - - c_methods = javaMethod ("getFields", "org.octave.ClassHelper", javaobj); - method_list = ostrsplit (c_methods, ';'); - - if (nargout == 0) - if (! isempty (method_list)) - disp (method_list); - endif - else - fld_names = cellstr (method_list); - endif - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/javamethods.m --- a/scripts/deprecated/javamethods.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -## Copyright (C) 2007, 2013 Michael Goffioul -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Function File} {} javamethods (@var{javaobj}) -## @deftypefnx {Function File} {} javamethods ("@var{classname}") -## @deftypefnx {Function File} {@var{mtd_names} =} javamethods (@dots{}) -## Return the methods of a Java object or Java class in the form of a cell -## array of strings. If no output is requested, print the result to the -## standard output. -## @seealso{methods, fieldnames, javaMethod, javaObject} -## @end deftypefn - -function mtd_names = javamethods (classname) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "javamethods is obsolete and will be removed from a future version of Octave, please use methods instead"); - endif - - if (nargin != 1) - print_usage (); - endif - - cls_methods = javaMethod ("getMethods", "org.octave.ClassHelper", classname); - method_list = ostrsplit (cls_methods, ';'); - - if (nargout == 0) - if (! isempty (method_list)) - disp (method_list); - endif - else - mtd_names = cellstr (method_list); - endif - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/module.mk --- a/scripts/deprecated/module.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/deprecated/module.mk Fri Mar 07 13:02:43 2014 -0500 @@ -1,23 +1,9 @@ FCN_FILE_DIRS += deprecated deprecated_FCN_FILES = \ - deprecated/default_save_options.m \ - deprecated/gen_doc_cache.m \ - deprecated/interp1q.m \ - deprecated/isequalwithequalnans.m \ + deprecated/find_dir_in_path.m \ deprecated/isstr.m \ - deprecated/java_convert_matrix.m \ - deprecated/java_debug.m \ - deprecated/java_get.m \ - deprecated/java_invoke.m \ - deprecated/java_new.m \ - deprecated/java_unsigned_conversion.m \ - deprecated/java_set.m \ - deprecated/javafields.m \ - deprecated/javamethods.m \ - deprecated/re_read_readline_init_file.m \ - deprecated/read_readline_init_file.m \ - deprecated/saving_history.m + deprecated/nfields.m FCN_FILES += $(deprecated_FCN_FILES) diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/nfields.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/deprecated/nfields.m Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,44 @@ +## Copyright (C) 2014 Rik Wehbring +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Function File} {} nfields (@var{s}) +## Return the number of fields of the structure @var{s}. +## +## @strong{Warning:} @code{nfields} is scheduled for removal in version 4.6. +## Use @code{numfields} instead. +## @seealso{numfields, fieldnames} +## @end deftypefn + +function retval = nfields (varargin) + + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "nfields is obsolete and will be removed from a future version of Octave; please use numfields instead"); + endif + + if (nargin < 1) + print_usage (); + endif + + retval = numfields (varargin{:}); + +endfunction + diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/re_read_readline_init_file.m --- a/scripts/deprecated/re_read_readline_init_file.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -## Copyright (C) 2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} re_read_readline_init_file (@var{file}) -## This function has been deprecated. Use -## @code{@file{readline_re_read_init_file}} instead. -## @seealso{readline_read_init_file} -## @end deftypefn - -## Deprecated in 3.8 - -function re_read_readline_init_file (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "re_read_readline_init_file is obsolete and will be removed from a future version of Octave, please use readline_re_read_init_file instead"); - endif - - readline_re_read_init_file (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/read_readline_init_file.m --- a/scripts/deprecated/read_readline_init_file.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -## Copyright (C) 2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {} read_readline_init_file (@var{file}) -## This function has been deprecated. Use -## @code{@file{readline_read_init_file}} instead. -## @seealso{readline_read_init_file} -## @end deftypefn - -## Deprecated in 3.8 - -function read_readline_init_file (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "read_readline_init_file is obsolete and will be removed from a future version of Octave, please use readline_read_init_file instead"); - endif - - readline_read_init_file (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/deprecated/saving_history.m --- a/scripts/deprecated/saving_history.m Fri Mar 07 12:54:16 2014 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -## Copyright (C) 2013 Rik Wehbring -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## . - -## -*- texinfo -*- -## @deftypefn {Built-in Function} {@var{val} =} saving_history () -## @deftypefnx {Built-in Function} {@var{old_val} =} saving_history (@var{new_val}) -## @deftypefnx {Built-in Function} {} saving_history (@var{new_val}, "local") -## This function has been deprecated. Use @code{@file{history_save}} instead. -## @seealso{history_save} -## @end deftypefn - -## Deprecated in 3.8 - -function retval = saving_history (varargin) - - persistent warned = false; - if (! warned) - warned = true; - warning ("Octave:deprecated-function", - "saving_history is obsolete and will be removed from a future version of Octave, please use history_save instead"); - endif - - retval = save_default_options (varargin{:}); - -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/general/bincoeff.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/general/cell2mat.m --- a/scripts/general/cell2mat.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/general/cell2mat.m Fri Mar 07 13:02:43 2014 -0500 @@ -32,15 +32,14 @@ print_usage (); endif - if (! iscell (c)) - error ("cell2mat: C is not a cell array"); - endif - nb = numel (c); if (nb == 0) m = []; else + if (! iscell (c)) + error ("cell2mat: C must be a cell array"); + endif ## Check first for valid matrix types valid = cellfun ("isnumeric", c); @@ -94,6 +93,7 @@ %! cell2mat (C) %!assert (cell2mat ({}), []); +%!assert (cell2mat ([]), []); %!test %! C = {[1], [2 3 4]; [5; 9], [6 7 8; 10 11 12]}; %! D = C; D(:,:,2) = C; @@ -115,7 +115,7 @@ %!error cell2mat () %!error cell2mat (1,2) -%!error cell2mat ([1,2]) +%!error cell2mat ([1,2]) %!error cell2mat ({[1], struct()}) %!error cell2mat ({[1], {1}}) %!error cell2mat ({struct(), {1}}) diff -r de76baa76aa1 -r b83fca22bb4c scripts/general/fieldnames.m --- a/scripts/general/fieldnames.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/general/fieldnames.m Fri Mar 07 13:02:43 2014 -0500 @@ -33,7 +33,7 @@ ## When the input is a Java object @var{javaobj} or Java classname ## @var{jclassname} the name are the public data elements of the object or ## class. -## @seealso{nfields, isfield, orderfields, struct, methods} +## @seealso{numfields, isfield, orderfields, struct, methods} ## @end deftypefn function names = fieldnames (obj) diff -r de76baa76aa1 -r b83fca22bb4c scripts/general/private/__isequal__.m --- a/scripts/general/private/__isequal__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/general/private/__isequal__.m Fri Mar 07 13:02:43 2014 -0500 @@ -95,9 +95,9 @@ if (isstruct (x)) ## Test the number of fields. fn_x = fieldnames (x); - l_fn_x = length (fn_x); + l_fn_x = numfields (x); fn_v = cellfun ("fieldnames", varargin, "uniformoutput", false); - t = all (l_fn_x == cellfun ("length", fn_v)); + t = all (l_fn_x == cellfun ("numfields", varargin)); ## Test that all the names are equal. idx = 0; diff -r de76baa76aa1 -r b83fca22bb4c scripts/geometry/voronoi.m --- a/scripts/geometry/voronoi.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/geometry/voronoi.m Fri Mar 07 13:02:43 2014 -0500 @@ -74,14 +74,13 @@ endif narg = 1; + hax = NaN; if (isscalar (varargin{1}) && ishandle (varargin{1})) hax = varargin{1}; - if (! isaxes (harg)) - error ("imagesc: HAX argument must be an axes object"); + if (! isaxes (hax)) + error ("voronoi: HAX argument must be an axes object"); endif narg++; - elseif (nargout < 2) - hax = gca (); endif if (nargin < 1 + narg || nargin > 3 + narg) @@ -108,6 +107,8 @@ if (length (x) != length (y)) error ("voronoi: X and Y must be vectors of the same length"); + elseif (length (x) < 2) + error ("voronoi: minimum of 2 points needed"); endif ## Add box to approximate rays to infinity. For Voronoi diagrams the @@ -142,19 +143,35 @@ edges = edges(:, [(edges(1, 1 :end - 1) != edges(1, 2 : end) | ... edges(2, 1 :end - 1) != edges(2, 2 : end)), true]); - ## Eliminate the edges of the diagram representing the box - poutside = (1:rows (p)) ... - (p(:, 1) < xmin - xdelta | p(:, 1) > xmax + xdelta | ... - p(:, 2) < ymin - ydelta | p(:, 2) > ymax + ydelta); - edgeoutside = ismember (edges(1, :), poutside) & ... - ismember (edges(2, :), poutside); - edges(:, edgeoutside) = []; + if (numel (x) > 2) + ## Eliminate the edges of the diagram representing the box + poutside = (1:rows (p)) ... + (p(:, 1) < xmin - xdelta | p(:, 1) > xmax + xdelta | ... + p(:, 2) < ymin - ydelta | p(:, 2) > ymax + ydelta); + edgeoutside = ismember (edges(1, :), poutside) & ... + ismember (edges(2, :), poutside); + edges(:, edgeoutside) = []; + else + ## look for the edge between the two given points + for edge = edges(1:2,:) + if (det ([[[1;1],p(edge,1:2)];1,x(1),y(1)]) + * det ([[[1;1],p(edge,1:2)];1,x(2),y(2)]) < 0) + edges = edge; + break; + endif + endfor + ## Use larger plot limits to make it more likely single bisector is shown. + xdelta = ydelta = max (xdelta, ydelta); + endif ## Get points of the diagram Vvx = reshape (p(edges, 1), size (edges)); Vvy = reshape (p(edges, 2), size (edges)); if (nargout < 2) + if (isnan (hax)) + hax = gca (); + endif h = plot (hax, Vvx, Vvy, linespec{:}, x, y, '+'); lim = [xmin, xmax, ymin, ymax]; axis (lim + 0.1 * [[-1, 1] * xdelta, [-1, 1] * ydelta]); @@ -179,5 +196,18 @@ %! assert (vx(2,:), zeros (1, columns (vx)), eps); %! assert (vy(2,:), zeros (1, columns (vy)), eps); -%% FIXME: Need input validation tests +%!testif HAVE_QHULL +%! ## Special case of just 2 points +%! x = [0 1]; y = [1 0]; +%! [vx, vy] = voronoi (x,y); +%! assert (vx, [-0.7; 1.7], eps); +%! assert (vy, [-0.7; 1.7], eps); +%% Input validation tests +%!error voronoi () +%!error voronoi (ones (3,1)) +%!error voronoi (ones (3,1), ones (3,1), "bogus1", "bogus2", "bogus3") +%!error voronoi (0, ones (3,1), ones (3,1)) +%!error voronoi (ones (3,1), ones (4,1)) +%!error voronoi (2.5, 3.5) + diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/errordlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/helpdlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/inputdlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/listdlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/msgbox.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/private/message_dialog.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/questdlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/gui/warndlg.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/help/help.m --- a/scripts/help/help.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/help/help.m Fri Mar 07 13:02:43 2014 -0500 @@ -163,7 +163,7 @@ found = false; - dlist = find_dir_in_path (name, "all"); + dlist = dir_in_loadpath (name, "all"); for i = 1:numel (dlist) fname = make_absolute_filename (fullfile (dlist{i}, "Contents.m")); diff -r de76baa76aa1 -r b83fca22bb4c scripts/help/which.m --- a/scripts/help/which.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/help/which.m Fri Mar 07 13:02:43 2014 -0500 @@ -28,9 +28,21 @@ if (nargin > 0 && iscellstr (varargin)) m = __which__ (varargin{:}); + ## Check whether each name is a variable, variables take precedence over + ## functions in name resolution. + for i = 1:nargin + m(i).is_variable = evalin ("caller", + ["exist (\"" m(i).name "\", \"var\")"], false); + if (m(i).is_variable) + m(i).file = "variable"; + endif + endfor + if (nargout == 0) for i = 1:nargin - if (isempty (m(i).file)) + if (m(i).is_variable) + printf ("'%s' is a variable\n", m(i).name); + elseif (isempty (m(i).file)) if (! isempty (m(i).type)) printf ("'%s' is a %s\n", m(i).name, m(i).type); @@ -64,3 +76,17 @@ %!assert (which ("_NO_SUCH_NAME_"), "") +%!test +%! x = 3; +%! str = which ("x"); +%! assert (str, "variable"); + +%!test +%! str = which ("amd"); +%! assert (str(end-6:end), "amd.oct"); +%! amd = 12; +%! str = which ("amd"); +%! assert (str, "variable"); +%! clear amd; +%! str = which ("amd"); +%! assert (str(end-6:end), "amd.oct"); diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/imfinfo.m --- a/scripts/image/imfinfo.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/imfinfo.m Fri Mar 07 13:02:43 2014 -0500 @@ -18,8 +18,8 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {@var{info} =} imfinfo (@var{filename}) -## @deftypefnx {Function File} {@var{info} =} imfinfo (@var{filename}, @var{ext}) ## @deftypefnx {Function File} {@var{info} =} imfinfo (@var{url}) +## @deftypefnx {Function File} {@var{info} =} imfinfo (@dots{}, @var{ext}) ## Read image information from a file. ## ## @code{imfinfo} returns a structure containing information about the image @@ -148,14 +148,32 @@ ## Author: Soren Hauberg -function info = imfinfo (varargin) +function info = imfinfo (filename, varargin) if (nargin < 1 || nargin > 2) print_usage (); - elseif (! ischar (varargin{1})) + elseif (! ischar (filename)) error ("imfinfo: FILENAME must be a string"); - elseif (nargin > 1 && ! ischar (varargin{2})) + elseif (nargin > 1 && ! ischar (ext)) error ("imfinfo: EXT must be a string"); endif - info = imageIO (@__imfinfo__, "info", varargin, varargin{:}); + info = imageIO ("imfinfo", @__imfinfo__, "info", filename, varargin{:}); endfunction +## This test is the same as the similar one in imread. imfinfo must check +## if file exists before calling __imfinfo_. This test confirm this. +%!testif HAVE_MAGICK +%! fmt = fmt_ori = imformats ("jpg"); +%! fmt.info = @true; +%! error_thrown = false; +%! imformats ("update", "jpg", fmt); +%! unwind_protect +%! try +%! imread ("I sure hope this file does not exist.jpg"); +%! catch +%! error_thrown = true; +%! end_try_catch +%! unwind_protect_cleanup +%! imformats ("update", "jpg", fmt_ori); +%! end_unwind_protect +%! assert (error_thrown, true); + diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/imformats.m --- a/scripts/image/imformats.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/imformats.m Fri Mar 07 13:02:43 2014 -0500 @@ -266,11 +266,10 @@ endfunction function match = find_ext_idx (formats, ext) - ## FIXME: is matlab sensitive to file extensions? ## XXX: what should we do if there's more than one hit? ## Should this function prevent the addition of ## duplicated extensions? - match = cellfun (@(x) any (strcmp (x, ext)), {formats.ext}); + match = cellfun (@(x) any (strcmpi (x, ext)), {formats.ext}); endfunction function bool = isa_magick (coder, filename) @@ -281,34 +280,68 @@ end_try_catch endfunction +## When imread or imfinfo are called, the file must exist or the +## function defined by imformats will never be called. Because +## of this, we must create a file for the tests to work. -## changing the function to read +## changing the function that does the reading %!testif HAVE_MAGICK -%! fmt = imformats ("jpg"); -%! fmt.read = @(x) size (x, 2); -%! imformats ("update", "jpg", fmt); -%! assert (imread ("this is 30 characters long.jpg"), 30); +%! fname = [tmpnam() ".jpg"]; +%! def_fmt = imformats (); +%! fid = fopen (fname, "w"); +%! unwind_protect +%! fmt = imformats ("jpg"); +%! fmt.read = @numel; +%! imformats ("update", "jpg", fmt); +%! assert (imread (fname), numel (fname)); +%! unwind_protect_cleanup +%! fclose (fid); +%! unlink (fname); +%! imformats (def_fmt); +%! end_unwind_protect ## adding a new format %!testif HAVE_MAGICK -%! fmt = imformats ("jpg"); -%! fmt.ext = "junk"; -%! fmt.read = @(x) true(); -%! imformats ("add", fmt); -%! assert (imread ("some file.junk"), true); +%! fname = [tmpnam() ".new_fmt"]; +%! def_fmt = imformats (); +%! fid = fopen (fname, "w"); +%! unwind_protect +%! fmt = imformats ("jpg"); # take jpg as template +%! fmt.ext = "new_fmt"; +%! fmt.read = @() true (); +%! imformats ("add", fmt); +%! assert (imread (fname), true); +%! unwind_protect_cleanup +%! fclose (fid); +%! unlink (fname); +%! imformats (def_fmt); +%! end_unwind_protect -## adding multiple formats in one way +## adding multiple formats at the same time %!testif HAVE_MAGICK -%! fmt = imformats ("jpg"); -%! fmt.ext = "junk1"; -%! fmt.read = @(x) true(); -%! fmt(2) = fmt(1); -%! fmt(2).ext = "junk2"; -%! imformats ("add", fmt); -%! assert (imread ("some file.junk1"), true); -%! assert (imread ("some file.junk2"), true); +%! fname1 = [tmpnam() ".new_fmt1"]; +%! fid1 = fopen (fname1, "w"); +%! fname2 = [tmpnam() ".new_fmt2"]; +%! fid2 = fopen (fname2, "w"); +%! def_fmt = imformats (); +%! unwind_protect +%! fmt = imformats ("jpg"); # take jpg as template +%! fmt.ext = "new_fmt1"; +%! fmt.read = @() true(); +%! fmt(2) = fmt(1); +%! fmt(2).ext = "new_fmt2"; +%! imformats ("add", fmt); +%! assert (imread (fname1), true); +%! assert (imread (fname2), true); +%! unwind_protect_cleanup +%! fclose (fid1); +%! fclose (fid2); +%! unlink (fname1); +%! unlink (fname2); +%! imformats (def_fmt); +%! end_unwind_protect -## changing format +## changing format and resetting back to default %!testif HAVE_MAGICK %! ori_fmt = mod_fmt = imformats ("jpg"); %! mod_fmt.description = "Another description"; @@ -319,10 +352,15 @@ %! new_fmt = imformats ("jpg"); %! assert (new_fmt.description, ori_fmt.description); -## FIXME: how to test for error together with testif? -## update to an invalid format -#%!testif HAVE_MAGICK -#%! fmt = imformats ("jpg"); -#%! fmt = rmfield (fmt, "read"); -#%! error imformats ("update", "jpg", fmt); +## updating to an invalid format should cause an error +%!testif HAVE_MAGICK +%! fmt = imformats ("jpg"); +%! fmt = rmfield (fmt, "read"); +%! error_thrown = false; +%! try +%! imformats ("update", "jpg", fmt); +%! catch +%! error_thrown = true; +%! end_try_catch +%! assert (error_thrown, true); diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/imread.m --- a/scripts/image/imread.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/imread.m Fri Mar 07 13:02:43 2014 -0500 @@ -23,16 +23,16 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{img}, @var{map}, @var{alpha}] =} imread (@var{filename}) -## @deftypefnx {Function File} {[@dots{}] =} imread (@var{filename}, @var{ext}) ## @deftypefnx {Function File} {[@dots{}] =} imread (@var{url}) +## @deftypefnx {Function File} {[@dots{}] =} imread (@dots{}, @var{ext}) ## @deftypefnx {Function File} {[@dots{}] =} imread (@dots{}, @var{idx}) ## @deftypefnx {Function File} {[@dots{}] =} imread (@dots{}, @var{param1}, @var{val1}, @dots{}) ## Read images from various file formats. ## ## Reads an image as a matrix from the file @var{filename}. If there is ## no file @var{filename}, and @var{ext} was specified, it will look for -## a file named @var{filename} and extension @var{ext}, i.e., a file named -## @var{filename}.@var{ext}. +## a file with the extension @var{ext}. Finally, it will attempt to download +## and read an image from @var{url}. ## ## The size and class of the output depends on the ## format of the image. A color image is returned as an @@ -88,23 +88,14 @@ ## Author: Stefan van der Walt ## Author: Andy Adler -function [img, varargout] = imread (varargin) +function [img, varargout] = imread (filename, varargin) if (nargin < 1) print_usage (); - elseif (! ischar (varargin{1})) + elseif (! ischar (filename)) error ("imread: FILENAME must be a string"); endif - ## In case the file format was specified as a separate argument we - ## do this. imageIO() will ignore the second part if filename on its - ## own is enough. And if the second argument was a parameter name instead - ## of an extension, it is still going to be passed to the next function - ## since we are passing the whole function input as well. - filename = {varargin{1}}; - if (nargin > 1 && ischar (varargin {2})) - filename{2} = varargin{2}; - endif - [img, varargout{1:nargout-1}] = imageIO (@__imread__, "read", filename, varargin{:}); + [img, varargout{1:nargout-1}] = imageIO ("imread", @__imread__, "read", filename, varargin{:}); endfunction @@ -139,3 +130,48 @@ %! assert (A(:,:,2), uint8 ([0, 255, 0; 255, 28, 255; 0, 255, 0])); %! assert (A(:,:,3), uint8 ([0, 255, 0; 255, 36, 255; 0, 255, 0])); +## If a file does not exist, it's the job of imread to check the file +## exists before sending it over to __imread__ or whatever function +## is defined in imformats to handle that specific format. This is the +## same in imfinfo. So in this test we replace one format in imformats +## with something that will not give an error if the file is missing +## and make sure we do get an error. +%!testif HAVE_MAGICK +%! fmt = fmt_ori = imformats ("jpg"); +%! fmt.read = @true; +%! error_thrown = false; +%! imformats ("update", "jpg", fmt); +%! unwind_protect +%! try +%! imread ("I sure hope this file does not exist.jpg"); +%! catch +%! error_thrown = true; +%! end_try_catch +%! unwind_protect_cleanup +%! imformats ("update", "jpg", fmt_ori); +%! end_unwind_protect +%! assert (error_thrown, true); + +## make one of the formats read, return what it received as input to +## confirm that the input parsing is working correcly +%!testif HAVE_MAGICK +%! fname = [tmpnam() ".jpg"]; +%! def_fmt = imformats (); +%! fid = fopen (fname, "w"); +%! unwind_protect +%! fmt = imformats ("jpg"); +%! fmt.read = @(varargin) varargin; +%! imformats ("update", "jpg", fmt); +%! assert (imread (fname), {fname}); +%! assert (imread (fname, "jpg"), {fname}); +%! assert (imread (fname(1:end-4), "jpg"), {fname}); +%! extra_inputs = {"some", 89, i, {6 7 8}}; +%! assert (imread (fname, extra_inputs{:}), {fname, extra_inputs{:}}); +%! assert (imread (fname, "jpg", extra_inputs{:}), {fname, extra_inputs{:}}); +%! assert (imread (fname(1:end-4), "jpg", extra_inputs{:}), {fname, extra_inputs{:}}); +%! unwind_protect_cleanup +%! fclose (fid); +%! unlink (fname); +%! imformats (def_fmt); +%! end_unwind_protect + diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/imwrite.m --- a/scripts/image/imwrite.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/imwrite.m Fri Mar 07 13:02:43 2014 -0500 @@ -100,7 +100,7 @@ fmt = imformats (ext); ## When there is no match, fmt will be a 1x1 structure with ## no fields, so we can't just use `isempty (fmt)'. - if (isempty (fieldnames (fmt))) + if (numfields (fmt) == 0) if (isempty (ext)) error ("imwrite: no extension found for %s to identify the image format", filename); diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/private/__imfinfo__.m --- a/scripts/image/private/__imfinfo__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/private/__imfinfo__.m Fri Mar 07 13:02:43 2014 -0500 @@ -17,56 +17,22 @@ ## along with Octave; see the file COPYING. If not, see ## . -## This function does al the work of imfinfo. It exists here as private +## This function does all the work of imfinfo. It exists here as private ## function so that imfinfo can use other functions if imformats is ## configured to. It is also needed so that imformats can create a ## function handle for it. ## Author: Soren Hauberg -function info = __imfinfo__ (filename, ext) +function info = __imfinfo__ (filename) - if (nargin < 1 || nargin > 2) + if (nargin != 1) print_usage ("imfinfo"); + elseif (! ischar (filename)) + error ("imfinfo: FILENAME must be a string"); endif - if (! ischar (filename)) - error ("imfinfo: FILENAME must be a string"); - elseif (nargin >= 2 && ! ischar (ext)) - error ("imfinfo: EXT must be a string"); - endif - filename = tilde_expand (filename); - - delete_file = false; - unwind_protect - - fn = file_in_path (IMAGE_PATH, filename); - if (isempty (fn)) - ## We couldn't find the file so... - if (nargin >= 2) - ## try adding a possible file extesion - filename = [filename "." ext]; - fn = file_in_path (IMAGE_PATH, filename); - if (isempty (fn)) - error ("imfinfo: cannot find file %s", filename); - endif - else - ## try filename as an URL - [fn, status, msg] = urlwrite (filename, tmpnam ()); - if (! status) - error ("imfinfo: cannot find or download %s: %s", filename, msg); - endif - delete_file = true; - endif - endif - - info = __magick_finfo__ (fn); - - unwind_protect_cleanup - if (delete_file) - unlink (fn); - endif - end_unwind_protect + info = __magick_finfo__ (filename); endfunction diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/private/__imread__.m --- a/scripts/image/private/__imread__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/private/__imread__.m Fri Mar 07 13:02:43 2014 -0500 @@ -44,18 +44,6 @@ ## keep track of the varargin offset we're looking at each moment offset = 1; - filename = tilde_expand (filename); - fn = file_in_path (IMAGE_PATH, filename); - if (isempty (fn) && nargin >= offset + 1 && ischar (varargin{offset})) - ## if we can't find the file, check if the next input is the file extension - filename = [filename "." varargin{offset}]; - fn = file_in_path (IMAGE_PATH, filename); - offset++; - endif - if (isempty (fn)) - error ("imread: cannot find %s", filename); - endif - ## It is possible for an file with multiple pages to have very different ## images on each page. Specifically, they may have different sizes. Because ## of this, we need to first find out the index of the images to read so @@ -90,114 +78,62 @@ endif endif - try - ## Use information from the first image to be read to set defaults. - if (ischar (options.index) && strcmpi (options.index, "all")) - info = __magick_ping__ (fn, 1); - else - info = __magick_ping__ (fn, options.index(1)); - endif + ## Use information from the first image to be read to set defaults. + if (ischar (options.index) && strcmpi (options.index, "all")) + info = __magick_ping__ (filename, 1); + else + info = __magick_ping__ (filename, options.index(1)); + endif - ## Set default for options. - options.region = {1:1:info.rows 1:1:info.columns}; + ## Set default for options. + options.region = {1:1:info.rows 1:1:info.columns}; + + for idx = offset:2:(numel (varargin) - offset + 1) + switch (tolower (varargin{idx})) - for idx = offset:2:(numel (varargin) - offset + 1) - switch (tolower (varargin{idx})) + case {"frames", "index"} + ## Do nothing. This options were already processed before the loop. - case {"frames", "index"} - ## Do nothing. This options were already processed before the loop. - - case "pixelregion", - options.region = varargin{idx+1}; - if (! iscell (options.region) || numel (options.region) != 2) - error ("imread: value for %s must be a 2 element cell array", + case "pixelregion", + options.region = varargin{idx+1}; + if (! iscell (options.region) || numel (options.region) != 2) + error ("imread: value for %s must be a 2 element cell array", + varargin{idx}); + endif + for reg_idx = 1:2 + if (numel (options.region{reg_idx}) == 3) + ## do nothing + elseif (numel (options.region{reg_idx}) == 2) + options.region{reg_idx}(3) = options.region{reg_idx}(2); + options.region{reg_idx}(2) = 1; + else + error ("imread: range for %s must be a 2 or 3 element vector", varargin{idx}); endif - for reg_idx = 1:2 - if (numel (options.region{reg_idx}) == 3) - ## do nothing - elseif (numel (options.region{reg_idx}) == 2) - options.region{reg_idx}(3) = options.region{reg_idx}(2); - options.region{reg_idx}(2) = 1; - else - error ("imread: range for %s must be a 2 or 3 element vector", - varargin{idx}); - endif - options.region{reg_idx} = floor (options.region{reg_idx}(1)): ... - floor (options.region{reg_idx}(2)): ... - floor (options.region{reg_idx}(3)); - endfor - if (options.region{1}(end) > info.rows) - error ("imread: end ROWS for PixelRegions option is larger than image height"); - elseif (options.region{2}(end) > info.columns) - error ("imread: end COLS for PixelRegions option is larger than image width"); - endif - - case "info", - ## We ignore this option. This parameter exists in Matlab to - ## speed up the reading of multipage TIFF by passing a structure - ## that contains information about the start on the file of each - ## page. We can't control it through GraphicsMagic but at least - ## we allow to load multiple pages with one command. - - otherwise - error ("imread: invalid PARAMETER `%s'", varargin{idx}); - - endswitch - endfor - - [varargout{1:nargout}] = __magick_read__ (fn, options); + options.region{reg_idx} = floor (options.region{reg_idx}(1)): ... + floor (options.region{reg_idx}(2)): ... + floor (options.region{reg_idx}(3)); + endfor + if (options.region{1}(end) > info.rows) + error ("imread: end ROWS for PixelRegions option is larger than image height"); + elseif (options.region{2}(end) > info.columns) + error ("imread: end COLS for PixelRegions option is larger than image width"); + endif - catch - ## If we can't read it with Magick, maybe the image is in Octave's - ## native image format. This is from back before Octave had 'imread' - ## and 'imwrite'. Then we had the functions 'loadimage' and 'saveimage'. - ## - ## This "image format" seems to be any file that can be read with - ## load() and contains 2 variables. The variable named "map" is a - ## colormap and must exist whether the image is indexed or not. The - ## other variable must be named "img" or "X" for a "normal" or - ## indexed image. - ## - ## FIXME: this has been deprecated for the next major release (3.8 or 4.0). - ## If someone wants to revive this as yet another image format, a - ## separate Octave package can be written for it, that register the - ## format through imformats. - - magick_error = lasterr (); - - img_field = false; - x_field = false; - map_field = false; + case "info", + ## We ignore this option. This parameter exists in Matlab to + ## speed up the reading of multipage TIFF by passing a structure + ## that contains information about the start on the file of each + ## page. We can't control it through GraphicsMagic but at least + ## we allow to load multiple pages with one command. - try - vars = load (fn); - if (isstruct (vars)) - img_field = isfield (vars, "img"); - x_field = isfield (vars, "X"); - map_field = isfield (vars, "map"); - endif - catch - error ("imread: invalid image file: %s", magick_error); - end_try_catch + otherwise + error ("imread: invalid PARAMETER `%s'", varargin{idx}); - if (map_field && (img_field || x_field)) - varargout{2} = vars.map; - if (img_field) - varargout{1} = vars.img; - else - varargout{1} = vars.X; - endif - persistent warned = false; - if (! warned) - warning ("Octave's native image format has been deprecated."); - warned = true; - endif - else - error ("imread: invalid Octave image file format"); - endif + endswitch + endfor - end_try_catch + [varargout{1:nargout}] = __magick_read__ (filename, options); endfunction @@ -205,10 +141,6 @@ ## can be defined in two places, but only in one place can it also be the ## string "all" function bool = is_valid_index_option (arg) - ## is the index option - bool = false; - if (isvector (arg) && isnumeric (arg) && isreal (arg)) - bool = true; - endif + bool = isvector (arg) && isnumeric (arg) && isreal (arg); endfunction diff -r de76baa76aa1 -r b83fca22bb4c scripts/image/private/imageIO.m --- a/scripts/image/private/imageIO.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/image/private/imageIO.m Fri Mar 07 13:02:43 2014 -0500 @@ -16,54 +16,111 @@ ## along with Octave; see the file COPYING. If not, see ## . -## This function simply connects imread and imfinfo() to the function -## to be used based on their format. It does it by checking the file extension -## of the file and redirecting to the appropriate function after checking -## with imformats. +## This function the image input functions imread() and imfinfo() to the +## functions that will actually be used, based on their format. See below +## on the details on how it identifies the format, and to what it defaults. +## +## It will change the input arguments that were passed to imread() and +## imfinfo(). It will change the filename to provide the absolute filepath +## for the file, it will extract the possible format name from the rest of +## the input arguments (in case there was one), and will give an error if +## the file can't be found. ## -## First argument is a function handle for the default imageIO function (what -## to use if the file extension for the image file is not listed by imformats). -## Second argument is the fieldname in the struct returned by imformats with a -## function handle for the function to use. Third argument is a cell array, its -## first element the filename, and the second, an optional file extension to -## add to filename, if filename alone does not exist. All the others are the -## original input arguments passed to the original imageIO function which will -## be passed on to the destination function. +## Usage: ## -## No input checking whatsoever is performed. That should be performed by the -## function calling it. - -function varargout = imageIO (core_func, fieldname, filename, varargin) +## func - Function name to use on error message. +## core_func - Function handle for the default function to use if we can't +## find the format in imformats. +## fieldname - Name of the field in the struct returned by imformats that +## has the function to use. +## filename - Most likely the first input argument from the function that +## called this. May be missing the file extension which can be +## on varargin. +## varargin - Followed by all the OTHER arguments passed to imread and +## imfinfo. - ## It should not be this function job to check if the file exists or not. - ## However, we need to know the file extension to use with imformats and - ## that means we need to know the actual filename that will be used which - ## is dependent on whether a file exists. - ## - ## If a file named filename{1} exists, then that's it, we will use that - ## wether it has an extension or not. If it does not exist and we have - ## something in filename{2}, then we will consider it the file extension. - ## Note the detail that if we find a file using filename{1} only, then we - ## should completely ignore filename{2}. It won't even be used by - ## imformats() at all, even if filename{1} has no extension to use with - ## imformats(). - if (isscalar (filename) || ! isempty (file_in_path (IMAGE_PATH, filename{1}))) - [~, ~, ext] = fileparts (filename{1}); - if (! isempty (ext)) - ## remove dot from extension - ext = ext(2:end); - endif - else - ext = filename{2}; +function varargout = imageIO (func, core_func, fieldname, filename, varargin) + + ## First thing: figure out the filename and possibly download it. + ## The first attempt is to try the filename and see if it exists. If it + ## does not, we try to add the next argument since the file extension can + ## be given as a separate argument. If we still can't find the file, it + ## can be a URL. Lastly, if we still didn't found a file, try adding the + ## extension to the URL + + file_2_delete = false; # will we have to remove the file in the end? + persistent abs_path = @(x) file_in_path (IMAGE_PATH, tilde_expand (x)); + + ## Filename was given with file extension + fn = abs_path (filename); + if (isempty (fn) && ! isempty (varargin)) + ## Maybe if we add a file extension + fn = abs_path ([filename "." varargin{1}]); endif - fmt = imformats (ext); - ## When there is no match, fmt will be a 1x1 structure with no fields, - ## so we can't just use `isempty (fmt)'. - if (isempty (fieldnames (fmt))) - [varargout{1:nargout}] = core_func (varargin{:}); - else - [varargout{1:nargout}] = fmt.(fieldname) (varargin{:}); + ## Maybe we have an URL + if (isempty (fn)) + file_2_delete = true; # mark file for deletion + [fn, ~] = urlwrite (filename, tmpnam ()); + ## Maybe the URL is missing the file extension + if (isempty (fn) && ! isempty (varargin)) + [fn, ~] = urlwrite ([filename "." varargin{1}], tmpnam ()); + endif + + if (isempty (fn)) + error ("%s: unable to find file %s", func, filename); + endif endif + + ## unwind_protect block because we may have a file to remove in the end + unwind_protect + + ## When guessing the format to use, we first check if the second + ## argument is a format defined in imformats. If so, we remove it + ## from the rest of arguments before passing them on. If not, we + ## try to guess the format from the file extension. Finally, if + ## we still don't know the format, we use the Octave core functions + ## which is the same for all formats. + foo = []; # the function we will use + + ## We check if the call to imformats (ext) worked using + ## "numfields (fmt) > 0 because when it fails, the returned + ## struct is not considered empty. + + ## try the second input argument + if (! isempty (varargin) && ischar (varargin{1})) + fmt = imformats (varargin{1}); + if (numfields (fmt) > 0) + foo = fmt.(fieldname); + varargin(1) = []; # remove format name from arguments + endif + endif + + ## try extension from file name + if (isempty (foo)) + [~, ~, ext] = fileparts (fn); + if (! isempty (ext)) + ## remove dot from extension + ext = ext(2:end); + endif + fmt = imformats (ext); + if (numfields (fmt) > 0) + foo = fmt.(fieldname); + endif + endif + + ## use the core function + if (isempty (foo)) + foo = core_func; + endif + + [varargout{1:nargout}] = foo (fn, varargin{:}); + + unwind_protect_cleanup + if (file_2_delete) + unlink (fn); + endif + end_unwind_protect + endfunction diff -r de76baa76aa1 -r b83fca22bb4c scripts/io/importdata.m --- a/scripts/io/importdata.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/io/importdata.m Fri Mar 07 13:02:43 2014 -0500 @@ -146,8 +146,7 @@ ## i.e., output = output.onlyFieldLeft ## Update the list of fields - fields = fieldnames (output); - if (numel (fields) == 1) + if (numfields (output) == 1) output = output.(fields{1}); endif endif diff -r de76baa76aa1 -r b83fca22bb4c scripts/linear-algebra/issymmetric.m --- a/scripts/linear-algebra/issymmetric.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/linear-algebra/issymmetric.m Fri Mar 07 13:02:43 2014 -0500 @@ -40,7 +40,8 @@ retval = isnumeric (x) && issquare (x); if (retval) if (tol == 0) - retval = all ((x == x.')(:)); + ## Handle large sparse matrices as well as full ones + retval = nnz (x != x.') == 0; else norm_x = norm (x, inf); retval = norm_x == 0 || norm (x - x.', inf) / norm_x <= tol; @@ -59,6 +60,7 @@ %!assert (issymmetric ([1, 2i; 2i, 1])) %!assert (! (issymmetric ("t"))) %!assert (! (issymmetric (["te"; "et"]))) +%!assert (issymmetric (speye (100000))) %!test %! s.a = 1; diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/cast.m --- a/scripts/miscellaneous/cast.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/cast.m Fri Mar 07 13:02:43 2014 -0500 @@ -19,27 +19,41 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} cast (@var{val}, @var{type}) ## Convert @var{val} to data type @var{type}. -## @seealso{int8, uint8, int16, uint16, int32, uint32, int64, uint64, double} +## +## The value @var{val} may be modified to fit within the range of the new type. +## +## Examples: +## +## @example +## @group +## cast (-5, "uint8") +## @result{} 0 +## cast (300, "int8") +## @result{} 127 +## @end group +## @end example +## +## @seealso{typecast, int8, uint8, int16, uint16, int32, uint32, int64, uint64, double, single, logical, char} ## @end deftypefn ## Author: jwe function retval = cast (val, typ) - if (nargin == 2) - if (ischar (typ)) - if (any (strcmp (typ, {"int8"; "uint8"; "int16"; "uint16"; - "int32"; "uint32"; "int64"; "uint64"; - "double"; "single"; "logical"; "char"}))) - retval = feval (typ, val); - else - error ("cast: type name '%s' is not a built-in type", typ); - endif + if (nargin != 2) + print_usage (); + endif + + if (ischar (typ)) + if (any (strcmp (typ, {"int8"; "uint8"; "int16"; "uint16"; + "int32"; "uint32"; "int64"; "uint64"; + "double"; "single"; "logical"; "char"}))) + retval = feval (typ, val); else - error ("cast: expecting TYPE name as second argument"); + error ("cast: type name '%s' is not a built-in type", typ); endif else - print_usage (); + error ("cast: expecting TYPE name as second argument"); endif endfunction diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/colon.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/genvarname.m diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/gzip.m --- a/scripts/miscellaneous/gzip.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/gzip.m Fri Mar 07 13:02:43 2014 -0500 @@ -58,10 +58,17 @@ %! error ("gzipped file cannot be found!"); %! endif %! gunzip (entry); -%! if (system (sprintf ("diff %s %s%c%s%s", filename, dirname, filesep, -%! basename, extension))) +%! fid = fopen (filename, "rb"); +%! assert (fid >= 0); +%! orig_data = fread (fid); +%! fclose (fid); +%! fid = fopen ([dirname filesep basename extension], "rb"); +%! assert (fid >= 0); +%! new_data = fread (fid); +%! fclose (fid); +%! if (orig_data != new_data) %! error ("unzipped file not equal to original file!"); -%! end +%! endif %! unwind_protect_cleanup %! delete (filename); %! delete ([dirname, filesep, basename, extension]); diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/inputname.m --- a/scripts/miscellaneous/inputname.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/inputname.m Fri Mar 07 13:02:43 2014 -0500 @@ -57,3 +57,8 @@ %!assert (inputname (1), "hello") %!assert (inputname (2), "worldly") +%!function r = foo (x, y) +%! r = inputname (2); +%!endfunction +%!assert (foo (pi, e), "e"); +%!assert (feval (@foo, pi, e), "e"); diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/ls.m --- a/scripts/miscellaneous/ls.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/ls.m Fri Mar 07 13:02:43 2014 -0500 @@ -61,14 +61,14 @@ if (nargin > 0) args = tilde_expand (varargin); if (ispc () && ! isunix ()) + idx = ! strncmp (args, '/', 1); + ## Enclose paths, potentially having spaces, in double quotes: + args(idx) = strcat ('"', args(idx), '"'); ## shell (cmd.exe) on MinGW uses '^' as escape character - args = regexprep (args, '([^\w.*? -])', '^$1'); - ## Strip UNIX directory character which looks like an option to dir cmd. - if (args{end}(end) == '/') - args{end}(end) = ""; - endif + args = regexprep (args, '([^\w.*?])', '^$1'); else - args = regexprep (args, '([^\w.*? -])', '\\$1'); + ## Escape any special characters in filename + args = regexprep (args, '([^\w.*?-[]])', '\\$1'); endif args = sprintf ("%s ", args{:}); else diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/mex.m --- a/scripts/miscellaneous/mex.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/mex.m Fri Mar 07 13:02:43 2014 -0500 @@ -23,8 +23,16 @@ ## @seealso{mkoctfile} ## @end deftypefn -function mex (varargin) - args = {"--mex", varargin{:}}; - mkoctfile (args{:}); +function retval = mex (varargin) + + [output, status] = mkoctfile ("--mex", varargin{:}); + + if (! isempty (output)) + disp (output); + endif + if (nargout > 0) + retval = status; + endif + endfunction diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/run.m --- a/scripts/miscellaneous/run.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/run.m Fri Mar 07 13:02:43 2014 -0500 @@ -31,9 +31,10 @@ ## falling back to the script name without an extension. ## ## Implementation Note: If @var{script} includes a path component, then -## @code{run} first changes the directory to the directory where @var{script} -## is found. @code{run} then executes the script, and returns to the original -## directory. +## @code{run} first changes the working directory to the directory where +## @var{script} is found. Next, the script is executed. Finally, @code{run} +## returns to the original working directory unless @code{script} has +## specifically changed directories. ## @seealso{path, addpath, source} ## @end deftypefn @@ -65,7 +66,9 @@ evalin ("caller", sprintf ('source ("%s%s");', f, ext), "rethrow (lasterror ())"); unwind_protect_cleanup - cd (wd); + if (strcmp (d, pwd ())) + cd (wd); + endif end_unwind_protect else error ("run: the path %s doesn't exist", d); diff -r de76baa76aa1 -r b83fca22bb4c scripts/miscellaneous/what.m --- a/scripts/miscellaneous/what.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/miscellaneous/what.m Fri Mar 07 13:02:43 2014 -0500 @@ -37,7 +37,7 @@ if (d(end) == '/' || d(end) == '\') d(end) = []; endif - dtmp = find_dir_in_path (d); + dtmp = dir_in_loadpath (d); if (isempty (dtmp)) error ("what: could not find the directory %s", d); endif @@ -45,7 +45,7 @@ d = dtmp; endif - files = dir (d); + files = readdir (d); w.path = d; w.m = cell (0, 1); w.mex = cell (0, 1); @@ -56,7 +56,7 @@ w.classes = cell (0, 1); for i = 1 : length (files) - n = files(i).name; + n = files{i}; ## Ignore . and .. if (strcmp (n, ".") || strcmp (n, "..")) continue; @@ -71,7 +71,7 @@ w.mex{end+1} = n; elseif (strcmp (e, ".mat")) w.mat{end+1} = n; - elseif (strcmp (n(1), "@")) + elseif (strcmp (n(1), "@") && isdir (n)) w.classes{end+1} = n; endif endif diff -r de76baa76aa1 -r b83fca22bb4c scripts/optimization/fminbnd.m --- a/scripts/optimization/fminbnd.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/optimization/fminbnd.m Fri Mar 07 13:02:43 2014 -0500 @@ -170,7 +170,7 @@ ## update a, b, v, w, and x - if (fu <= fval) + if (fu < fval) if (u < x) b = x; else @@ -283,4 +283,5 @@ %!assert (fminbnd (@(x) (x - 1e-3)^4, -1, 1, opt0), 1e-3, 10e-3*sqrt (eps)) %!assert (fminbnd (@(x) abs (x-1e7), 0, 1e10, opt0), 1e7, 10e7*sqrt (eps)) %!assert (fminbnd (@(x) x^2 + sin (2*pi*x), 0.4, 1, opt0), fzero (@(x) 2*x + 2*pi*cos (2*pi*x), [0.4, 1], opt0), sqrt (eps)) +%!assert (fminbnd (@(x) x > 0.3, 0, 1) < 0.3) diff -r de76baa76aa1 -r b83fca22bb4c scripts/optimization/fzero.m --- a/scripts/optimization/fzero.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/optimization/fzero.m Fri Mar 07 13:02:43 2014 -0500 @@ -100,7 +100,7 @@ ## Get default options if requested. if (nargin == 1 && ischar (fun) && strcmp (fun, 'defaults')) - x = optimset ("MaxIter", Inf, "MaxFunEvals", Inf, "TolX", 1e-8, + x = optimset ("MaxIter", Inf, "MaxFunEvals", Inf, "TolX", eps, "OutputFcn", [], "FunValCheck", "off"); return; endif @@ -117,7 +117,7 @@ ## displev = optimget (options, "Display", "notify"); funvalchk = strcmpi (optimget (options, "FunValCheck", "off"), "on"); outfcn = optimget (options, "OutputFcn"); - tolx = optimget (options, "TolX", 1e-8); + tolx = optimget (options, "TolX", eps); maxiter = optimget (options, "MaxIter", Inf); maxfev = optimget (options, "MaxFunEvals", Inf); @@ -302,7 +302,7 @@ endif ## If there's an output function, use it now. - if (outfcn) + if (! isempty (outfcn)) optv.funccount = nfev; optv.fval = fval; optv.iteration = niter; diff -r de76baa76aa1 -r b83fca22bb4c scripts/optimization/sqp.m --- a/scripts/optimization/sqp.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/optimization/sqp.m Fri Mar 07 13:02:43 2014 -0500 @@ -1,4 +1,5 @@ ## Copyright (C) 2005-2013 John W. Eaton +## Copyright (C) 2013 Arun Giridhar ## ## This file is part of Octave. ## @@ -128,8 +129,17 @@ ## ## @table @asis ## @item 101 -## The algorithm terminated normally. -## Either all constraints meet the requested tolerance, or the stepsize, +## The algorithm terminated normally. +## All constraints meet the specified tolerance. +## +## @item 102 +## The BFGS update failed. +## +## @item 103 +## The maximum number of iterations was reached. +## +## @item 104 +## The stepsize has become too small, i.e., ## @tex ## $\Delta x,$ ## @end tex @@ -137,12 +147,6 @@ ## delta @var{x}, ## @end ifnottex ## is less than @code{@var{tol} * norm (x)}. -## -## @item 102 -## The BFGS update failed. -## -## @item 103 -## The maximum number of iterations was reached. ## @end table ## ## An example of calling @code{sqp}: @@ -394,6 +398,8 @@ t3 = all (lambda_i >= 0); t4 = norm (lambda .* con); + ## Normal convergence. All constraints are satisfied + ## and objective has converged. if (t2 && t3 && max ([t0; t1; t4]) < tol) info = 101; break; @@ -408,8 +414,8 @@ info = INFO.info; - ## FIXME -- check QP solution and attempt to recover if it has - ## failed. For now, just warn about possible problems. + ## FIXME: check QP solution and attempt to recover if it has failed. + ## For now, just warn about possible problems. id = "Octave:SQP-QP-subproblem"; switch (info) @@ -453,8 +459,9 @@ delx = x_new - x; + ## Check if step size has become too small (indicates lack of progress). if (norm (delx) < tol * norm (x)) - info = 101; + info = 104; break; endif @@ -483,6 +490,8 @@ d2 = delxt*r; + ## Check if the next BFGS update will work properly. + ## If d1 or d2 vanish, the BFGS update will fail. if (d1 == 0 || d2 == 0) info = 102; break; @@ -510,6 +519,7 @@ endwhile + ## Check if we've spent too many iterations without converging. if (iter >= iter_max) info = 103; endif diff -r de76baa76aa1 -r b83fca22bb4c scripts/pkg/module.mk --- a/scripts/pkg/module.mk Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/pkg/module.mk Fri Mar 07 13:02:43 2014 -0500 @@ -5,6 +5,7 @@ pkg/private/configure_make.m \ pkg/private/copy_files.m \ pkg/private/create_pkgadddel.m \ + pkg/private/default_prefix.m \ pkg/private/describe.m \ pkg/private/dirempty.m \ pkg/private/extract_pkg.m \ diff -r de76baa76aa1 -r b83fca22bb4c scripts/pkg/pkg.m --- a/scripts/pkg/pkg.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/pkg/pkg.m Fri Mar 07 13:02:43 2014 -0500 @@ -280,14 +280,7 @@ global_install = ((ispc () && ! isunix ()) || (geteuid () == 0)); if (isbool (prefix)) - if (global_install) - prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); - archprefix = fullfile (octave_config_info ("libdir"), - "octave", "packages"); - else - prefix = fullfile ("~", "octave"); - archprefix = prefix; - endif + [prefix, archprefix] = default_prefix (global_install); prefix = tilde_expand (prefix); archprefix = tilde_expand (archprefix); endif @@ -326,15 +319,12 @@ case "-local" global_install = false; if (! user_prefix) - prefix = tilde_expand (fullfile ("~", "octave")); - archprefix = prefix; + [prefix, archprefix] = default_prefix (global_install); endif case "-global" global_install = true; if (! user_prefix) - prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); - archprefix = fullfile (octave_config_info ("libdir"), - "octave", "packages"); + [prefix, archprefix] = default_prefix (global_install); endif case available_actions if (strcmp (action, "none")) diff -r de76baa76aa1 -r b83fca22bb4c scripts/pkg/private/configure_make.m --- a/scripts/pkg/private/configure_make.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/pkg/private/configure_make.m Fri Mar 07 13:02:43 2014 -0500 @@ -32,11 +32,6 @@ mkoctfile_program = fullfile (octave_bindir, sprintf ("mkoctfile-%s%s", ver, ext)); octave_config_program = fullfile (octave_bindir, sprintf ("octave-config-%s%s", ver, ext)); octave_binary = fullfile (octave_bindir, sprintf ("octave-%s%s", ver, ext)); - cenv = {"MKOCTFILE"; mkoctfile_program; - "OCTAVE_CONFIG"; octave_config_program; - "OCTAVE"; octave_binary; - "INSTALLDIR"; desc.dir}; - scenv = sprintf ("%s=\"%s\" ", cenv{:}); if (! exist (mkoctfile_program, "file")) __gripe_missing_component__ ("pkg", "mkoctfile"); @@ -48,6 +43,16 @@ __gripe_missing_component__ ("pkg", "octave"); endif + if (verbose) + mkoctfile_program = [mkoctfile_program " --verbose"]; + endif + + cenv = {"MKOCTFILE"; mkoctfile_program; + "OCTAVE_CONFIG"; octave_config_program; + "OCTAVE"; octave_binary; + "INSTALLDIR"; desc.dir}; + scenv = sprintf ("%s=\"%s\" ", cenv{:}); + ## Configure. if (exist (fullfile (src, "configure"), "file")) flags = ""; diff -r de76baa76aa1 -r b83fca22bb4c scripts/pkg/private/default_prefix.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/pkg/private/default_prefix.m Fri Mar 07 13:02:43 2014 -0500 @@ -0,0 +1,35 @@ +## Copyright (C) 2014 Carlo de Falco +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{prefix}, @var{archprefix} =} @ +## default_prefix (@var{global_install}) +## Undocumented internal function. +## @end deftypefn + +function [prefix, archprefix] = default_prefix (global_install) + if (global_install) + prefix = fullfile (OCTAVE_HOME (), "share", "octave", "packages"); + archprefix = fullfile (octave_config_info ("libdir"), "octave", + "packages", [desc.name "-" desc.version]); + else + prefix = tilde_expand (fullfile ("~", "octave")); + archprefix = prefix; + endif +endfunction + diff -r de76baa76aa1 -r b83fca22bb4c scripts/pkg/private/getarchprefix.m --- a/scripts/pkg/private/getarchprefix.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/pkg/private/getarchprefix.m Fri Mar 07 13:02:43 2014 -0500 @@ -24,8 +24,7 @@ function archprefix = getarchprefix (desc, global_install) if (global_install) - archprefix = fullfile (octave_config_info ("libdir"), "octave", - "packages", [desc.name "-" desc.version]); + [~, archprefix] = default_prefix (global_install); else archprefix = desc.dir; endif diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/appearance/datetick.m --- a/scripts/plot/appearance/datetick.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/appearance/datetick.m Fri Mar 07 13:02:43 2014 -0500 @@ -45,8 +45,8 @@ unwind_protect ## FIXME: This will bring the axes to the top of the stack. - ## This may not always be desirable if there are multiple axes - ## objects. + ## This may not be desirable if there are multiple axes objects, + ## such as can occur with plotyy. axes (hax); __datetick__ (varargin{:}); unwind_protect_cleanup diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/appearance/diffuse.m --- a/scripts/plot/appearance/diffuse.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/appearance/diffuse.m Fri Mar 07 13:02:43 2014 -0500 @@ -18,11 +18,11 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} diffuse (@var{sx}, @var{sy}, @var{sz}, @var{lv}) -## Calculate diffuse reflection strength of a surface defined by the normal +## Calculate the diffuse reflection strength of a surface defined by the normal ## vector elements @var{sx}, @var{sy}, @var{sz}. ## -## The light source location vector @var{lv} can be given as 2-element vector -## [azimuth, elevation] in degrees or as 3-element vector [lx, ly, lz]. +## The light source location vector @var{lv} can be given as a 2-element vector +## [azimuth, elevation] in degrees or as a 3-element vector [x, y, z]. ## @seealso{specular, surfl} ## @end deftypefn @@ -34,13 +34,13 @@ print_usage (); endif - ## check for normal vector - if (!size_equal (sx, sy, sz)) - error ("diffuse: SX, SY, and SZ must have same size"); + ## Check normal vectors + if (! size_equal (sx, sy, sz)) + error ("diffuse: SX, SY, and SZ must be the same size"); endif - ## check for light vector (lv) argument - if (length (lv) < 2 || length (lv) > 3) + ## Check light vector (lv) argument + if (! isvector (lv) || length (lv) < 2 || length (lv) > 3) error ("diffuse: light vector LV must be a 2- or 3-element vector"); elseif (length (lv) == 2) [lv(1), lv(2), lv(3)] = sph2cart (lv(1) * pi/180, lv(2) * pi/180, 1.0); @@ -48,7 +48,7 @@ ## Normalize view and light vector. if (sum (abs (lv)) > 0) - lv /= norm (lv); + lv /= norm (lv); endif ns = sqrt (sx.^2 + sy.^2 + sz.^2); diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/appearance/legend.m --- a/scripts/plot/appearance/legend.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/appearance/legend.m Fri Mar 07 13:02:43 2014 -0500 @@ -829,10 +829,11 @@ case "line" color = get (hplots(k), "color"); style = get (hplots(k), "linestyle"); + lwidth = min (get (hplots(k), "linewidth"), 5); if (! strcmp (style, "none")) l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3), "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4), - "color", color, "linestyle", style, + "color", color, "linestyle", style, "linewidth", lwidth, "marker", "none", "userdata", hplots(k)); hobjects(end+1) = l1; @@ -841,11 +842,11 @@ if (! strcmp (marker, "none")) l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3), "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4), - "color", color, "linestyle", "none", + "color", color, "linestyle", "none", "linewidth", lwidth, "marker", marker, "markeredgecolor",get (hplots(k), "markeredgecolor"), "markerfacecolor",get (hplots(k), "markerfacecolor"), - "markersize", get (hplots(k), "markersize"), + "markersize", min (get (hplots(k), "markersize"),10), "userdata", hplots(k)); hobjects(end+1) = l1; endif @@ -855,6 +856,8 @@ {@updateline, hlegend, linelength, false}); addlistener (hplots(k), "linestyle", {@updateline, hlegend, linelength, false}); + addlistener (hplots(k), "linewidth", + {@updateline, hlegend, linelength, false}); addlistener (hplots(k), "marker", {@updateline, hlegend, linelength, false}); addlistener (hplots(k), "markeredgecolor", @@ -1149,6 +1152,7 @@ if (ishandle (hplots(i)) && strcmp (get (hplots(i), "type"), "line")) dellistener (hplots(i), "color"); dellistener (hplots(i), "linestyle"); + dellistener (hplots(i), "linewidth"); dellistener (hplots(i), "marker"); dellistener (hplots(i), "markeredgecolor"); dellistener (hplots(i), "markerfacecolor"); @@ -1198,14 +1202,18 @@ if (! strcmp (linestyle, "none")) line ("xdata", xpos1, "ydata", ypos1, "color", get (h, "color"), - "linestyle", get (h, "linestyle"), "marker", "none", + "linestyle", get (h, "linestyle"), + "linewidth", min (get (h, "linewidth"), 5), + "marker", "none", "userdata", h, "parent", hlegend); endif if (! strcmp (marker, "none")) line ("xdata", xpos2, "ydata", ypos2, "color", get (h, "color"), "marker", marker, "markeredgecolor", get (h, "markeredgecolor"), "markerfacecolor", get (h, "markerfacecolor"), - "markersize", get (h, "markersize"), "linestyle", "none", + "markersize", min (get (h, "markersize"), 10), + "linestyle", "none", + "linewidth", min (get (h, "linewidth"), 5), "userdata", h, "parent", hlegend); endif endif diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/appearance/specular.m --- a/scripts/plot/appearance/specular.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/appearance/specular.m Fri Mar 07 13:02:43 2014 -0500 @@ -19,15 +19,17 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} specular (@var{sx}, @var{sy}, @var{sz}, @var{lv}, @var{vv}) ## @deftypefnx {Function File} {} specular (@var{sx}, @var{sy}, @var{sz}, @var{lv}, @var{vv}, @var{se}) -## Calculate specular reflection strength of a surface defined by the normal -## vector elements @var{sx}, @var{sy}, @var{sz} using Phong's approximation. +## Calculate the specular reflection strength of a surface defined by the +## normal vector elements @var{sx}, @var{sy}, @var{sz} using Phong's +## approximation. ## -## The light source location and viewer location vectors can be specified using -## parameter @var{lv} and @var{vv} respectively. The location vectors can +## The light source location and viewer location vectors are specified using +## parameters @var{lv} and @var{vv} respectively. The location vectors can ## given as 2-element vectors [azimuth, elevation] in degrees or as 3-element ## vectors [x, y, z]. ## -## An optional sixth argument describes the specular exponent (spread) @var{se}. +## An optional sixth argument specifies the specular exponent (spread) @var{se}. +## If not given, @var{se} defaults to 10. ## @seealso{diffuse, surfl} ## @end deftypefn @@ -39,54 +41,52 @@ print_usage (); endif - ## Checks for specular exponent (se). - if (nargin < 6) - se = 10; - else - if (!isnumeric (se) || numel (se) != 1 || se <= 0) - error ("specular: exponent must be positive scalar"); - endif + ## Check normal vectors + if (! size_equal (sx, sy, sz)) + error ("specular: SX, SY, and SZ must be the same size"); endif - ## Checks for normal vector. - if (!size_equal (sx, sy, sz)) - error ("specular: SX, SY, and SZ must have same size"); - endif - - ## Check for light vector (lv) argument. - if (length (lv) < 2 || length (lv) > 3) + ## Check light vector (lv) argument + if (! isvector (lv) || length (lv) < 2 || length (lv) > 3) error ("specular: light vector LV must be a 2- or 3-element vector"); elseif (length (lv) == 2) [lv(1), lv(2), lv(3)] = sph2cart (lv(1) * pi/180, lv(2) * pi/180, 1.0); endif - ## Check for view vector (vv) argument. - if (length (vv) < 2 || length (lv) > 3) + ## Check view vector (vv) argument + if (! isvector (vv) || length (vv) < 2 || length (lv) > 3) error ("specular: view vector VV must be a 2- or 3-element vector"); elseif (length (vv) == 2) [vv(1), vv(2), vv(3)] = sph2cart (vv(1) * pi / 180, vv(2) * pi / 180, 1.0); endif - ## Normalize view and light vector. + ## Check specular exponent (se) argument + if (nargin < 6) + se = 10; + elseif (! (isnumeric (se) && numel (se) == 1 && se > 0)) + error ("specular: exponent SE must be a positive scalar"); + endif + + ## Normalize view and light vectors if (sum (abs (lv)) > 0) - lv /= norm (lv); + lv /= norm (lv); endif if (sum (abs (vv)) > 0) - vv /= norm (vv); + vv /= norm (vv); endif - ## Calculate normal vector lengths and dot-products. + ## Calculate normal vector lengths and dot-products ns = sqrt (sx.^2 + sy.^2 + sz.^2); l_dot_n = (sx * lv(1) + sy * lv(2) + sz * lv(3)) ./ ns; v_dot_n = (sx * vv(1) + sy * vv(2) + sz * vv(3)) ./ ns; - ## Calculate specular reflection using Phong's approximation. + ## Calculate specular reflection using Phong's approximation retval = 2 * l_dot_n .* v_dot_n - dot (lv, vv); - ## Set zero if light is on the other side. + ## Set reflectance to zero if light is on the other side retval(l_dot_n < 0) = 0; - ## Allow postive values only. + ## Allow postive values only retval(retval < 0) = 0; retval = retval .^ se; diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/fill.m --- a/scripts/plot/draw/fill.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/fill.m Fri Mar 07 13:02:43 2014 -0500 @@ -92,17 +92,28 @@ set (hax, "nextplot", "add"); for i = 1 : length (iargs) + x = varargin{iargs(i)}; + y = varargin{iargs(i) + 1}; cdata = varargin{iargs(i) + 2}; + + if (! size_equal (x,y)) + if (iscolumn (y) && rows (y) == rows (x)) + y = repmat (y, [1, columns(x)]); + elseif (iscolumn (x) && rows (x) == rows (y)) + x = repmat (x, [1, columns(y)]); + else + error ("fill: X annd Y must have same number of rows"); + endif + endif ## For Matlab compatibility, replicate cdata to match size of data - if (iscolumn (cdata)) - sz = size (varargin{iargs(i)}); + if (iscolumn (cdata) && ! ischar (cdata)) + sz = size (x); if (all (sz > 1)) cdata = repmat (cdata, [1, sz(2)]); endif endif - [htmp, fail] = __patch__ (hax, varargin{iargs(i)+(0:1)}, cdata, - opts{:}); + [htmp, fail] = __patch__ (hax, x, y, cdata, opts{:}); if (fail) print_usage (); endif @@ -160,4 +171,30 @@ %! x2 = sin (t2) + 0.8; %! y2 = cos (t2); %! h = fill (x1,y1,'r', x2,y2,'g'); +%! title ({'fill() function'; 'cdata specified with string'}); +%!demo +%! clf; +%! t1 = (1/16:1/8:1) * 2*pi; +%! t2 = ((1/16:1/8:1) + 1/32) * 2*pi; +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); +%! h = fill (x1,y1,1, x2,y2,2); +%! title ({'fill() function'; 'cdata = row vector produces FaceColor = "flat"'}); + +%!demo +%! clf; +%! x = [0 0 +%! 1 0.5 +%! 1 0.5 +%! 0 0]; +%! y = [0 0 +%! 0 0 +%! 1 0.5 +%! 1 0.5]; +%! c = [1 2 3 4]'; +%! fill (x, y, c); +%! title ({'fill() function'; 'cdata = column vector produces FaceColor = "interp"'}); + diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/plotyy.m --- a/scripts/plot/draw/plotyy.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/plotyy.m Fri Mar 07 13:02:43 2014 -0500 @@ -22,7 +22,7 @@ ## @deftypefnx {Function File} {} plotyy (@dots{}, @var{fun1}, @var{fun2}) ## @deftypefnx {Function File} {} plotyy (@var{hax}, @dots{}) ## @deftypefnx {Function File} {[@var{ax}, @var{h1}, @var{h2}] =} plotyy (@dots{}) -## Plot two sets of data with independent y-axes. +## Plot two sets of data with independent y-axes and a common x-axis. ## ## The arguments @var{x1} and @var{y1} define the arguments for the first plot ## and @var{x1} and @var{y2} for the second. @@ -40,7 +40,7 @@ ## the principal axis in which to plot the @var{x1} and @var{y1} data. ## ## The return value @var{ax} is a vector with the axis handles of the two -## y axes. @var{h1} and @var{h2} are handles to the objects generated by the +## y-axes. @var{h1} and @var{h2} are handles to the objects generated by the ## plot commands. ## ## @example @@ -57,113 +57,66 @@ ## @seealso{plot} ## @end deftypefn -function [Ax, H1, H2] = plotyy (varargin) +function [ax, h1, h2] = plotyy (varargin) - ## Don't use __plt_get_axis_arg__ here as ax is a two vector for plotyy - if (nargin > 1 && length (varargin{1}) == 2 && ishandle (varargin{1}(1)) - && ishandle (varargin{1}(2)) - && all (floor (varargin{1}) != varargin{1})) - obj1 = get (varargin{1}(1)); - obj2 = get (varargin{1}(2)); - if (strcmp (obj1.type, "axes") || strcmp (obj2.type, "axes")) - ax = [obj1, obj2]; - varargin(1) = []; - if (isempty (varargin)) - varargin = {}; - endif - else - error ("plotyy: expecting first argument to be axes handle"); - endif - oldh = gca (); - else - f = get (0, "currentfigure"); - if (isempty (f)) - f = figure (); - endif - ca = get (f, "currentaxes"); - if (isempty (ca)) - ax = []; - elseif (ishandle (ca) && isprop (ca, "__plotyy_axes__")) - ax = get (ca, "__plotyy_axes__"); - else - ax = ca; - endif - if (length (ax) > 2) - for i = 3 : length (ax) - delete (ax (i)); - endfor - ax = ax(1:2); - elseif (length (ax) == 1) - ax(2) = axes (); - set (ax(2), "nextplot", get (ax(1), "nextplot")); - elseif (isempty (ax)) - ax(1) = axes (); - ax(2) = axes (); - ca = ax(2); - endif - if (nargin < 2) - varargin = {}; - endif - oldh = ca; - endif + [hax, varargin] = __plt_get_axis_arg__ ("plotyy", varargin{:}); - if (nargin < 4) + nargin = numel (varargin); + if (nargin < 4 || nargin > 6) print_usage (); endif + oldfig = []; + if (! isempty (hax)) + oldfig = get (0, "currentfigure"); + endif unwind_protect - [ax, h1, h2] = __plotyy__ (ax, varargin{:}); + hax = newplot (hax); + + ## FIXME: Second conditional test shouldn't be required. + ## 'cla reset' needs to delete user properties like __plotyy_axes__. + if (isprop (hax, "__plotyy_axes__") + && isaxes (get (hax, "__plotyy_axes__")) == [true true]) + hax = get (hax, "__plotyy_axes__"); + else + hax(2) = axes ("nextplot", get (hax(1), "nextplot")); + endif + + [axtmp, h1tmp, h2tmp] = __plotyy__ (hax, varargin{:}); + + set (gcf, "currentaxes", hax(1)); + unwind_protect_cleanup - ## Only change back to the old axis if we didn't delete it - if (isaxes (oldh)) - axes (oldh); + if (! isempty (oldfig)) + set (0, "currentfigure", oldfig); endif end_unwind_protect if (nargout > 0) - Ax = ax; - H1 = h1; - H2 = h2; + ax = axtmp; + h1 = h1tmp; + h2 = h2tmp; endif endfunction -function [ax, h1, h2] = __plotyy__ (ax, x1, y1, x2, y2, varargin) - if (nargin > 5) - fun1 = varargin{1}; - else - fun1 = @plot; - endif - if (nargin > 6) - fun2 = varargin{2}; - else +function [ax, h1, h2] = __plotyy__ (ax, x1, y1, x2, y2, fun1 = @plot, fun2) + + if (nargin < 7) fun2 = fun1; endif xlim = [min([x1(:); x2(:)]), max([x1(:); x2(:)])]; - if (isaxes (ax(1))) - axes (ax(1)); - else - ax(1) = axes (); - endif - newplot (); + axes (ax(1)); + h1 = feval (fun1, x1, y1); - set (ax(1), "ycolor", getcolor (h1(1))); - set (ax(1), "xlim", xlim); - set (ax(1), "color", "none"); - - cf = gcf (); - set (cf, "nextplot", "add"); + set (ax(1), "color", "none", "ycolor", getcolor (h1(1)), "xlim", xlim); - if (isaxes (ax(2))) - axes (ax(2)); - else - ax(2) = axes (); - set (ax(2), "nextplot", get (ax(1), "nextplot")); - endif - newplot (); + set (gcf (), "nextplot", "add"); + + axes (ax(2)); colors = get (ax(1), "colororder"); set (ax(2), "colororder", [colors(2:end,:); colors(1,:)]); @@ -174,35 +127,38 @@ set (ax, "activepositionproperty", "position"); endif - ## Kluge, until __plt_get_axis_arg__ and newplot are reworked. - set (ax(2), "nextplot", "replacechildren"); + ## Don't replace axis which has colororder property already modified + if (strcmp (get (ax(1), "nextplot"), "replace")) + set (ax(2), "nextplot", "replacechildren"); + endif h2 = feval (fun2, ax(2), x2, y2); - set (ax(2), "yaxislocation", "right"); - set (ax(2), "ycolor", getcolor (h2(1))); + + set (ax(2), "yaxislocation", "right", "color", "none", + "ycolor", getcolor (h2(1)), "box", "off", "xlim", xlim); if (strcmp (get(ax(1), "activepositionproperty"), "position")) set (ax(2), "position", get (ax(1), "position")); else - set (ax(2), "outerposition", get (ax(1), "outerposition")); - set (ax(2), "looseinset", get (ax(1), "looseinset")); + set (ax(2), {"outerposition", "looseinset"}, + get (ax(1), {"outerposition", "looseinset"})); endif - set (ax(2), "xlim", xlim); - set (ax(2), "color", "none"); - set (ax(2), "box", "off"); + ## Restore nextplot value by copying value from axis #1 + set (ax(2), "nextplot", get (ax(1), "nextplot")); ## Add invisible text objects that when destroyed, ## also remove the other axis t1 = text (0, 0, "", "parent", ax(1), "tag", "plotyy", - "handlevisibility", "off", "visible", "off", + "visible", "off", "handlevisibility", "off", "xliminclude", "off", "yliminclude", "off"); t2 = text (0, 0, "", "parent", ax(2), "tag", "plotyy", - "handlevisibility", "off", "visible", "off", + "visible", "off", "handlevisibility", "off", "xliminclude", "off", "yliminclude", "off"); set (t1, "deletefcn", {@deleteplotyy, ax(2), t2}); set (t2, "deletefcn", {@deleteplotyy, ax(1), t1}); + ## Add cross-listeners so a change in one axes' attributes updates the other. addlistener (ax(1), "position", {@update_position, ax(2)}); addlistener (ax(2), "position", {@update_position, ax(1)}); addlistener (ax(1), "outerposition", {@update_position, ax(2)}); @@ -235,6 +191,80 @@ endif endfunction +function deleteplotyy (h, ~, ax2, t2) + if (isaxes (ax2) + && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"), "off")) + && strcmp (get (ax2, "beingdeleted"), "off")) + set (t2, "deletefcn", []); + delete (ax2); + endif +endfunction + +function update_nextplot (h, ~, ax2) + persistent recursion = false; + if (! recursion) + unwind_protect + recursion = true; + set (ax2, "nextplot", get (h, "nextplot")); + unwind_protect_cleanup + recursion = false; + end_unwind_protect + endif +endfunction + +function update_position (h, ~, ax2) + persistent recursion = false; + + ## Don't allow recursion + if (! recursion) + unwind_protect + recursion = true; + view = get (h, "view"); + oldview = get (ax2, "view"); + plotboxaspectratio = get (h, "plotboxaspectratio"); + oldplotboxaspectratio = get (ax2, "plotboxaspectratio"); + plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); + oldplotboxaspectratiomode = get (ax2, "plotboxaspectratiomode"); + + if (strcmp (get (h, "activepositionproperty"), "position")) + position = get (h, "position"); + oldposition = get (ax2, "position"); + if (! (isequal (position, oldposition) && isequal (view, oldview))) + set (ax2, "position", position, "view", view); + endif + else + outerposition = get (h, "outerposition"); + oldouterposition = get (ax2, "outerposition"); + if (! (isequal (outerposition, oldouterposition) + && isequal (view, oldview))) + set (ax2, "outerposition", outerposition, "view", view); + endif + endif + + if (! (isequal (plotboxaspectratio, oldplotboxaspectratio) + && isequal (plotboxaspectratiomode, oldplotboxaspectratiomode))) + set (ax2, "plotboxaspectratio", plotboxaspectratio, + "plotboxaspectratiomode", plotboxaspectratiomode); + endif + unwind_protect_cleanup + recursion = false; + end_unwind_protect + endif +endfunction + +function color = getcolor (ax) + obj = get (ax); + if (isfield (obj, "color")) + color = obj.color; + elseif (isfield (obj, "facecolor") && ! ischar (obj.facecolor)) + color = obj.facecolor; + elseif (isfield (obj, "edgecolor") && ! ischar (obj.edgecolor)) + color = obj.edgecolor; + else + color = [0, 0, 0]; + endif +endfunction + %!demo %! clf; @@ -245,12 +275,11 @@ %! xlabel ('X'); %! ylabel (ax(1), 'Axis 1'); %! ylabel (ax(2), 'Axis 2'); -%! axes (ax(1)); %! text (0.5, 0.5, 'Left Axis', ... -%! 'color', [0 0 1], 'horizontalalignment', 'center'); -%! axes (ax(2)); +%! 'color', [0 0 1], 'horizontalalignment', 'center', 'parent', ax(1)); %! text (4.5, 80, 'Right Axis', ... -%! 'color', [0 0.5 0], 'horizontalalignment', 'center'); +%! 'color', [0 0.5 0], 'horizontalalignment', 'center', 'parent', ax(2)); +%! title ({"plotyy() example"; "Left axis uses @plot, Right axis uses @semilogy"}); %!demo %! clf; @@ -267,14 +296,6 @@ %! axis square; %!demo -%! clf; -%! x = linspace (-1, 1, 201); -%! hax = plotyy (x, sin (pi*x), x, cos (pi*x)); -%! ylabel (hax(1), 'Blue on the Left'); -%! ylabel (hax(2), 'Green on the Right'); -%! xlabel ('xlabel'); - -%!demo %! clf %! hold on %! t = (0:0.1:9); @@ -284,81 +305,7 @@ %! [~, h3, h4] = plotyy (t+1, x, t+1, y); %! set ([h3, h4], 'linestyle', '--'); %! xlabel (hax(1), 'xlabel'); -%! title (hax(2), 'title'); +%! title (hax(2), 'Two plotyy graphs on same figure using "hold on"'); %! ylabel (hax(1), 'Left axis is Blue'); %! ylabel (hax(2), 'Right axis is Green'); -function deleteplotyy (h, d, ax2, t2) - if (isaxes (ax2) - && (isempty (gcbf ()) || strcmp (get (gcbf (), "beingdeleted"),"off")) - && strcmp (get (ax2, "beingdeleted"), "off")) - set (t2, "deletefcn", []); - delete (ax2); - endif -endfunction - -function update_nextplot (h, d, ax2) - persistent recursion = false; - prop = "nextplot"; - if (! recursion) - unwind_protect - recursion = true; - set (ax2, prop, get (h, prop)); - unwind_protect_cleanup - recursion = false; - end_unwind_protect - endif -endfunction - -function update_position (h, d, ax2) - persistent recursion = false; - - ## Don't allow recursion - if (! recursion) - unwind_protect - recursion = true; - view = get (h, "view"); - oldview = get (ax2, "view"); - plotboxaspectratio = get (h, "plotboxaspectratio"); - oldplotboxaspectratio = get (ax2, "plotboxaspectratio"); - plotboxaspectratiomode = get (h, "plotboxaspectratiomode"); - oldplotboxaspectratiomode = get (ax2, "plotboxaspectratiomode"); - - if (strcmp (get(h, "activepositionproperty"), "position")) - position = get (h, "position"); - oldposition = get (ax2, "position"); - if (! (isequal (position, oldposition) && isequal (view, oldview))) - set (ax2, "position", position, "view", view); - endif - else - outerposition = get (h, "outerposition"); - oldouterposition = get (ax2, "outerposition"); - if (! (isequal (outerposition, oldouterposition) && isequal (view, oldview))) - set (ax2, "outerposition", outerposition, "view", view); - endif - endif - - if (! (isequal (plotboxaspectratio, oldplotboxaspectratio) - && isequal (plotboxaspectratiomode, oldplotboxaspectratiomode))) - set (ax2, "plotboxaspectratio", plotboxaspectratio); - set (ax2, "plotboxaspectratiomode", plotboxaspectratiomode); - endif - unwind_protect_cleanup - recursion = false; - end_unwind_protect - endif -endfunction - -function color = getcolor (ax) - obj = get (ax); - if (isfield (obj, "color")) - color = obj.color; - elseif (isfield (obj, "facecolor") && ! ischar (obj.facecolor)) - color = obj.facecolor; - elseif (isfield (obj, "edgecolor") && ! ischar (obj.edgecolor)) - color = obj.edgecolor; - else - color = [0, 0, 0]; - endif -endfunction - diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/private/__patch__.m --- a/scripts/plot/draw/private/__patch__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/private/__patch__.m Fri Mar 07 13:02:43 2014 -0500 @@ -70,7 +70,7 @@ y = varargin{2}; iarg = 4; if (rem (nargin - iarg, 2) == 1) - c = varargin {iarg}; + c = varargin{iarg}; z = varargin{3}; iarg = 5; else @@ -83,7 +83,7 @@ z = []; iarg = 3; if (rem (nargin - iarg, 2) == 1) - c = varargin {iarg}; + c = varargin{iarg}; iarg++; else c = []; @@ -127,7 +127,7 @@ args{9} = "cdata"; args{10} = c; else - error ("patch: color value not valid"); + error ("patch: color data C must be numeric"); endif elseif (isvector (c) && numel (c) == 3) args{7} = "facecolor"; @@ -150,7 +150,7 @@ args{9} = "cdata"; args{10} = c; else - error ("patch: color value not valid"); + error ("patch: Invalid TrueColor data C"); endif else ## Color Vectors @@ -159,18 +159,17 @@ args{8} = "interp"; args{9} = "cdata"; args{10} = []; - elseif (isequal (size (c), size (x)) && isequal (size (c), size (y))) + elseif (size_equal (c, x) && size_equal (c, y)) args{7} = "facecolor"; args{8} = "interp"; args{9} = "cdata"; args{10} = c; else - error ("patch: size of x, y, and c must be equal"); + error ("patch: size of X, Y, and C must be equal"); endif endif elseif (ischar (c) && rem (nargin - iarg, 2) == 0) - ## Assume that any additional argument over an even number is - ## color string. + ## Assume any additional argument over an even number is a color string. args{7} = "facecolor"; args{8} = tolower (c); args{9} = "cdata"; @@ -195,7 +194,7 @@ endif if (!failed) - h = __go_patch__ (p, args {:}); + h = __go_patch__ (p, args{:}); ## Setup listener functions addlistener (h, "xdata", @update_data); @@ -229,19 +228,19 @@ if (idx > nargs) faces = []; else - faces = args {idx}; + faces = args{idx}; endif idx = find (strcmpi (args, "vertices"), 1, "last") + 1; if (idx > nargs) vert = []; else - vert = args {idx}; + vert = args{idx}; endif idx = find (strcmpi (args, "facevertexcdata"), 1, "last") + 1; if (isempty (idx) || idx > nargs) fvc = []; else - fvc = args {idx}; + fvc = args{idx}; endif idx = find (strcmpi (args, "facecolor"), 1, "last") + 1; if (isempty (idx) || idx > nargs) @@ -254,7 +253,7 @@ endif nc = rows (faces); - idx = faces .'; + idx = faces.'; t1 = isnan (idx); for i = find (any (t1)) first_idx_in_column = find (t1(:,i), 1); @@ -273,11 +272,11 @@ else if (columns (fvc) == 3) c = cat (3, reshape (fvc(idx, 1), size (idx)), - reshape (fvc(idx, 2), size (idx)), - reshape (fvc(idx, 3), size (idx))); + reshape (fvc(idx, 2), size (idx)), + reshape (fvc(idx, 3), size (idx))); elseif (isempty (fvc)) c = []; - else ## if (columnns (fvc) == 1) + else ## if (columnns (fvc) == 1) c = permute (fvc(faces), [2, 1]); endif endif @@ -293,25 +292,25 @@ if (idx > nargs) x = []; else - x = args {idx}; + x = args{idx}; endif idx = find (strcmpi (args, "ydata"), 1, "last") + 1; if (idx > nargs) y = []; else - y = args {idx}; + y = args{idx}; endif idx = find (strcmpi (args, "zdata"), 1, "last") + 1; if (isempty (idx) || idx > nargs) z = []; else - z = args {idx}; + z = args{idx}; endif idx = find (strcmpi (args, "cdata"), 1, "last") + 1; if (isempty (idx) || idx > nargs) c = []; else - c = args {idx}; + c = args{idx}; endif idx = find (strcmpi (args, "facecolor"), 1, "last") + 1; if (isempty (idx) || idx > nargs) @@ -328,13 +327,13 @@ nr = nc; nc = 1; endif - if (!isempty (z)) + if (isempty (z)) + vert = [x(:), y(:)]; + else vert = [x(:), y(:), z(:)]; - else - vert = [x(:), y(:)]; endif faces = reshape (1:numel (x), nr, nc); - faces = faces'; + faces = faces.'; if (ndims (c) == 3) fvc = reshape (c, rows (c) * columns (c), size (c, 3)); diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/private/__scatter__.m --- a/scripts/plot/draw/private/__scatter__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/private/__scatter__.m Fri Mar 07 13:02:43 2014 -0500 @@ -84,6 +84,21 @@ c = []; endif + ## Validate inputs + if (nd == 2 && ! size_equal (x, y)) + error ([fcn ": X and Y must have the same size"]); + elseif (nd == 3 && ! size_equal (x, y, z)) + error ([fcn ": X, Y, and Z must have the same size"]); + endif + + if (! isscalar (s) && ! size_equal (x, s)) + error ([fcn ": size of S must match X, Y, and Z"]); + endif + + if (rows (c) > 1 && rows (c) != rows (x)) + error ([fcn ": number of colors in C must match number of points in X"]); + endif + newargs = {}; filled = false; have_marker = false; diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/private/__stem__.m --- a/scripts/plot/draw/private/__stem__.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/private/__stem__.m Fri Mar 07 13:02:43 2014 -0500 @@ -48,6 +48,8 @@ h = []; nx = rows (x); + h_baseline = []; + for i = 1 : columns (x) if (have_z) xt = x(:)'; @@ -90,19 +92,19 @@ __line__ (hax, xt, yt, zt, "color", lc, "linestyle", ls, "parent", hg); __line__ (hax, x, y, z, "color", mc, "linestyle", "none", "marker", ms, "markerfacecolor", fc, "parent", hg); - h_baseline = []; else __line__ (hax, xt, yt, "color", lc, "linestyle", ls, "parent", hg); __line__ (hax, x(:,i), y(:, i), "color", mc, "linestyle", "none", "marker", ms, "markerfacecolor", fc, "parent", hg); + x_axis_range = get (hax, "xlim"); - h_baseline = line (hax, x_axis_range, [0, 0], "color", [0, 0, 0]); - set (h_baseline, "handlevisibility", "off", "xliminclude", "off"); - addlistener (hax, "xlim", @update_xlim); - addproperty ("basevalue", h_baseline, "data", 0); - addlistener (h_baseline, "basevalue", {@update_baseline, 0}); - addlistener (h_baseline, "ydata", {@update_baseline, 1}); - addlistener (h_baseline, "visible", {@update_baseline, 2}); + if (isempty (h_baseline)) + h_baseline = line (hax, x_axis_range, [0, 0], "color", [0, 0, 0]); + set (h_baseline, "handlevisibility", "off", "xliminclude", "off"); + addproperty ("basevalue", h_baseline, "data", 0); + else + set (h_baseline, "xdata", x_axis_range); + endif endif ## Setup the hggroup and listeners. @@ -110,11 +112,6 @@ addproperty ("baseline", hg, "data", h_baseline); addproperty ("basevalue", hg, "data", 0); - if (! have_z) - addlistener (hg, "showbaseline", @show_baseline); - addlistener (hg, "basevalue", @move_baseline); - endif - addproperty ("color", hg, "linecolor", lc); addproperty ("linestyle", hg, "linelinestyle", ls); addproperty ("linewidth", hg, "linelinewidth", 0.5); @@ -146,14 +143,28 @@ ## Matlab property, although Octave does not implement it. addproperty ("hittestarea", hg, "radio", "on|{off}", "off"); - if (! isempty (args)) - set (hg, args{:}); - endif - if (i == 1 && ! isempty (h_baseline)) - set (h_baseline, "parent", get (hg, "parent")); - endif endfor + ## baseline listeners + if (! isempty (h_baseline)) + addlistener (hax, "xlim", @update_xlim); + for hg = h' + addlistener (hg, "showbaseline", @show_baseline); + addlistener (hg, "visible", {@show_baseline, h}); + addlistener (hg, "basevalue", @move_baseline); + endfor + + addlistener (h_baseline, "basevalue", {@update_baseline, 0}); + addlistener (h_baseline, "ydata", {@update_baseline, 1}); + addlistener (h_baseline, "visible", {@update_baseline, 2}); + set (h_baseline, "parent", get (hg(1), "parent")); + endif + + ## property/value pairs + if (! isempty (args)) + set (h, args{:}); + endif + if (! strcmp (hold_state, "add") && have_z) set (hax, "view", [-37.5 30], "xgrid", "on", "ygrid", "on", "zgrid", "on"); @@ -365,8 +376,16 @@ endfor endfunction -function show_baseline (h, ~) - set (get (h, "baseline"), "visible", get (h, "showbaseline")); +function show_baseline (h, ~, hg = []) + if (isempty (hg)) + set (get (h, "baseline"), "visible", get (h, "showbaseline")); + else + if (all (strcmp (get (hg, "visible"), "off"))) + set (get (h, "baseline"), "visible", "off"); + else + set (get (h, "baseline"), "visible", "on"); + endif + endif endfunction function move_baseline (h, ~) @@ -374,6 +393,7 @@ bl = get (h, "baseline"); set (bl, "ydata", [b0, b0]); + set (bl, "basevalue", b0); kids = get (h, "children"); yt = get (h, "ydata")(:)'; diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/shrinkfaces.m --- a/scripts/plot/draw/shrinkfaces.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/shrinkfaces.m Fri Mar 07 13:02:43 2014 -0500 @@ -23,24 +23,29 @@ ## @deftypefnx {Function File} {@var{nfv} =} shrinkfaces (@var{f}, @var{v}, @var{sf}) ## @deftypefnx {Function File} {[@var{nf}, @var{nv}] =} shrinkfaces (@dots{}) ## -## Reduce the faces area for a given patch, structure or explicit faces -## and points matrices by a scale factor @var{sf}. The structure -## @var{fv} must contain the fields @qcode{"faces"} and @qcode{"vertices"}. -## If the factor @var{sf} is omitted then a default of 0.3 is used. +## Reduce the size of faces in a patch by the shrink factor @var{sf}. +## +## The patch object can be specified by a graphics handle (@var{p}), a patch +## structure (@var{fv}) with the fields @qcode{"faces"} and @qcode{"vertices"}, +## or as two separate matrices (@var{f}, @var{v}) of faces and vertices. ## -## Given a patch handle as the first input argument and no output -## parameters, perform the shrinking of the patch faces in place and -## redraw the patch. +## The shrink factor @var{sf} is a positive number specifying the percentage +## of the original area the new face will occupy. If no factor is given the +## default is 0.3 (a reduction to 30% of the original size). A factor greater +## than 1.0 will result in the expansion of faces. +## +## Given a patch handle as the first input argument and no output parameters, +## perform the shrinking of the patch faces in place and redraw the patch. ## ## If called with one output argument, return a structure with fields ## @qcode{"faces"}, @qcode{"vertices"}, and @qcode{"facevertexcdata"} -## containing the data after shrinking which can then directly be used as an -## input argument for the @code{patch} function. +## containing the data after shrinking. This structure can be used directly +## as an input argument to the @code{patch} function. ## -## Performing the shrinking on faces which are not convex can lead to -## undesired results. +## @strong{Caution:}: Performing the shrink operation on faces which are not +## convex can lead to undesirable results. ## -## For example, +## Example: a triangulated 3/4 circle and the corresponding shrunken version. ## ## @example ## @group @@ -56,9 +61,6 @@ ## @end group ## @end example ## -## @noindent -## draws a triangulated 3/4 circle and the corresponding shrunken -## version. ## @seealso{patch} ## @end deftypefn @@ -71,8 +73,8 @@ endif sf = 0.3; + colors = []; p = varargin{1}; - colors = []; if (ishandle (p) && nargin < 3) faces = get (p, "Faces"); @@ -104,8 +106,8 @@ error ("shrinkfaces: scale factor must be a positive scalar"); endif - n = columns (vertices); - if (n < 2 || n > 3) + nc = columns (vertices); + if (nc < 2 || nc > 3) error ("shrinkfaces: only 2-D and 3-D patches are supported"); endif @@ -120,14 +122,12 @@ elseif (rows (colors) == rows (vertices)) c = colors(faces'(:), :); else - ## Discard inconsistent color data. - c = []; + c = []; # Discard inconsistent color data. endif sv = rows (v); - ## we have to deal with a probably very large number of vertices, so - ## use sparse we use as midpoint (1/m, ..., 1/m) in generalized - ## barycentric coordinates. - midpoints = full (kron ( speye (sv / m), ones (m, m) / m) * sparse (v)); + ## We have to deal with a possibly very large number of vertices, so use + ## sparse as midpoint (1/m, ..., 1/m) in generalized barycentric coordinates. + midpoints = full (kron (speye (sv / m), ones (m, m) / m) * sparse (v)); v = sqrt (sf) * (v - midpoints) + midpoints; f = reshape (1:sv, m, sv / m)'; @@ -216,3 +216,13 @@ %!assert (size (nfv.vertices), [3 3]) %!assert (norm (nfv2.vertices - vertices), 0, 2*eps) +%% Test input validation +%!error shrinkfaces () +%!error shrinkfaces (1,2,3,4) +%!error [a,b,c] = shrinkfaces (1) +%!error shrinkfaces (nfv, ones (2)) +%!error shrinkfaces (nfv, 0) +%!error shrinkfaces (faces, ones (3,1)) +%!error shrinkfaces (faces, ones (3,4)) +%!error shrinkfaces (faces(1:2), vertices) + diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/stem.m --- a/scripts/plot/draw/stem.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/stem.m Fri Mar 07 13:02:43 2014 -0500 @@ -187,7 +187,7 @@ %! y = [sin(x), cos(x)]; %! h = stem (x, y); %! set (h(2), 'color', 'g'); -%! set (h(1), 'basevalue', -1); +%! set (h(1), 'basevalue', -0.75); %! title ('stem plots modified through hggroup handle'); %!demo @@ -213,3 +213,18 @@ %!error stem (ones (2,2), ones (3,3)) %!error stem (1, "FOO") +%!test +%! ## stemseries share the same baseline and basevalue +%! hf = figure ("visible", "off"); +%! unwind_protect +%! h = stem ([1 2; 1.5 2.5], [1 1;2 2]); +%! assert (get (h(1), "baseline"), get (h(2), "baseline")) +%! bv = 0.3; +%! set (h(1), "basevalue", bv) +%! assert (get (get (h(1), "baseline"), "basevalue"), bv) +%! assert (get (h(1), "basevalue"), bv) +%! assert (get (h(2), "basevalue"), bv) +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/surface.m --- a/scripts/plot/draw/surface.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/surface.m Fri Mar 07 13:02:43 2014 -0500 @@ -73,109 +73,110 @@ h = 0; bad_usage = false; - firststring = nargin; - for i = 1 : (nargin - 1) - if (ischar (varargin{i})) - firststring = i; - break; - endif - endfor + firststring = find (cellfun ("isclass", varargin, "char"), 1); + if (isempty (firststring)) + firststring = nargin; + endif - if (firststring > 5) - bad_usage = true; - return; - elseif (firststring == 5) - x = varargin{1}; - y = varargin{2}; - z = varargin{3}; - c = varargin{4}; + switch (firststring) + case 5 + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + c = varargin{4}; - if (iscomplex (x) || iscomplex (y) || iscomplex (z) || iscomplex (c)) - error ("mesh: X, Y, Z, C arguments must be real"); - endif + if (iscomplex (x) || iscomplex (y) || iscomplex (z) || iscomplex (c)) + error ("mesh: X, Y, Z, C arguments must be real"); + endif + + [z_nr, z_nc] = size (z); + [c_nr, c_nc, c_np] = size (c); + if (! (z_nr == c_nr && z_nc == c_nc && (c_np == 1 || c_np == 3))) + error ("surface: Z and C must have the same size"); + endif - [z_nr, z_nc] = size (z); - [c_nr, c_nc, c_np] = size (c); - if (! (z_nr == c_nr && z_nc == c_nc && (c_np == 1 || c_np == 3))) - error ("surface: Z and C must have the same size"); - endif - - if (isvector (x) && isvector (y) && ismatrix (z)) - if (rows (z) == length (y) && columns (z) == length (x)) - x = x(:)'; - y = y(:); + if (isvector (x) && isvector (y) && ismatrix (z)) + if (rows (z) == length (y) && columns (z) == length (x)) + x = x(:)'; + y = y(:); + else + error ("surface: rows (Z) must be the same as length (Y) and columns (Z) must be the same as length (X)"); + endif + elseif (ismatrix (x) && ismatrix (y) && ismatrix (z)) + if (! size_equal (x, y, z)) + error ("surface: X, Y, and Z must have the same dimensions"); + endif else - error ("surface: rows (Z) must be the same as length (Y) and columns (Z) must be the same as length (X)"); + error ("surface: X and Y must be vectors and Z must be a matrix"); endif - elseif (ismatrix (x) && ismatrix (y) && ismatrix (z)) - if (! size_equal (x, y, z)) - error ("surface: X, Y, and Z must have the same dimensions"); + + case 4 + x = varargin{1}; + y = varargin{2}; + z = varargin{3}; + c = z; + + if (iscomplex (x) || iscomplex (y) || iscomplex (z)) + error ("mesh: X, Y, Z arguments must be real"); endif - else - error ("surface: X and Y must be vectors and Z must be a matrix"); - endif - elseif (firststring == 4) - x = varargin{1}; - y = varargin{2}; - z = varargin{3}; - c = z; - - if (iscomplex (x) || iscomplex (y) || iscomplex (z)) - error ("mesh: X, Y, Z arguments must be real"); - endif - if (isvector (x) && isvector (y) && ismatrix (z)) - if (rows (z) == length (y) && columns (z) == length (x)) - x = x(:)'; - y = y(:); + if (isvector (x) && isvector (y) && ismatrix (z)) + if (rows (z) == length (y) && columns (z) == length (x)) + x = x(:)'; + y = y(:); + else + error ("surface: rows (Z) must be the same as length (Y) and columns (Z) must be the same as length (X)"); + endif + elseif (ismatrix (x) && ismatrix (y) && ismatrix (z)) + if (! size_equal (x, y, z)) + error ("surface: X, Y, and Z must have the same dimensions"); + endif else - error ("surface: rows (Z) must be the same as length (Y) and columns (Z) must be the same as length (X)"); - endif - elseif (ismatrix (x) && ismatrix (y) && ismatrix (z)) - if (! size_equal (x, y, z)) - error ("surface: X, Y, and Z must have the same dimensions"); + error ("surface: X and Y must be vectors and Z must be a matrix"); endif - else - error ("surface: X and Y must be vectors and Z must be a matrix"); - endif - elseif (firststring == 3) - z = varargin{1}; - c = varargin{2}; - if (iscomplex (z) || iscomplex (c)) - error ("mesh: X, C arguments must be real"); - endif + case 3 + z = varargin{1}; + c = varargin{2}; + + if (iscomplex (z) || iscomplex (c)) + error ("mesh: X, C arguments must be real"); + endif - if (ismatrix (z) && !isvector (z) && !isscalar (z)) - [nr, nc] = size (z); - x = 1:nc; - y = (1:nr)'; - else - error ("surface: Z argument must be a matrix"); - endif - elseif (firststring == 2) - z = varargin{1}; - c = z; + if (ismatrix (z) && !isvector (z) && !isscalar (z)) + [nr, nc] = size (z); + x = 1:nc; + y = (1:nr)'; + else + error ("surface: Z argument must be a matrix"); + endif - if (iscomplex (z)) - error ("mesh: Z argument must be real"); - endif + case 2 + z = varargin{1}; + c = z; + + if (iscomplex (z)) + error ("mesh: Z argument must be real"); + endif - if (ismatrix (z) && !isvector (z) && !isscalar (z)) - [nr, nc] = size (z); - x = 1:nc; - y = (1:nr)'; - else - error ("surface: Z argument must be a matrix"); - endif - elseif (firststring == 1) - x = 1:3; - y = x'; - c = z = eye (3); - else - bad_usage = true; - return; - endif + if (ismatrix (z) && !isvector (z) && !isscalar (z)) + [nr, nc] = size (z); + x = 1:nc; + y = (1:nr)'; + else + error ("surface: Z argument must be a matrix"); + endif + + case 1 + x = 1:3; + y = x'; + c = z = eye (3); + + otherwise + bad_usage = true; + return; + + endswitch if (firststring < nargin) other_args = varargin(firststring:end); diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/draw/surfl.m --- a/scripts/plot/draw/surfl.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/draw/surfl.m Fri Mar 07 13:02:43 2014 -0500 @@ -164,7 +164,7 @@ endif vn = get (htmp, "vertexnormals"); - dar = get (hax, "plotboxaspectratio"); + dar = get (hax, "dataaspectratio"); vn(:,:,1) *= dar(1); vn(:,:,2) *= dar(2); vn(:,:,3) *= dar(3); @@ -206,8 +206,7 @@ %! clf; %! [X,Y,Z] = sombrero (); %! colormap (copper (64)); -%! [az, el] = view (); -%! surfl (X,Y,Z, [az+225,el], [0.2 0.6 0.4 25]); +%! surfl (X,Y,Z, [62.50,30], [0.2 0.6 0.4 25]); %! shading interp; %! title ('surfl() with lighting vector and material properties'); diff -r de76baa76aa1 -r b83fca22bb4c scripts/plot/util/colstyle.m --- a/scripts/plot/util/colstyle.m Fri Mar 07 12:54:16 2014 -0500 +++ b/scripts/plot/util/colstyle.m Fri Mar 07 13:02:43 2014 -0500 @@ -36,10 +36,7 @@ try opt = __pltopt__ ("colstyle", style); l = opt.linestyle; - c = opt.color; - m = opt.marker; - msg = []; - switch (c) + switch (opt.color) case [0 0 0] c = "k"; case [1 0 0] @@ -56,7 +53,11 @@ c = "c"; case [0 1 1] c = "w"; + otherwise + c = opt.color; endswitch + m = opt.marker; + msg = []; catch l = c = m = []; msg = lasterr (); @@ -86,5 +87,5 @@ %% Test input validation %!error colstyle () %!error colstyle (1, 2) -%!error colstyle (1.5) +%!error