# HG changeset patch # User jwe # Date 1198875418 0 # Node ID 745a8299c2b559b5559cb2c4e087b193eafe6bd4 # Parent 58f5fab3ebe5be60a39addd9b5bee8ac9e742836 [project @ 2007-12-28 20:56:55 by jwe] diff -r 58f5fab3ebe5 -r 745a8299c2b5 doc/ChangeLog --- a/doc/ChangeLog Fri Feb 01 23:56:51 2008 -0500 +++ b/doc/ChangeLog Fri Dec 28 20:56:58 2007 +0000 @@ -1,3 +1,12 @@ +2007-12-28 John W. Eaton + + Merge changes from object branch: + + 2007-06-20 John W. Eaton + + * interpreter/var.txi, interpreter/io.txi: + Eliminate print_answer_id_name. + 2007-12-21 John W. Eaton Version 3.0.0 released. diff -r 58f5fab3ebe5 -r 745a8299c2b5 doc/interpreter/io.txi --- a/doc/interpreter/io.txi Fri Feb 01 23:56:51 2008 -0500 +++ b/doc/interpreter/io.txi Fri Dec 28 20:56:58 2007 +0000 @@ -69,8 +69,6 @@ @DOCSTRING(format) -@DOCSTRING(print_answer_id_name) - @menu * Paging Screen Output:: @end menu diff -r 58f5fab3ebe5 -r 745a8299c2b5 doc/interpreter/var.txi --- a/doc/interpreter/var.txi Fri Feb 01 23:56:51 2008 -0500 +++ b/doc/interpreter/var.txi Fri Dec 28 20:56:58 2007 +0000 @@ -477,11 +477,6 @@ Default value: 1. -@item print_answer_id_name -@xref{Terminal Output}. - -Default value: 1. - @item print_empty_dimensions @xref{Empty Matrices}. diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ChangeLog --- a/src/ChangeLog Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ChangeLog Fri Dec 28 20:56:58 2007 +0000 @@ -1,3 +1,418 @@ +2007-12-28 John W. Eaton + + Merge changes from object branch: + + 2007-12-12 John W. Eaton + + * load-path.cc (load_path::dir_info::get_file_list, + load_path::move_method_map, load_path::remove_method_map, + load_path::do_find_fcn, load_path::do_find_private_fcn, + load_path::do_find_method, load_path::do_find_file, + load_path::do_find_first_of, load_path::do_find_all_first_of, + load_path::do_display, load_path::add_to_method_map, genpath, + execute_pkg_add_or_del): Use file_ops::concat. + + 2007-08-24 John W. Eaton + + * variables.cc (Fmislocked): return value for nargin == 0 case. + + 2007-07-27 John W. Eaton + + * pt-idx.cc (tree_index_expression::rvalue): + Pass substring of type to subsref when doing partial evaluation. + (tree_index_expression::lvalue): Likewise. + + 2007-06-29 John W. Eaton + + * ov-class.cc (is_built_in_class, set_class_relationship, + Fsuperiorto, Finferiorto): New functions. + (octave_class::in_class_method): New function. + (octave_class::subsref, octave_class:subsasgn): Use it. + + 2007-06-28 John W. Eaton + + * src/ov-class.cc (sanitize): New function. + (make_idx_args): Use it. + + 2007-06-28 John W. Eaton + + * src/ov-class.cc (octave_class::subsasgn): Expect and use only + one return value from feval of subsasgn method. + + * ov.cc (octave_value::assign): Don't convert to struct if + indexing a class object with ".". + + * pt-idx.cc (tree_index_expression::make_arg_struct): + Use Cell instead of octave_value_list for subscripts. + + * ov-class.cc (make_idx_args): For "." index, subs field is + string, not cell. + + 2007-06-27 John W. Eaton + + * ov-fcn-handle.cc (octave_fcn_handle::save_ascii, + octave_fcn_handle::load_ascii, octave_fcn_handle::save_binary, + octave_fcn_handle::load_binary, octave_fcn_handle::save_hdf5, + octave_fcn_handle::load_hdf5): Adapt to new symbol table objects. + + * symtab.h (symbol_table::all_variables, + symbol_table::do_all_variables): New arg, defined_only. + + 2007-06-26 John W. Eaton + + * ls-mat5.cc (read_mat5_binary_element): Adapt to new symbol table + objects. + + * variables.cc (Vwhos_line_format): New static variable. + (Fwhos_line_format): New function. + (symbol_record_name_compare): Delete function. + (symbol_record_name_compare, whos_parameter): New structs. + (print_descriptor, dimensions_string_req_first_space, + dimensions_string_req_total_space, make_dimensions_string, + parse_whos_line_format, print_symbol_info_line): New static + functions, adapted from old symbol table class. + (do_who): Adapt to new symbol table objects. + + * symtab.h (symbol_table::glob_variables): New functions. + (symbol_table::do_glob): New argument, vars_only. Change all uses. + + 2007-06-22 John W. Eaton + + * symtab.cc (symbol_table::fcn_info::fcn_info_rep::help_for_dispatch): + New function. + * symtab.h: Provide decl. + (symbol_table::fcn_info::help_for_dispatch, + symbol_table::help_for_dispatch): New functions. + + * help.cc (help_from_symbol_table): Call + symbol_table::help_for_dispatch instead of + extract_help_from_dispatch. + + * help.cc (extract_help_from_dispatch): Delete. + * help.h: Delete decl. + + 2007-06-21 John W. Eaton + + * DLD-FUNCTIONS/dispatch.cc (class octave_dispatch): Delete class. + (builtin, any_arg_is_magic_colon, dispatch_record): Delete functions. + (Fbuiltin, Fdispatch): Adapt to new symbol table objects. + + * symtab.cc (symbol_table::fcn_info::fcn_info_rep::print_dispatch): + New function. + * symtab.h: Provide decl. + (symbol_table::fcn_info::print_dispatch, symbol_table::print_dispatch): + New functions. + + * symtab.h (symbol_table::fcn_info::fcn_info_rep::clear_dispatch, + symbol_table::fcn_info::clear_dispatch, symbol_table::clear_dispatch): + New functions. + + * symtab.h (symbol_table::fcn_info::fcn_info_rep::get_dispatch, + symbol_table::fcn_info::get_dispatch, symbol_table::get_dispatch): + New functions. + + * symtab.cc (symbol_table::fcn_info::fcn_info_rep::find): + Use leftmost class argument as dispatch type, or first argument if + there are no class arguments. + + 2007-06-20 John W. Eaton + + * ov-base.cc (Vprint_answer_id_name, Fprint_answer_id_name): Delete. + (octave_base_value::print_with_name): Always print name. + + * ov-base.cc (Vsilent_functions): No longer static. + * ov-base.h: Provide decl. + + * ov-class.cc (Fmethods): Define as command. + + * ov-class.cc (octave_class::print): Simply call print_raw. + + * ov-class.cc (octave_class::print_with_name): New function. + * ov-class.h: Provide decl. + + 2007-06-19 John W. Eaton + + * ov.cc (octave_value::do_unary_op, octave_value::do_binary_op): + Handle class methods. + + * ov.cc (octave_value::unary_op_fcn_name, + octave_value::binary_op_fcn_name): New functions. + * ov.h: Provide decls. + + * ov-typeinfo.cc (octave_value_typeinfo::register_unary_class_op, + octave_value_typeinfo::register_binary_class_op, + octave_value_typeinfo::do_register_unary_class_op, + octave_value_typeinfo::do_register_binary_class_op, + octave_value_typeinfo::do_lookup_unary_class_op, + octave_value_typeinfo::do_lookup_binary_class_op): New functions. + * ov-typeinfo.h: Provide decls. + + * ov-typeinfo.h (octave_value_typeinfo::unary_class_op_fcn, + octave_value_typeinfo::binary_class_op_fcn): New typedefs. + (octave_value_typeinfo::unary_class_ops, + octave_value_typeinfo::binary_class_ops): New data members. + (octave_value_typeinfo::octave_value_typeinfo): Initialize them. + (octave_value_typeinfo::lookup_unary_class_op, + octave_value_typeinfo::lookup_binary_class_op): New functions. + + * OPERATORS/op-class.cc: New file. + * Makefile.in (OP_XSRC): Add it to the list. + + * ov.cc (install_types): Call octave_class::register_type here. + + * ov-class.h (octave_class): Implement by containing a map object + instead of deriving from octave_struct. + * ov-class.cc (octave_class::subsref, octave_class::subsasgn): + Don't use octave_class implementation as default action. + + * ov.h, ov.cc (octave_value::octave_value (const Octave_map&, const + std::string&)): New constructor. + + 2007-06-18 John W. Eaton + + * ov-class.cc (octave_class::subsref, octave_class::subsasgn): + Handle dispatch to user-defined methods. + + * parse.y (load_fcn_from_file): New arg, dispatch_type. + Change all uses. + + * ov-fcn.h (octave_function::is_class_constructor, + octave_function::is_class_method, octave_function::dispatch_class): + New virtual functions. + + * ov-usr-fcn.h (octave_user_function::dispatch_class, + octave_usr_function::stash_dispatch_class): New functions. + (octave_usr_fucntion::xdispatch_class): New data member. + * parse.y (frob_function): Call stash_dispatch_class here. + + * ov-struct.cc (Ffieldnames): Also handle objects. + + * ov-class.cc (Fmethods): New function. + * load-path.cc (load_path::do_methods): New function. + * load-path.h (load_path::methods): New function. + + * ov.h (octave_value::is_object): New function. + * ov-base.h (octave_base_value::is_object): New virtual function. + * ov-class.h (octave_class::is_object): New function. + * ov-class.cc (Fisobject): New function. + + 2007-06-15 John W. Eaton + + * ov-class.cc (octave_class::print): Call display method if found. + + * symtab.h (symbol_table::fcn_info::find_method): New function. + (symbol_table::find_method): New function. + (symbol_table::fcn_info::fcn_info_rep::find_method): Provide decl. + * symtab.cc (symbol_table::fcn_info::fcn_info_rep::find_method): + New function. + (symbol_table::fcn_info::fcn_info_rep::find): Use it. + + 2007-06-14 John W. Eaton + + * symtab.h (symbol_table::clear_mex_functions): Make it work. + (symbol_table::fcn_info::fcn_info_rep::clear_mex_function, + symbol_table::fcn_info::clear_mex_function): New functions. + + 2007-06-08 John W. Eaton + + * defun.cc (Falias): Delete. + + * variables.cc (load_fcn_try_ctor): New function. + (lookup): call load_fcn_try_ctor instead of load_fcn_from_file. + + * variables.cc, variables.h (at_top_level, lookup_by_name, lookup, + initialize_symbol_tables, fcn_out_of_date, symbol_out_of_date, + lookup_function, lookup_user_function, link_to_global_variable, + link_to_builtin_or_function, force_link_to_function, Fdocument, + is_local_variable, do_clear_all, do_clear_functions, + do_clear_globals, do_clear_variables, do_clear_function, + do_clear_global, do_clear_variable, do_clear_symbol, + do_clear_function_pattern, do_clear_global_pattern, + do_clear_variable_pattern, do_clear_symbol_pattern, + clear_function, clear_variable, clear_symbol): + Delete (some functionality moved to the new symtab.cc and some is + no longer needed). + (Fignore_function_time_stamp): Move to symtab.cc. + + * lex.l (lookup_identifier): Delete. + + * parse.y (is_function_file): New function. + (load_fcn_from_file): Return pointer to octave_function, not bool. + + * ov-usr-fcn.h, ov-usr-fcn.cc (octave_user_function::argn_sr, + octave_user_function::nargin_sr, octave_user_function::nargout_sr, + octave_user_function::varargin_sr): Delete data members. + (octave_user_function::install_automatic_vars): Delete. + (octave_user_script::do_multi_index_op): New function. + + * ov-fcn.h (octave_function::locked, octave_function::my_dir_name): + New data members. + (octave_function::dir_name, octave_function::stash_dir_name, + octave_function::lock, octave_function::unlock, + octave_function::islocked): New functions. + + * of-fcn-handle.h, ov-fcn-handle.cc (octave_fcn_handle::subsref): + Call out_of_date_check here to simplify time stamp checking. + (octave_fcn_handle::reload_warning): Delete. + + * ov.h (octave_value::is_user_script, octave_value::is_user_function): + New functions. + * ov-base.h (octave_base_value::is_user_script, + octave_base_value::is_user_function): New pure virtual functions. + * ov-fcn.h (octave_function::is_user_script, + octave_function::is_user_function): Delete. + + * load-save.cc (install_loaded_variable): Greatly simplify. + + * load-path.h, load-path.cc: Change private_fcn_file to private_file. + (load_path::private_fcn_map): New data member. + (load_path::do_add, load_path::do_remove, load_path::do_update): + Also manage private_file_map here. + (load_path::add_to_private_fcn_map): New function. + (load_path::remove_private_fcn_map): New function. + (load_path::do_find_private_fcn): Make it work. + (get_file_list): New function. + (load_path::do_display): Use it. Display private map. + (load_path::find_method, load_path::find_fcn): Handle directory name. + + * token.cc, token.h, toplev.cc, debug.cc, defun.cc, defun-dld.h, + defun-int.h, error.cc, help.cc, load-save.h, load-save.cc, mex.cc, + octave.cc, ov-fcn-handle.cc, ov-usr-fcn.cc, parse.h, parse.y, + lex.l, variables.cc: Adapt to new symbol table objects (my + apologies for the lack of detail). + + * unwind-prot.h (unwind_protect::add): Set default value for ptr arg. + + * pt-stmt.cc (tree_statement::eval): Rework method for deciding + whether to assign value to ans. + + * pt-idx.cc (tree_index_expression::rvalue): + Looking up symbol may evaluaate first args now. + + * pt-id.h, pt-id.cc (tree_identifier::document, + tree_identifier::is_defined, tree_identifier::define, + tree_identifier::is_function, tree_identifier::lookup, + tree_identifier::link_to_global): Delete. + (tree_identifier::do_lookup): Simplify. + (tree_identifier::rvalue): Looking up symbol can't execute script now. + + * pt-misc.cc (tree_parameter_list::initialize_undefined, + tree_parameter_list::is_defined): Call is_variable for elt, not + is_defined. + + * pt-fcn-handle.h (tree_anon_fcn_handle::fcn): Now pointer to + octave_user_function, not value. Change all uses. + + * pt-decl.h (tree_decl_command::initialized): Delete data member. + (tree_decl_elt::is_variable): New function. + * pt-decl.cc: Fix all uses of tree_decl_command::initialized. + + * ls-hdf5.cc, ls-mat-ascii.cc, ls-mat4.cc, ls-mat5.cc, + ls-oct-ascii.cc, ls-oct-binary.cc, input.cc: Don't include symtab.h. + + * dynamic-ld.h, dynamic-ld.cc (octave_dynamic_loader::load_oct, + octave_dynamic_loader::load_mex, octave_dynamic_loader::do_load_oct, + octave_dynamic_loader::do_load_mex): Adapt to new symbol table + objects. Return pointer octave_function instead of bool. + + * DLD-FUNCTIONS/dispatch.cc (Fbuiltin): Disable for now. + Disable code that works with old symbol tables. + (Fbuiltin): Simply call symbol_table::add_dispatch. + + * pt-arg-list.cc, pt-arg-list.h, pt-assign.cc, pt-assign.h, + pt-binop.cc, pt-binop.h, pt-bp.h, pt-cell.cc, pt-cell.h, + pt-cmd.cc, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, + pt-const.h, pt-decl.cc, pt-decl.h, pt-except.cc, pt-except.h, + pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, + pt-idx.cc, pt-idx.h, pt-jump.cc, pt-jump.h, pt-loop.cc, pt-loop.h, + pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-select.cc, + pt-select.h, pt-stmt.cc, pt-stmt.h, pt-unop.cc, pt-unop.h: + Adapt dup functions to use scope instead of symbol_table objects. + + * TEMPLATE-INST/Array-sym.cc: Delete. + * Makefile.in (TI_XSRC): Remove it from the list. + + * symtab.h, symtab.cc: Replace with new versions. + + 2007-05-16 John W. Eaton + + * oct-lvalue.cc, oct-lvalue.h (octave_lvalue::chg_fcn): Delete. + Fix all uses. + + 2007-05-15 John W. Eaton + + * load-path.cc (load_path::do_find_private_function): New function. + * load-path.h (load_path::do_find_private_function): Provide decl. + (load_path::find_private_function): New function. + + 2007-05-08 John W. Eaton + + * pt-idx.cc (tree_index_expression::rvalue): Handle dispatch here. + + * pt-id.cc (tree_identifier::is_variable, tree_identifier::lookup): + New functions. + * pt-id.cc: Provide decls. + + * parse.y (current_class_name): New global variable. + * parse.h: Provide decl. + + * parse.y (load_fcn_from_file, parse_fcn_file): + New arg, dispatch_type. + (parse_fcn_file): Protect current_class_name and set it to + dispatch_type before parsing function. + (load_fcn_from_file): If dispatch_type is not empty, call + load_path::find_method instead of load_path::find_fcn. + * parse.h: Fix decls for extern functions. + + * lex.h (lexical_feedback::parsing_class_method): New data member. + * lex.l (lexical_feedback::init): Initialize it. + (lookup_identifier): Check it and set sym_name accordingly. + + * ov-usr-fcn.h (octave_user_function::mark_as_class_constructor, + octave_user_function::is_class_constructor, + octave_user_function::mark_as_class_method, + octave_user_function::is_class_method): New functions. + (octave_user_function::class_constructor, + octave_user_function::class_method): New data members. + * ov-usr-fcn.cc (octave_user_function::octave_user_function): + Initialize them. + + * load-path.h, load-path.cc: Use typedefs to simplify template decls. + Use fcn consistently instead of function. + + 2007-05-03 John W. Eaton + + * ov-class.cc (Fclass): Move here. + * ov-typeinfo.cc: From here. + + * input.cc (octave_gets): Call load_path::update if user input + contains something other than one of the characters " \t\n\r". + + * ov-class.cc, ov-class.h: New files. + * Makefile.in: Add them to the appropriate lists. + + * load-path.cc (genpath): Skip directories beginning with "@". + (load_path::dir_info::get_file_list): Don't return anything. + Call get_private_function_map here. + (load_path::dir_info::initialize): Not here. + (load_path::dir_info_::get_method_file_map): New function. + (load_path::method_map): New data member. + (load_path::do_clear): Also clear method_map. + (load_path::do_add): Also call add_to_method_map. + (load_path::do_update): Also clear method_map and call + (load_path::do_find_method): New function. + (load_path::do_add_to_method_map): New function. + (load_path::move_fcn_map, load_path::move_method_map): New functions. + (load_path::move): Use them. + (load_path::remove_fcn_map, load_path::remove_method_map): + New functions. + (load_path::remove): Use them. + * load-path.h: Provide/fix decls. + (load_path::find_method): New static function. + + * Makefile.in (%.df : %.cc): Use mv instead of + $(simple-move-if-change-rule). + 2007-12-21 John W. Eaton Version 3.0.0 released. diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/DLD-FUNCTIONS/dispatch.cc --- a/src/DLD-FUNCTIONS/dispatch.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/DLD-FUNCTIONS/dispatch.cc Fri Dec 28 20:56:58 2007 +0000 @@ -28,6 +28,8 @@ #include #include +#include "Cell.h" +#include "oct-map.h" #include "defun-dld.h" #include "ov.h" #include "ov-fcn.h" @@ -37,257 +39,6 @@ #include "symtab.h" #include "variables.h" -// FIXME should be using a map from type_id->name, rather -// than type_name->name - -template class std::map; - -typedef std::map Table; - -class -octave_dispatch : public octave_function -{ -public: - - // FIXME need to handle doc strings of dispatched functions, for - // example, by appending "for (,...) see " for each - // time dispatch(f,type,name) is called. - octave_dispatch (const std::string &nm) - : octave_function (nm, "Overloaded function"), tab (), base (nm), - has_alias (false) - { } - - // FIXME if we get deleted, we should restore the original - // symbol_record from base before dying. - ~octave_dispatch (void) { } - - bool is_builtin_function (void) const { return true; } - - octave_function *function_value (bool) { return this; } - - octave_value do_index_op (const octave_value_list&, bool = false) - { - error ("dispatch: do_index_op"); - return octave_value (); - } - - octave_value subsref (const std::string&, - const std::list&) - { - error ("dispatch: subsref (str, list)"); - panic_impossible (); - return octave_value (); - } - - octave_value_list subsref (const std::string& type, - const std::list& idx, - int nargout); - - octave_value_list do_multi_index_op (int, const octave_value_list&); - - void add (const std::string t, const std::string n); - - void clear (const std::string t); - - void print (std::ostream& os, bool pr_as_read=false) const; - -private: - - Table tab; - std::string base; - bool has_alias; - - octave_dispatch (void) - : octave_function (), tab (), base (), has_alias (false) { } - - DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA - - DECLARE_OCTAVE_ALLOCATOR -}; - -DEFINE_OCTAVE_ALLOCATOR (octave_dispatch); - -DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_dispatch, - "overloaded function", "function"); - -void -octave_dispatch::add (const std::string t, const std::string n) -{ - if (tab.count (t) > 0 && tab[t] != n) - warning ("replacing %s(%s,...)->%s with %s", - base.c_str (), t.c_str (), tab[t].c_str (), n.c_str ()); - - tab[t] = n; - - if (t == "any") - has_alias = true; -} - -void -octave_dispatch::clear (const std::string t) -{ - tab.erase (t); - - if (t == "any") - has_alias = false; -} - -octave_value_list -octave_dispatch::subsref (const std::string& type, - const std::list& idx, - int nargout) -{ - octave_value_list retval; - - switch (type[0]) - { - case '(': - retval = do_multi_index_op (nargout, idx.front ()); - break; - - case '{': - case '.': - { - const std::string nm = type_name (); - error ("%s cannot be indexed with %c", nm.c_str (), type[0]); - } - break; - - default: - panic_impossible (); - } - - if (idx.size () > 1) - retval = retval(0).next_subsref (type, idx); - - return retval; -} - -static octave_function* -builtin (const std::string& base) -{ - octave_function *fcn = 0; - - // Check if we are overriding a builtin function. This is the - // case if builtin is protected. - symbol_record *builtin = fbi_sym_tab->lookup ("builtin:" + base, 0); - - if (! builtin) - error ("builtin record has gone missing"); - - if (error_state) - return fcn; - - if (builtin->is_read_only ()) - { - // builtin is read only, so checking for updates is pointless - if (builtin->is_function ()) - fcn = builtin->def().function_value (); - else - error ("builtin %s is not a function", base.c_str ()); - } - else - { - // Check that builtin is up to date. - - // Don't try to fight octave's function name handling - // mechanism. Instead, move dispatch record out of the way, - // and restore the builtin to its original name. - symbol_record *dispatch = fbi_sym_tab->lookup (base, 0); - if (! dispatch) - error ("dispatch record has gone missing"); - - dispatch->unprotect (); - - fbi_sym_tab->rename (base, "dispatch:" + base); - - fbi_sym_tab->rename ("builtin:" + base, base); - - // check for updates to builtin function; ignore errors that - // appear (they interfere with renaming), and remove the updated - // name from the current symbol table. FIXME check that - // updating a function updates it in all contexts --- it may be - // that it is updated only in the current symbol table, and not - // the caller. I believe this won't be a problem because the - // caller will go through the same logic and end up with the - // newer version. - fcn = is_valid_function (base, "dispatch", 1); - int cache_error = error_state; - error_state = 0; - curr_sym_tab->clear_function (base); - - // Move the builtin function out of the way and restore the - // dispatch fuction. - // FIXME what if builtin wants to protect itself? - symbol_record *found = fbi_sym_tab->lookup (base, 0); - bool readonly = found->is_read_only (); - found->unprotect (); - fbi_sym_tab->rename (base, "builtin:" + base); - fbi_sym_tab->rename ("dispatch:" + base, base); - if (readonly) - found->protect (); - dispatch->protect (); - - // remember if there were any errors. - error_state = cache_error; - } - - return fcn; -} - -static bool -any_arg_is_magic_colon (const octave_value_list& args) -{ - int nargin = args.length (); - - for (int i = 0; i < nargin; i++) - if (args(i).is_magic_colon ()) - return true; - - return false; -} - -octave_value_list -octave_dispatch::do_multi_index_op (int nargout, const octave_value_list& args) -{ - octave_value_list retval; - - if (error_state) return retval; - - if (any_arg_is_magic_colon (args)) - { - ::error ("invalid use of colon in function argument list"); - return retval; - } - - // If more than one argument, check if argument template matches any - // overloaded functions. Also provide a catch-all '*' type to provide - // single level pseudo rename and replace functionality. - if (args.length () > 0 && tab.count (args(0).type_name ()) > 0) - retval = feval (tab[args(0).type_name()], args, nargout); - else if (has_alias) - retval = feval (tab["any"], args, nargout); - else - { - octave_function *fcn = builtin (base); - if (! error_state && fcn) - retval = fcn->do_multi_index_op (nargout, args); - } - - return retval; -} - -void -octave_dispatch::print (std::ostream& os, bool) const -{ - os << "Overloaded function " << base << std::endl; - - for (Table::const_iterator it = tab.begin (); it != tab.end (); it++) - os << base << "(" << it->first << ",...)->" - << it->second << "(" << it->first << ",...)" - << std::endl; -} - DEFUN_DLD (builtin, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {[@dots{}]} builtin (@var{f}, @dots{})\n\ @@ -304,25 +55,18 @@ { const std::string name (args(0).string_value ()); - if (error_state) - return retval; - - symbol_record *sr = lookup_by_name (name, 0); - - if (sr && sr->is_function ()) + if (! error_state) { - if (sr->def().type_id () == octave_dispatch::static_type_id ()) - { - octave_function *fcn = builtin (name); + octave_value fcn = symbol_table::find_function (name); - if (!error_state && fcn) - retval = fcn->do_multi_index_op (nargout, args.splice (0, 1)); - } + if (fcn.is_defined ()) + retval = feval (fcn.function_value (), args.splice (0, 1), + nargout); else - retval = feval (name, args.splice (0, 1), nargout); + error ("builtin: lookup for symbol `%s' failed", name.c_str ()); } else - error ("builtin: lookup for symbol `%s' failed", name.c_str ()); + error ("builtin: expecting function name as first argument"); } else print_usage (); @@ -330,102 +74,7 @@ return retval; } -static void -dispatch_record (const std::string &f, const std::string &n, - const std::string &t) -{ - // find the base function in the symbol table, loading it if it - // is not already there; if it is already a dispatch, then bonus - - symbol_record *sr = fbi_sym_tab->lookup (f, true); - - if (sr->def().type_id () != octave_dispatch::static_type_id ()) - { - // Preserve mark_as_command status - bool iscommand = sr->is_command (); - - // Not an overloaded name, so if only display or clear then we are done - if (t.empty ()) - return; - - // sr is the base symbol; rename it to keep it safe. When we need - // it we will rename it back again. - if (sr->is_read_only ()) - { - sr->unprotect (); - fbi_sym_tab->rename (f, "builtin:" + f); - sr = fbi_sym_tab->lookup (f, true); - sr->protect (); - } - else - fbi_sym_tab->rename (f, "builtin:" + f); - - // It would be good to hide the builtin:XXX name, but since the - // new XXX name in the symbol table is set to BUILTIN_FUNCTION, - // things don't work quite the way we would like. - // sr->hide (); - - // Problem: when a function is first called a new record - // is created for it in the current symbol table, so calling - // dispatch on a function that has already been called, we - // should also clear it from all existing symbol tables. - // This is too much work, so we will only do it for the - // top level symbol table. We can't use the clear_function() - // method, because it won't clear builtin functions. Instead - // we check if the symbol is a function and clear it then. This - // won't properly clear shadowed functions, or functions in - // other namespaces (such as the current, if called from a - // function). - symbol_record *local = top_level_sym_tab->lookup (f, false); - if (local && local->is_function ()) - local->clear (); - - // Build a new dispatch object based on the function definition - octave_dispatch *dispatch = new octave_dispatch (f); - - // Create a symbol record for the dispatch object. - sr = fbi_sym_tab->lookup (f, true); - sr->unprotect (); - sr->define (octave_value (dispatch), symbol_record::BUILTIN_FUNCTION); - // std::cout << "iscommand('"<mark_as_command(); - sr->document ("\n\n@noindent\nOverloaded function:\n"); - sr->make_eternal (); // FIXME why?? - sr->mark_as_static (); - sr->protect (); - } - - // clear/replace/extend the map with the new type-function pair - const octave_dispatch& rep - = dynamic_cast (sr->def().get_rep ()); - - if (t.empty ()) - // FIXME should return the list if nargout > 1 - rep.print (octave_stdout); - else if (n.empty ()) - { - // FIXME should we eliminate the dispatch function if - // there are no more elements? - // FIXME should clear the " $t:\w+" from the help string. - // FIXME -- seems bad to cast away const here... - octave_dispatch& xrep = const_cast (rep); - - xrep.clear (t); - } - else - { - // FIXME -- seems bad to cast away const here... - octave_dispatch& xrep = const_cast (rep); - - xrep.add (t, n); - - if (! sr->help().empty ()) - sr->document (sr->help() + "\n" + n + " (" + t + ", ...)\n"); - } -} - -DEFUN_DLD (dispatch, args, , +DEFUN_DLD (dispatch, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} dispatch (@var{f}, @var{r}, @var{type})\n\ \n\ @@ -443,40 +92,89 @@ @end deftypefn") { octave_value retval; + int nargin = args.length (); - if (nargin < 1 || nargin > 3) - { - print_usage (); - return retval; - } + std::string f, r, t; - std::string f, t, n; - if (nargin > 0) - f = args(0).string_value (); - - if (nargin == 2) - t = args(1).string_value (); - else if (nargin > 2) + if (nargin > 0 && nargin < 4) { - n = args(1).string_value (); - t = args(2).string_value (); - } + if (nargin > 0) + { + f = args(0).string_value (); + + if (error_state) + { + error ("dispatch: expecting first argument to be function name"); + return retval; + } + } + + if (nargin > 1) + { + r = args(1).string_value (); - if (error_state) - return retval; - - static bool register_type = true; + if (error_state) + { + error ("dispatch: expecting second argument to be function name"); + return retval; + } + } + + if (nargin > 2) + { + t = args(2).string_value (); + + if (error_state) + { + error ("dispatch: expecting third argument to be type name"); + return retval; + } + } - // register dispatch function type if you have not already done so - if (register_type) - { - octave_dispatch::register_type (); - register_type = false; - fbi_sym_tab->lookup("dispatch")->mark_as_static (); + if (nargin == 1) + { + if (nargout > 0) + { + symbol_table::fcn_info::dispatch_map_type dm + = symbol_table::get_dispatch (f); + + size_t len = dm.size (); + + Cell type_field (len, 1); + Cell name_field (len, 1); + + symbol_table::fcn_info::dispatch_map_type::const_iterator p + = dm.begin (); + + for (size_t i = 0; i < len; i++) + { + type_field(i) = p->first; + name_field(i) = p->second; + + p++; + } + + Octave_map m; + + m.assign ("type", type_field); + m.assign ("name", name_field); + + retval = m; + } + else + symbol_table::print_dispatch (octave_stdout, f); + } + else if (nargin == 2) + { + t = r; + symbol_table::clear_dispatch (f, t); + } + else + symbol_table::add_dispatch (f, t, r); } - - dispatch_record (f, n, t); + else + print_usage (); return retval; } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/Makefile.in --- a/src/Makefile.in Fri Feb 01 23:56:51 2008 -0500 +++ b/src/Makefile.in Fri Dec 28 20:56:58 2007 +0000 @@ -100,7 +100,7 @@ ov-streamoff.h ov-str-mat.h ov-bool-mat.h ov-bool.h \ ov-cell.h ov.h ov-fcn.h ov-builtin.h ov-dld-fcn.h \ ov-mapper.h ov-mex-fcn.h ov-usr-fcn.h ov-fcn-handle.h \ - ov-fcn-inline.h ov-typeinfo.h ov-type-conv.h \ + ov-fcn-inline.h ov-class.h ov-typeinfo.h ov-type-conv.h \ $(OV_INTTYPE_INC) OV_SPARSE_INCLUDES := \ @@ -129,7 +129,7 @@ $(PT_INCLUDES) \ $(OV_SPARSE_INCLUDES) -TI_XSRC := Array-os.cc Array-sym.cc Array-tc.cc +TI_XSRC := Array-os.cc Array-tc.cc TI_SRC := $(addprefix TEMPLATE-INST/, $(TI_XSRC)) @@ -144,8 +144,8 @@ op-sm-cs.cc op-sm-m.cc op-sm-s.cc op-sm-scm.cc op-sm-sm.cc \ op-s-scm.cc op-s-sm.cc -OP_XSRC := op-b-b.cc op-b-bm.cc op-bm-b.cc op-bm-bm.cc \ - op-cell.cc op-chm.cc op-cm-cm.cc op-cm-cs.cc op-cm-m.cc \ +OP_XSRC := op-b-b.cc op-b-bm.cc op-bm-b.cc op-bm-bm.cc op-cell.cc \ + op-chm.cc op-class.cc op-cm-cm.cc op-cm-cs.cc op-cm-m.cc \ op-cm-s.cc op-cs-cm.cc op-cs-cs.cc op-cs-m.cc \ op-cs-s.cc op-list.cc op-m-cm.cc \ op-m-cs.cc op-m-m.cc op-m-s.cc op-range.cc op-s-cm.cc \ @@ -172,7 +172,7 @@ ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-cell.cc \ ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc ov-mapper.cc \ ov-mex-fcn.cc ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc \ - ov-typeinfo.cc \ + ov-class.cc ov-typeinfo.cc \ $(OV_INTTYPE_SRC) \ $(OV_SPARSE_SRC) @@ -193,7 +193,7 @@ octave.cc zfstream.cc oct-strstrm.cc oct-lvalue.cc pager.cc \ parse.y pr-output.cc procstream.cc sighandlers.cc \ siglist.c sparse-xdiv.cc sparse-xpow.cc strfns.cc \ - symtab.cc syscalls.cc sysdep.cc token.cc toplev.cc \ + syscalls.cc symtab.cc sysdep.cc token.cc toplev.cc \ unwind-prot.cc utils.cc variables.cc xdiv.cc xpow.cc \ $(OV_SRC) \ $(PT_SRC) diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/debug.cc --- a/src/debug.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/debug.cc Fri Dec 28 20:56:58 2007 +0000 @@ -70,23 +70,9 @@ dbg_fcn = octave_call_stack::caller_user_function (); else { - symbol_record *ptr = curr_sym_tab->lookup (fname); + octave_value fcn = symbol_table::find_user_function (fname); - if (ptr && ptr->is_user_function ()) - { - octave_value tmp = ptr->def (); - dbg_fcn = dynamic_cast (tmp.function_value ()); - } - else - { - ptr = lookup_by_name (fname, false); - - if (ptr && ptr->is_user_function ()) - { - octave_value tmp = ptr->def (); - dbg_fcn = dynamic_cast (tmp.function_value ()); - } - } + dbg_fcn = fcn.user_function_value (); } return dbg_fcn; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/defun-dld.h --- a/src/defun-dld.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/defun-dld.h Fri Dec 28 20:56:58 2007 +0000 @@ -50,7 +50,7 @@ // quoted string, and the internal name of the function must be passed // too (the convention is to use a prefix of "F", so "foo" becomes "Ffoo"). -#define DEFUNX_DLD(name, fname, fsname, args_name, nargout_name, doc) \ +#define DEFUNX_DLD(name, fname, fsname, gname, args_name, nargout_name, doc) \ DEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, false, doc) #else @@ -60,9 +60,9 @@ DEFINE_FUN_INSTALLER_FUN (name, doc) \ DECLARE_FUN (name, args_name, nargout_name) -#define DEFUNX_DLD(name, fname, fsname, args_name, nargout_name, doc) \ +#define DEFUNX_DLD(name, fname, fsname, gname, args_name, nargout_name, doc) \ DECLARE_FUNX (fname, args_name, nargout_name); \ - DEFINE_FUNX_INSTALLER_FUN (name, fname, fsname, doc) \ + DEFINE_FUNX_INSTALLER_FUN (name, fname, fsname, gname, doc) \ DECLARE_FUNX (fname, args_name, nargout_name) #endif diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/defun-int.h --- a/src/defun-int.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/defun-int.h Fri Dec 28 20:56:58 2007 +0000 @@ -40,7 +40,7 @@ extern OCTINTERP_API void check_version (const std::string& version, const std::string& fcn); extern OCTINTERP_API void -install_builtin_mapper (octave_mapper *mf); +install_builtin_mapper (octave_mapper *mf, const std::string& name); extern OCTINTERP_API void install_builtin_function (octave_builtin::fcn f, const std::string& name, @@ -74,6 +74,8 @@ typedef bool (*octave_dld_fcn_installer) (const octave_shlib&, bool relative); +typedef octave_function * (*octave_dld_fcn_getter) (const octave_shlib&, bool relative); + #define DEFINE_FUN_INSTALLER_FUN(name, doc) \ DEFINE_FUN_INSTALLER_FUN2(name, doc, CXX_ABI) @@ -81,15 +83,15 @@ DEFINE_FUN_INSTALLER_FUN3(name, doc, cxx_abi) #define DEFINE_FUN_INSTALLER_FUN3(name, doc, cxx_abi) \ - DEFINE_FUNX_INSTALLER_FUN3(#name, F ## name, FS ## name, doc, cxx_abi) + DEFINE_FUNX_INSTALLER_FUN3(#name, F ## name, FS ## name, G ## name, doc, cxx_abi) -#define DEFINE_FUNX_INSTALLER_FUN(name, fname, fsname, doc) \ - DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, doc, CXX_ABI) +#define DEFINE_FUNX_INSTALLER_FUN(name, fname, fsname, gname, doc) \ + DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, gname, doc, CXX_ABI) -#define DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, doc, cxx_abi) \ - DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, doc, cxx_abi) +#define DEFINE_FUNX_INSTALLER_FUN2(name, fname, fsname, gname, doc, cxx_abi) \ + DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, gname, doc, cxx_abi) -#define DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, doc, cxx_abi) \ +#define DEFINE_FUNX_INSTALLER_FUN3(name, fname, fsname, gname, doc, cxx_abi) \ extern "C" \ OCTAVE_EXPORT \ bool \ @@ -105,6 +107,28 @@ install_dld_function (fname, name, shl, doc, false, relative); \ \ return retval; \ + } \ + \ + extern "C" \ + OCTAVE_EXPORT \ + octave_function * \ + gname ## _ ## cxx_abi (const octave_shlib& shl, bool relative) \ + { \ + octave_function *retval = 0; \ + \ + check_version (OCTAVE_API_VERSION, name); \ + \ + if (! error_state) \ + { \ + octave_dld_function *fcn = new octave_dld_function (fname, shl, name, doc); \ + \ + if (relative) \ + fcn->mark_relative (); \ + \ + retval = fcn; \ + } \ + \ + return retval; \ } // MAKE_BUILTINS is defined to extract function names and related @@ -193,8 +217,9 @@ ch_map_flag, can_ret_cmplx_for_real, doc) \ install_builtin_mapper \ (new octave_mapper \ - (ch_map, d_b_map, c_b_map, d_d_map, d_c_map, c_c_map, \ - lo, hi, ch_map_flag, can_ret_cmplx_for_real, #name, doc)) + (ch_map, d_b_map, c_b_map, d_d_map, d_c_map, c_c_map, \ + lo, hi, ch_map_flag, can_ret_cmplx_for_real, #name, doc), \ + #name) #endif /* ! MAKE_BUILTINS */ diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/defun.cc --- a/src/defun.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/defun.cc Fri Dec 28 20:56:58 2007 +0000 @@ -129,18 +129,9 @@ // Install variables and functions in the symbol tables. void -install_builtin_mapper (octave_mapper *mf) +install_builtin_mapper (octave_mapper *mf, const std::string& name) { - symbol_record *sym_rec = fbi_sym_tab->lookup (mf->name (), true); - - unsigned int t - = symbol_record::BUILTIN_FUNCTION | symbol_record::MAPPER_FUNCTION; - - sym_rec->unprotect (); - sym_rec->define (mf, t); - sym_rec->document (mf->doc_string ()); - sym_rec->make_eternal (); - sym_rec->protect (); + symbol_table::install_built_in_function (name, octave_value (mf)); } void @@ -148,18 +139,12 @@ const std::string& doc, bool is_text_fcn, bool /* can_hide_function -- not yet implemented */) { - symbol_record *sym_rec = fbi_sym_tab->lookup (name, true); + octave_value fcn (new octave_builtin (f, name, doc)); - unsigned int t = symbol_record::BUILTIN_FUNCTION; + symbol_table::install_built_in_function (name, fcn); if (is_text_fcn) - t |= symbol_record::COMMAND; - - sym_rec->unprotect (); - sym_rec->define (new octave_builtin (f, name, doc), t); - sym_rec->document (doc); - sym_rec->make_eternal (); - sym_rec->protect (); + mark_as_command (name); } void @@ -168,30 +153,17 @@ const std::string& doc, bool is_text_fcn, bool relative) { - symbol_record *sym_rec = fbi_sym_tab->lookup (name, true); - - unsigned int t = symbol_record::DLD_FUNCTION; - - if (is_text_fcn) - t |= symbol_record::COMMAND; - - sym_rec->unprotect (); - - octave_dld_function *df = new octave_dld_function (f, shl, name, doc); + octave_dld_function *fcn = new octave_dld_function (f, shl, name, doc); if (relative) - df->mark_relative (); + fcn->mark_relative (); - sym_rec->define (df, t); - sym_rec->document (doc); + octave_value fval (fcn); - // Also insert the full name in the symbol table. This way, we can - // properly cope with changes to LOAD_PATH. + symbol_table::install_built_in_function (name, fval); - symbol_record *full_sr = fbi_sym_tab->lookup (shl.file_name (), true); - - full_sr->alias (sym_rec, true); - full_sr->hide (); + if (is_text_fcn) + mark_as_command (name); } void @@ -199,89 +171,25 @@ const octave_shlib& shl, bool is_text_fcn, bool relative) { - symbol_record *sym_rec = fbi_sym_tab->lookup (name, true); - - unsigned int t = symbol_record::MEX_FUNCTION; - - if (is_text_fcn) - t |= symbol_record::COMMAND; - - sym_rec->unprotect (); - - octave_mex_function *mf = new octave_mex_function (fptr, fmex, shl, name); + octave_mex_function *fcn = new octave_mex_function (fptr, fmex, shl, name); if (relative) - mf->mark_relative (); + fcn->mark_relative (); - sym_rec->define (mf, t); + octave_value fval (fcn); - // Also insert the full name in the symbol table. This way, we can - // properly cope with changes to LOAD_PATH. + symbol_table::install_built_in_function (name, fval); - symbol_record *full_sr = fbi_sym_tab->lookup (shl.file_name (), true); - - full_sr->alias (sym_rec, true); - full_sr->hide (); + if (is_text_fcn) + mark_as_command (name); } void alias_builtin (const std::string& alias, const std::string& name) { - symbol_record *sr_name = fbi_sym_tab->lookup (name); - - if (! sr_name) - panic ("can't alias to undefined name!"); - - symbol_record *sr_alias = fbi_sym_tab->lookup (alias, true); - - if (sr_alias) - sr_alias->alias (sr_name); - else - panic ("can't find symbol record for builtin function `%s'", - alias.c_str ()); + symbol_table::alias_built_in_function (alias, name); } -#if 0 -// This is insufficient to really make it possible to define an alias -// for function. There are a number of subtle problems related to -// automatically reloading functions. -DEFUN (alias, args, , - "alias (alias, name)") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 2) - { - string alias = args(0).string_value (); - string name = args(1).string_value (); - - if (! error_state) - { - symbol_record *sr_name = lookup_by_name (name, false); - - if (sr_name && sr_name->is_function ()) - { - symbol_record *sr_alias = fbi_sym_tab->lookup (alias, true); - - if (sr_alias) - sr_alias->alias (sr_name); - else - error ("alias: unable to insert `%s' in symbol table", - alias.c_str ()); - } - else - error ("alias: function `%s' does not exist", name.c_str ()); - } - } - else - print_usage (); - - return retval; -} -#endif - /* ;;; Local Variables: *** ;;; mode: C++ *** diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/dynamic-ld.cc --- a/src/dynamic-ld.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/dynamic-ld.cc Fri Dec 28 20:56:58 2007 +0000 @@ -35,6 +35,9 @@ #include "defun.h" #include "dynamic-ld.h" +#include "ov-fcn.h" +#include "ov-dld-fcn.h" +#include "ov-mex-fcn.h" #include "parse.h" #include "unwind-prot.h" #include "utils.h" @@ -295,12 +298,7 @@ { warning_with_id ("Octave:reload-forces-clear", " %s", fcn_name.c_str ()); - curr_sym_tab->clear (fcn_name); - - if (curr_sym_tab != top_level_sym_tab) - top_level_sym_tab->clear (fcn_name); - - fbi_sym_tab->clear (fcn_name); + symbol_table::clear_user_function (fcn_name); } static void @@ -314,12 +312,12 @@ octave_shlib_list::remove (oct_file, do_clear_function); } -bool +octave_function * octave_dynamic_loader::do_load_oct (const std::string& fcn_name, const std::string& file_name, bool relative) { - bool retval = false; + octave_function *retval = 0; octave_shlib oct_file; @@ -330,7 +328,7 @@ doing_load = true; void *function - = octave_shlib_list::search (fcn_name, oct_file, mangle_name); + = octave_shlib_list::search (fcn_name, oct_file, xmangle_name); if (! error_state) { @@ -377,7 +375,7 @@ octave_shlib_list::append (oct_file); - function = oct_file.search (fcn_name, mangle_name); + function = oct_file.search (fcn_name, xmangle_name); } else ::error ("%s is not a valid shared library", @@ -389,8 +387,8 @@ if (function) { - octave_dld_fcn_installer f - = FCN_PTR_CAST (octave_dld_fcn_installer, function); + octave_dld_fcn_getter f + = FCN_PTR_CAST (octave_dld_fcn_getter, function); retval = f (oct_file, relative); @@ -404,12 +402,12 @@ return retval; } -bool +octave_function * octave_dynamic_loader::do_load_mex (const std::string& fcn_name, const std::string& file_name, bool relative) { - bool retval = false; + octave_function *retval = 0; octave_shlib mex_file; @@ -467,11 +465,7 @@ } if (function) - { - install_mex_function (function, have_fmex, fcn_name, mex_file, relative); - - retval = true; - } + retval = new octave_mex_function (function, have_fmex, mex_file, fcn_name); else ::error ("failed to install .mex file function `%s'", fcn_name.c_str ()); @@ -499,22 +493,22 @@ return retval; } -bool +octave_function * octave_dynamic_loader::load_oct (const std::string& fcn_name, - const std::string& file_name, - bool relative) + const std::string& file_name, + bool relative) { return (instance_ok ()) - ? instance->do_load_oct (fcn_name, file_name, relative) : false; + ? instance->do_load_oct (fcn_name, file_name, relative) : 0; } -bool +octave_function * octave_dynamic_loader::load_mex (const std::string& fcn_name, - const std::string& file_name, - bool relative) + const std::string& file_name, + bool relative) { return (instance_ok ()) - ? instance->do_load_mex (fcn_name, file_name, relative) : false; + ? instance->do_load_mex (fcn_name, file_name, relative) : 0; } bool @@ -537,6 +531,20 @@ return retval; } +std::string +octave_dynamic_loader::xmangle_name (const std::string& name) +{ +#if defined (CXX_PREPENDS_UNDERSCORE) + std::string retval ("_G"); +#else + std::string retval ("G"); +#endif + retval.append (name); + retval.append ("_"); + retval.append (STRINGIFY (CXX_ABI)); + return retval; +} + /* ;;; Local Variables: *** ;;; mode: C++ *** diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/dynamic-ld.h --- a/src/dynamic-ld.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/dynamic-ld.h Fri Dec 28 20:56:58 2007 +0000 @@ -28,6 +28,8 @@ #include "oct-shlib.h" +class octave_function; + class octave_dynamic_loader { @@ -39,13 +41,15 @@ virtual ~octave_dynamic_loader (void) { } - static bool load_oct (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); + static octave_function * + load_oct (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); - static bool load_mex (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); + static octave_function * + load_mex (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); static bool remove (const std::string& fcn_name, octave_shlib& shl); @@ -61,13 +65,15 @@ static bool instance_ok (void); - bool do_load_oct (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); + octave_function * + do_load_oct (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); - bool do_load_mex (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); + octave_function * + do_load_mex (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); bool do_remove (const std::string& fcn_name, octave_shlib& shl); @@ -76,6 +82,8 @@ protected: static std::string mangle_name (const std::string& name); + + static std::string xmangle_name (const std::string& name); }; #endif diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/error.cc --- a/src/error.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/error.cc Fri Dec 28 20:56:58 2007 +0000 @@ -643,7 +643,7 @@ } else if (warn_opt == 1) { - if (curr_sym_tab != top_level_sym_tab + if (symbol_table::at_top_level () && Vbacktrace_on_warning && ! warning_state && ! discard_warning_messages) diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/file-io.cc --- a/src/file-io.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/file-io.cc Fri Dec 28 20:56:58 2007 +0000 @@ -44,6 +44,7 @@ #include #include +#include #include #ifdef HAVE_UNISTD_H diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/help.cc --- a/src/help.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/help.cc Fri Dec 28 20:56:58 2007 +0000 @@ -61,6 +61,7 @@ #include "parse.h" #include "pathsearch.h" #include "procstream.h" +#include "pt-pr-code.h" #include "sighandlers.h" #include "symtab.h" #include "syswait.h" @@ -563,18 +564,20 @@ string_vector key = names (keyword_help ()); int key_len = key.length (); - string_vector fbi = fbi_sym_tab->name_list (); - int fbi_len = fbi.length (); + string_vector bif = symbol_table::built_in_function_names (); + int bif_len = bif.length (); - string_vector glb = global_sym_tab->name_list (); + string_vector glb + = symbol_table::variable_names (symbol_table::global_scope ()); int glb_len = glb.length (); - string_vector top = top_level_sym_tab->name_list (); + string_vector top + = symbol_table::variable_names (symbol_table::top_scope ()); int top_len = top.length (); string_vector lcl; - if (top_level_sym_tab != curr_sym_tab) - lcl = curr_sym_tab->name_list (); + if (! symbol_table::at_top_level ()) + lcl = symbol_table::variable_names (); int lcl_len = lcl.length (); string_vector ffl = load_path::fcn_names (); @@ -583,7 +586,8 @@ string_vector afl = autoloaded_functions (); int afl_len = afl.length (); - int total_len = key_len + fbi_len + glb_len + top_len + lcl_len + ffl_len + afl_len; + int total_len = key_len + bif_len + glb_len + top_len + lcl_len + + ffl_len + afl_len; string_vector list (total_len); @@ -594,8 +598,8 @@ for (i = 0; i < key_len; i++) list[j++] = key[i]; - for (i = 0; i < fbi_len; i++) - list[j++] = fbi[i]; + for (i = 0; i < bif_len; i++) + list[j++] = bif[i]; for (i = 0; i < glb_len; i++) list[j++] = glb[i]; @@ -649,28 +653,19 @@ } static void -display_symtab_names (std::ostream& os, const string_vector& names, +display_symtab_names (std::ostream& os, const std::list& names, const std::string& desc) { if (! names.empty ()) { os << "\n*** " << desc << ":\n\n"; - names.list_in_columns (os); + + string_vector sv (names); + + sv.list_in_columns (os); } } -#ifdef LIST_SYMBOLS -#undef LIST_SYMBOLS -#endif -#define LIST_SYMBOLS(type, msg) \ - do \ - { \ - string_vector names \ - = fbi_sym_tab->name_list (string_vector (), true, type); \ - display_symtab_names (octave_stdout, names, msg); \ - } \ - while (0) - static void simple_help (void) { @@ -684,18 +679,11 @@ display_names_from_help_list (octave_stdout, keyword_help (), "reserved words"); - // FIXME -- is this distinction needed? - - LIST_SYMBOLS (symbol_record::COMMAND, "commands"); - - LIST_SYMBOLS (symbol_record::MAPPER_FUNCTION, "mapper functions"); + display_symtab_names (octave_stdout, + symbol_table::built_in_function_names (), + "built-in functions"); - LIST_SYMBOLS (symbol_record::BUILTIN_FUNCTION, "general functions"); - - // Also need to list variables and currently compiled functions from - // the symbol table, if there are any. - - // Also need to search octave_path for script files. + // FIXME -- list functions defined on command line? load_path::display (octave_stdout); @@ -944,80 +932,34 @@ return retval; } -std::string -extract_help_from_dispatch (const std::string& nm) -{ - std::string retval; - - symbol_record *builtin = fbi_sym_tab->lookup ("builtin:" + nm, 0); - - if (builtin) - { - // Check that builtin is up to date. - - // Don't try to fight octave's function name handling - // mechanism. Instead, move dispatch record out of the way, - // and restore the builtin to its original name. - symbol_record *dispatch = fbi_sym_tab->lookup (nm, 0); - - if (dispatch) - { - dispatch->unprotect (); - - fbi_sym_tab->rename (nm, "dispatch:" + nm); - fbi_sym_tab->rename ("builtin:" + nm, nm); - - // Check for updates to builtin function; ignore errors - // that appear (they interfere with renaming), and remove - // the updated name from the current symbol table. FIXME -- - // check that updating a function updates it in all - // contexts. It may be that it is updated only in the - // current symbol table, and not the caller. I believe this - // won't be a problem because the caller will go through the - // same logic and end up with the newer version. - - octave_function *f = is_valid_function (nm); - - if (f) - retval = builtin->help (); - - curr_sym_tab->clear_function (nm); - - // Move the builtin function out of the way and restore the - // dispatch fuction. FIXME what if builtin wants to - // protect itself? - - fbi_sym_tab->rename (nm, "builtin:" + nm); - fbi_sym_tab->rename ("dispatch:" + nm, nm); - - dispatch->protect (); - } - else - error ("failed to find dispatch record for `builtin:%s'", nm.c_str ()); - } - - return retval; -} - static bool raw_help_from_symbol_table (const std::string& nm, std::string& h, std::string& w, bool& symbol_found) { bool retval = false; - symbol_record *sym_rec = lookup_by_name (nm, 0); + octave_value val = symbol_table::find_function (nm); - if (sym_rec && sym_rec->is_defined ()) + if (val.is_defined ()) { - symbol_found = true; + octave_function *fcn = val.function_value (); + + if (fcn) + { + symbol_found = true; - h = sym_rec->help (); + h = fcn->doc_string (); + + if (! h.empty ()) + { + retval = true; - if (h.length () > 0) - { - w = sym_rec->which (); + w = fcn->fcn_file_name (); - retval = true; + if (w.empty ()) + w = fcn->is_user_function () + ? "command-line function" : "built-in function"; + } } } @@ -1037,7 +979,7 @@ { if (h.length () > 0) { - h = extract_help_from_dispatch (nm) + h; + h += "\n\n@noindent\n" + symbol_table::help_for_dispatch (nm); display_help_text (os, h); @@ -1193,36 +1135,82 @@ } static void +display_file (std::ostream& os, const std::string& name, + const std::string& fname, const std::string& type, + bool pr_type_info, bool quiet) +{ + std::ifstream fs (fname.c_str (), std::ios::in); + + if (fs) + { + if (pr_type_info && ! quiet) + os << name << " is the " << type + << " defined from: " << fname << "\n\n"; + + char ch; + + while (fs.get (ch)) + os << ch; + } + else + os << "unable to open `" << fname << "' for reading!\n"; +} + +static void do_type (std::ostream& os, const std::string& name, bool pr_type_info, bool quiet, bool pr_orig_txt) { - symbol_record *sym_rec = lookup_by_name (name, 0); + // FIXME -- should we bother with variables here (earlier versions + // of Octave displayed them)? + + octave_value val = symbol_table::varval (name); - if (sym_rec && sym_rec->is_defined ()) - sym_rec->type (os, pr_type_info, quiet, pr_orig_txt); + if (val.is_defined ()) + { + if (pr_type_info && ! quiet) + os << name << " is a variable\n"; + + val.print_raw (os, pr_orig_txt); + + if (pr_type_info) + os << "\n"; + } else { - std::string ff = fcn_file_in_path (name); + val = symbol_table::find_function (name); - if (! ff.empty ()) + if (val.is_defined ()) { - std::ifstream fs (ff.c_str (), std::ios::in); + octave_function *fcn = val.function_value (); + + std::string fn = fcn ? fcn->fcn_file_name () : std::string (); - if (fs) + if (pr_orig_txt && ! fn.empty ()) + display_file (os, name, fn, "function", pr_type_info, quiet); + else { if (pr_type_info && ! quiet) - os << name << " is the script file: " << ff << "\n\n"; - - char ch; + { + std::string type + = fcn->is_user_function () ? "command-line" : "built-in"; - while (fs.get (ch)) - os << ch; + os << name << " is a " << type << " function:\n\n"; + } + + tree_print_code tpc (os, "", pr_orig_txt); + + fcn->accept (tpc); } - else - os << "unable to open `" << ff << "' for reading!\n"; } else - error ("type: `%s' undefined", name.c_str ()); + { + std::string fn = fcn_file_in_path (name); + + if (! fn.empty ()) + display_file (os, name, fn, "script", pr_type_info, quiet); + else + error ("type: `%s' undefined", name.c_str ()); + } } } @@ -1298,35 +1286,64 @@ std::string do_which (const std::string& name) { - std::string retval; + octave_value val = symbol_table::find_function (name); - symbol_record *sym_rec = lookup_by_name (name, 0); + if (val.is_defined ()) + { + octave_function *fcn = val.function_value (); - if (sym_rec && sym_rec->is_defined ()) - retval = sym_rec->which (); - else - retval = fcn_file_in_path (name); + if (fcn) + { + std::string fn = fcn->fcn_file_name (); - return retval; + return fn.empty () + ? (fcn->is_user_function () + ? "command-line function" : "built-in function") + : fn; + } + } + + return fcn_file_in_path (name); } static void do_which (std::ostream& os, const std::string& name) { - symbol_record *sym_rec = lookup_by_name (name, 0); + std::string desc; - if (sym_rec && sym_rec->is_defined ()) - sym_rec->which (os); - else + octave_value val = symbol_table::find_function (name); + + if (val.is_defined ()) { - std::string path = fcn_file_in_path (name); + octave_function *fcn = val.function_value (); + + if (fcn) + { + desc = fcn->fcn_file_name (); - if (! path.empty ()) - os << "which: `" << name << "' is the script file\n" - << path << "\n"; + if (desc.empty ()) + { + if (fcn->is_user_function ()) + desc = "is a command-line function"; + else + desc = "is a built-in function"; + } + else + desc = "is the function from the file " + desc; + } + } + + if (desc.empty ()) + { + std::string fn = fcn_file_in_path (name); + + if (! fn.empty ()) + desc = "is the script file " + fn; else - os << "which: `" << name << "' is undefined\n"; + desc = "is undefined"; } + + os << "which: `" << name << "' " << desc << std::endl; } DEFCMD (which, args, nargout, @@ -1764,6 +1781,7 @@ @end deffn") { octave_value_list retval; + int nargin = args.length (); bool first_sentence_only = true; @@ -1897,9 +1915,11 @@ ptr++; } + string_vector names; + +#ifdef OLD_SYMTAB // Check the symbol record table - string_vector names - = fbi_sym_tab->name_list (string_vector (), true); + names = fbi_sym_tab->name_list (string_vector (), true); for (octave_idx_type i = 0; i < names.length (); i++) { @@ -1947,6 +1967,7 @@ } } } +#endif string_vector dirs = load_path::dirs (); @@ -1973,6 +1994,7 @@ else continue; +#ifdef OLD_SYMTAB // Check if already in symbol table symbol_record *sr = fbi_sym_tab->lookup (name); @@ -2037,6 +2059,7 @@ } } } +#endif // Check if this function has autoloaded functions attached to it std::string file_name = load_path::find_fcn (name); @@ -2049,6 +2072,7 @@ { std::string aname = autoload_fcns (k); +#ifdef OLD_SYMTAB // Check if already in symbol table sr = fbi_sym_tab->lookup (aname); @@ -2094,6 +2118,7 @@ } } } +#endif } } } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/help.h --- a/src/help.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/help.h Fri Dec 28 20:56:58 2007 +0000 @@ -31,8 +31,6 @@ extern string_vector make_name_list (void); -extern std::string extract_help_from_dispatch (const std::string&); - extern void display_help_text (std::ostream&, const std::string&); extern void display_usage_text (std::ostream&, const std::string&); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/input.cc --- a/src/input.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/input.cc Fri Dec 28 20:56:58 2007 +0000 @@ -66,7 +66,6 @@ #include "pt-const.h" #include "pt-stmt.h" #include "sighandlers.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" @@ -265,7 +264,7 @@ // There is no need to update the load_path cache if there is no // user input. - if (! retval.empty ()) + if (! retval.empty () && retval.find_first_not_of (" \t\n\r") != NPOS) load_path::update (); } else diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/lex.h --- a/src/lex.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/lex.h Fri Dec 28 20:56:58 2007 +0000 @@ -119,6 +119,9 @@ // -1 ==> Yes, but it is the last one because we have seen EOF. int parsing_nested_function; + // TRUE means we are parsing a class method. + bool parsing_class_method; + // Return transpose or start a string? bool quote_is_transpose; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/lex.l --- a/src/lex.l Fri Feb 01 23:56:51 2008 -0500 +++ b/src/lex.l Fri Dec 28 20:56:58 2007 +0000 @@ -242,7 +242,6 @@ static int is_keyword_token (const std::string& s); static void prep_for_function (void); static void prep_for_nested_function (void); -static symbol_record *lookup_identifier (const std::string& s); static std::string grab_help_text (void); static bool match_any (char c, const char *s); static bool next_token_is_sep_op (void); @@ -844,6 +843,8 @@ while (! symtab_context.empty ()) symtab_context.pop (); + symbol_table::reset_parent_scope (); + // We do want a prompt by default. promptflag = 1; @@ -959,10 +960,6 @@ { end_tokens_expected++; - // Prepare for local symbols. - - tmp_local_sym_tab = new symbol_table (); - promptflag--; lexer_flags.defining_func = true; @@ -1174,39 +1171,19 @@ return 0; } -// Try to find an identifier. All binding to global or builtin -// variables occurs when expressions are evaluated. - -static symbol_record * -lookup_identifier (const std::string& name) -{ - std::string sym_name = name; - - if (curr_sym_tab == fbi_sym_tab - && lexer_flags.parsing_nested_function) - sym_name = parent_function_name + ":" + sym_name; - - return curr_sym_tab->lookup (sym_name, true); -} - static bool is_variable (const std::string& name) { - symbol_record *sr = curr_sym_tab->lookup (name); - - return sr && sr->is_variable (); + return symbol_table::is_variable (name); } static void force_local_variable (const std::string& name) { - if (! is_variable (name)) - curr_sym_tab->clear (name); - - symbol_record *sr = curr_sym_tab->lookup (name, true); - - if (sr) - sr->define (octave_value ()); + octave_value& val = symbol_table::varref (name); + + if (! val.is_defined ()) + val = Matrix (); } // Grab the help text from an function file. @@ -2307,19 +2284,6 @@ yyunput (c1, yytext); - // Make sure we put the return values of a function in the symbol - // table that is local to the function. - - // If we are defining a function and we have not seen the function - // name yet and the next token is `=', then this identifier must be - // the only return value for the function and it belongs in the - // local symbol table. - - if (next_tok_is_eq - && lexer_flags.defining_func - && ! lexer_flags.parsed_function_name) - curr_sym_tab = tmp_local_sym_tab; - // Kluge alert. // // If we are looking at a text style function, set up to gobble its @@ -2357,9 +2321,13 @@ if (tok == "end") tok = "__end__"; - yylval.tok_val = new token (lookup_identifier (tok), - input_line_number, - current_input_column); + yylval.tok_val = new token (&(symbol_table::insert (tok)), + input_line_number, current_input_column); + + // FIXME -- this forces a link for tok in the chain of variables for + // the current scope. Probably this step should be done + // differently, maybe in symbol_table::insert? + symbol_table::varref (tok); token_stack.push (yylval.tok_val); @@ -2399,6 +2367,7 @@ defining_func = false; parsed_function_name = false; parsing_nested_function = 0; + parsing_class_method = false; // Not initiallly looking at a function handle. looking_at_function_handle = 0; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/load-path.cc --- a/src/load-path.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/load-path.cc Fri Dec 28 20:56:58 2007 +0000 @@ -43,8 +43,8 @@ #include "utils.h" load_path *load_path::instance = 0; -load_path::hook_function_ptr load_path::add_hook = execute_pkg_add; -load_path::hook_function_ptr load_path::remove_hook = execute_pkg_del; +load_path::hook_fcn_ptr load_path::add_hook = execute_pkg_add; +load_path::hook_fcn_ptr load_path::remove_hook = execute_pkg_del; std::string load_path::command_line_path; std::string load_path::sys_path; @@ -81,17 +81,7 @@ { dir_mtime = fs.mtime (); - bool has_private_subdir = get_file_list (dir_name); - - if (! error_state) - { - if (has_private_subdir) - { - std::string pdn = file_ops::concat (dir_name, "private"); - - get_private_function_map (pdn); - } - } + get_file_list (dir_name); } else { @@ -100,11 +90,9 @@ } } -bool +void load_path::dir_info::get_file_list (const std::string& d) { - bool has_private_subdir = false; - dir_entry dir (d); if (dir) @@ -131,8 +119,10 @@ { if (fs.is_dir ()) { - if (! has_private_subdir && fname == "private") - has_private_subdir = true; + if (fname == "private") + get_private_file_map (full_name); + else if (fname[0] == '@') + get_method_file_map (full_name, fname.substr (1)); } else { @@ -164,13 +154,13 @@ std::string msg = dir.error (); warning ("load_path: %s: %s", d.c_str (), msg.c_str ()); } - - return has_private_subdir; } -void -load_path::dir_info::get_private_function_map (const std::string& d) +load_path::dir_info::fcn_file_map_type +get_fcn_files (const std::string& d) { + load_path::dir_info::fcn_file_map_type retval; + dir_entry dir (d); if (dir) @@ -204,7 +194,7 @@ else if (ext == ".mex") t = load_path::MEX_FILE; - private_function_map[base] |= t; + retval[base] |= t; } } } @@ -214,6 +204,21 @@ std::string msg = dir.error (); warning ("load_path: %s: %s", d.c_str (), msg.c_str ()); } + + return retval; +} + +void +load_path::dir_info::get_private_file_map (const std::string& d) +{ + private_file_map = get_fcn_files (d); +} + +void +load_path::dir_info::get_method_file_map (const std::string& d, + const std::string& class_name) +{ + method_file_map[class_name] = get_fcn_files (d); } bool @@ -234,6 +239,9 @@ return retval; } +// FIXME -- maybe we should also maintain a map to speed up this +// method of access. + load_path::const_dir_info_list_iterator load_path::find_dir_info (const std::string& dir_arg) const { @@ -277,51 +285,81 @@ } void -load_path::move (dir_info_list_iterator i, bool at_end) +load_path::move_fcn_map (const std::string& dir_name, + const string_vector& fcn_files, bool at_end) { - if (dir_info_list.size () > 1) + octave_idx_type len = fcn_files.length (); + + for (octave_idx_type k = 0; k < len; k++) { - dir_info di = *i; - - dir_info_list.erase (i); + std::string fname = fcn_files[k]; - if (at_end) - dir_info_list.push_back (di); - else - dir_info_list.push_front (di); + std::string ext; + std::string base = fname; + + size_t pos = fname.rfind ('.'); - std::string dir = di.dir_name; + if (pos != NPOS) + { + base = fname.substr (0, pos); + ext = fname.substr (pos); + } - string_vector fcn_files = di.fcn_files; + file_info_list_type& file_info_list = fcn_map[base]; - octave_idx_type len = fcn_files.length (); - - for (octave_idx_type k = 0; k < len; k++) + if (file_info_list.size () == 1) + continue; + else { - std::string fname = fcn_files[k]; + for (file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + if (p->dir_name == dir_name) + { + file_info fi = *p; - std::string ext; - std::string base = fname; + file_info_list.erase (p); + + if (at_end) + file_info_list.push_back (fi); + else + file_info_list.push_front (fi); - size_t pos = fname.rfind ('.'); + break; + } + } + } + } +} - if (pos != NPOS) - { - base = fname.substr (0, pos); - ext = fname.substr (pos); - } +void +load_path::move_method_map (const std::string& dir_name, bool at_end) +{ + for (method_map_iterator i = method_map.begin (); + i != method_map.end (); + i++) + { + std::string class_name = i->first; - std::list& file_info_list = fcn_map[base]; + fcn_map_type& fm = i->second; + + std::string full_dir_name + = file_ops::concat (dir_name, "@" + class_name); + + for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++) + { + file_info_list_type& file_info_list = q->second; if (file_info_list.size () == 1) continue; else { - for (std::list::iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) + for (file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) { - if (p->dir_name == dir) + if (p->dir_name == full_dir_name) { file_info fi = *p; @@ -340,6 +378,30 @@ } } +void +load_path::move (dir_info_list_iterator i, bool at_end) +{ + if (dir_info_list.size () > 1) + { + dir_info di = *i; + + dir_info_list.erase (i); + + if (at_end) + dir_info_list.push_back (di); + 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); + } +} + static void maybe_add_path_elts (std::string& path, const std::string& dir) { @@ -387,6 +449,8 @@ { dir_info_list.clear (); fcn_map.clear (); + private_fcn_map.clear (); + method_map.clear (); do_append (".", false); } @@ -503,6 +567,10 @@ add_to_fcn_map (di, true); + add_to_private_fcn_map (di); + + add_to_method_map (di, true); + if (add_hook) add_hook (dir); } @@ -527,6 +595,96 @@ panic_impossible (); } +void +load_path::remove_fcn_map (const std::string& dir, + const string_vector& fcn_files) +{ + octave_idx_type len = fcn_files.length (); + + for (octave_idx_type k = 0; k < len; k++) + { + std::string fname = fcn_files[k]; + + std::string ext; + std::string base = fname; + + size_t pos = fname.rfind ('.'); + + if (pos != NPOS) + { + base = fname.substr (0, pos); + ext = fname.substr (pos); + } + + file_info_list_type& file_info_list = fcn_map[base]; + + for (file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + if (p->dir_name == dir) + { + file_info_list.erase (p); + + if (file_info_list.empty ()) + fcn_map.erase (fname); + + break; + } + } + } +} + +void +load_path::remove_private_fcn_map (const std::string& dir) +{ + private_fcn_map_iterator p = private_fcn_map.find (dir); + + if (p != private_fcn_map.end ()) + private_fcn_map.erase (p); +} + +void +load_path::remove_method_map (const std::string& dir) +{ + for (method_map_iterator i = method_map.begin (); + i != method_map.end (); + i++) + { + std::string class_name = i->first; + + fcn_map_type& fm = i->second; + + std::string full_dir_name = file_ops::concat (dir, "@" + class_name); + + for (fcn_map_iterator q = fm.begin (); q != fm.end (); q++) + { + file_info_list_type& file_info_list = q->second; + + if (file_info_list.size () == 1) + continue; + else + { + for (file_info_list_iterator p = file_info_list.begin (); + p != file_info_list.end (); + p++) + { + if (p->dir_name == full_dir_name) + { + file_info_list.erase (p); + + // FIXME -- if there are no other elements, we + // should remove this element of fm but calling + // erase here would invalidate the iterator q. + + break; + } + } + } + } + } +} + bool load_path::do_remove (const std::string& dir_arg) { @@ -558,40 +716,11 @@ dir_info_list.erase (i); - octave_idx_type len = fcn_files.length (); - - for (octave_idx_type k = 0; k < len; k++) - { - std::string fname = fcn_files[k]; - - std::string ext; - std::string base = fname; - - size_t pos = fname.rfind ('.'); - - if (pos != NPOS) - { - base = fname.substr (0, pos); - ext = fname.substr (pos); - } + remove_fcn_map (dir, fcn_files); - std::list& file_info_list = fcn_map[base]; + remove_private_fcn_map (dir); - for (std::list::iterator p = file_info_list.begin (); - p != file_info_list.end (); - p++) - { - if (p->dir_name == dir) - { - file_info_list.erase (p); - - if (file_info_list.empty ()) - fcn_map.erase (fname); - - break; - } - } - } + remove_method_map (dir); } } } @@ -608,6 +737,10 @@ fcn_map.clear (); + private_fcn_map.clear (); + + method_map.clear (); + for (dir_info_list_iterator p = dir_info_list.begin (); p != dir_info_list.end (); p++) @@ -617,21 +750,122 @@ di.update (); add_to_fcn_map (di, true); + + add_to_private_fcn_map (di); + + add_to_method_map (di, true); } } +bool +load_path::check_file_type (std::string& fname, int type, int possible_types, + const std::string& fcn, const char *who) +{ + bool retval = false; + + if (type == load_path::OCT_FILE) + { + if ((type & possible_types) == load_path::OCT_FILE) + { + fname += ".oct"; + retval = true; + } + } + else if (type == load_path::M_FILE) + { + if ((type & possible_types) == load_path::M_FILE) + { + fname += ".m"; + retval = true; + } + } + else if (type == load_path::MEX_FILE) + { + if ((type & possible_types) == load_path::MEX_FILE) + { + fname += ".mex"; + retval = true; + } + } + else if (type == (load_path::M_FILE | load_path::OCT_FILE)) + { + if (possible_types & load_path::OCT_FILE) + { + fname += ".oct"; + retval = true; + } + else if (possible_types & load_path::M_FILE) + { + fname += ".m"; + retval = true; + } + } + else if (type == (load_path::M_FILE | load_path::MEX_FILE)) + { + if (possible_types & load_path::MEX_FILE) + { + fname += ".mex"; + retval = true; + } + else if (possible_types & load_path::M_FILE) + { + fname += ".m"; + retval = true; + } + } + else if (type == (load_path::OCT_FILE | load_path::MEX_FILE)) + { + if (possible_types & load_path::OCT_FILE) + { + fname += ".oct"; + retval = true; + } + else if (possible_types & load_path::MEX_FILE) + { + fname += ".mex"; + retval = true; + } + } + else if (type == (load_path::M_FILE | load_path::OCT_FILE + | load_path::MEX_FILE)) + { + if (possible_types & load_path::OCT_FILE) + { + fname += ".oct"; + retval = true; + } + else if (possible_types & load_path::MEX_FILE) + { + fname += ".mex"; + retval = true; + } + else if (possible_types & load_path::M_FILE) + { + fname += ".m"; + retval = true; + } + } + else + error ("%s: %s: invalid type code = %d", who, fcn.c_str (), type); + + return retval; +} + std::string -load_path::do_find_fcn (const std::string& fcn, int type) const +load_path::do_find_fcn (const std::string& fcn, std::string& dir_name, + int type) const { std::string retval; + + // update (); - update (); + dir_name = std::string (); const_fcn_map_iterator p = fcn_map.find (fcn); if (p != fcn_map.end ()) { - const std::list& file_info_list = p->second; + const file_info_list_type& file_info_list = p->second; for (const_file_info_list_iterator i = file_info_list.begin (); i != file_info_list.end (); @@ -639,104 +873,123 @@ { const file_info& fi = *i; - int t = fi.types; - retval = file_ops::concat (fi.dir_name, fcn); - if (type == load_path::OCT_FILE) + if (check_file_type (retval, type, fi.types, + fcn, "load_path::do_find_fcn")) { - if ((type & t) == load_path::OCT_FILE) - { - retval += ".oct"; - break; - } - } - else if (type == load_path::M_FILE) - { - if ((type & t) == load_path::M_FILE) - { - retval += ".m"; - break; - } + dir_name = fi.dir_name; + break; } - else if (type == load_path::MEX_FILE) + else + retval = std::string (); + } + } + + return retval; +} + +std::string +load_path::do_find_private_fcn (const std::string& dir, + const std::string& fcn, int type) const +{ + std::string retval; + + // update (); + + const_private_fcn_map_iterator q = private_fcn_map.find (dir); + + if (q != private_fcn_map.end ()) + { + const dir_info::fcn_file_map_type& m = q->second; + + dir_info::const_fcn_file_map_iterator p = m.find (fcn); + + if (p != m.end ()) + { + std::string fname + = file_ops::concat (file_ops::concat (dir, "private"), fcn); + + if (check_file_type (fname, type, p->second, fcn, + "load_path::find_private_fcn")) + retval = fname; + } + } + + return retval; +} + +std::string +load_path::do_find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name, int type) const +{ + std::string retval; + + // update (); + + dir_name = std::string (); + + const_method_map_iterator q = method_map.find (class_name); + + if (q != method_map.end ()) + { + const fcn_map_type& m = q->second; + + const_fcn_map_iterator p = m.find (meth); + + if (p != m.end ()) + { + const file_info_list_type& file_info_list = p->second; + + for (const_file_info_list_iterator i = file_info_list.begin (); + i != file_info_list.end (); + i++) { - if ((type & t) == load_path::MEX_FILE) + const file_info& fi = *i; + + retval = file_ops::concat (fi.dir_name, meth); + + bool found = check_file_type (retval, type, fi.types, + meth, "load_path::do_find_method"); + + if (found) { - retval += ".mex"; - break; - } - } - else if (type == (load_path::M_FILE | load_path::OCT_FILE)) - { - if (t & load_path::OCT_FILE) - { - retval += ".oct"; - break; - } - else if (t & load_path::M_FILE) - { - retval += ".m"; + dir_name = fi.dir_name; break; } - } - else if (type == (load_path::M_FILE | load_path::MEX_FILE)) - { - if (t & load_path::MEX_FILE) - { - retval += ".mex"; - break; - } - else if (t & load_path::M_FILE) - { - retval += ".m"; - break; - } + else + retval = std::string (); } - else if (type == (load_path::OCT_FILE | load_path::MEX_FILE)) - { - if (t & load_path::OCT_FILE) - { - retval += ".oct"; - break; - } - else if (t & load_path::MEX_FILE) - { - retval += ".mex"; - break; - } - } - else if (type == (load_path::M_FILE | load_path::OCT_FILE - | load_path::MEX_FILE)) - { - if (t & load_path::OCT_FILE) - { - retval += ".oct"; - break; - } - else if (t & load_path::MEX_FILE) - { - retval += ".mex"; - break; - } - else if (t & load_path::M_FILE) - { - retval += ".m"; - break; - } - } - else - error ("load_path::do_find_fcn: %s: invalid type code = %d", - fcn.c_str (), type); - - // Reset the return string, in case the above tesst fail. - retval = std::string (); } } return retval; } +std::list +load_path::do_methods (const std::string& class_name) const +{ + std::list retval; + + // update (); + + const_method_map_iterator q = method_map.find (class_name); + + if (q != method_map.end ()) + { + const fcn_map_type& m = q->second; + + for (const_fcn_map_iterator p = m.begin (); p != m.end (); p++) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); + + return retval; +} + std::string load_path::do_find_file (const std::string& file) const { @@ -987,6 +1240,80 @@ } void +print_types (std::ostream& os, int types) +{ + bool printed_type = false; + + if (types & load_path::OCT_FILE) + { + os << "oct"; + printed_type = true; + } + + if (types & load_path::MEX_FILE) + { + if (printed_type) + os << "|"; + os << "mex"; + printed_type = true; + } + + if (types & load_path::M_FILE) + { + if (printed_type) + os << "|"; + os << "m"; + printed_type = true; + } +} + +void +print_fcn_list (std::ostream& os, + const load_path::dir_info::fcn_file_map_type& lst) +{ + for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin (); + p != lst.end (); + p++) + { + os << " " << p->first << " ("; + + print_types (os, p->second); + + os << ")\n"; + } +} + +string_vector +get_file_list (const load_path::dir_info::fcn_file_map_type& lst) +{ + octave_idx_type n = lst.size (); + + string_vector retval (n); + + octave_idx_type count = 0; + + for (load_path::dir_info::const_fcn_file_map_iterator p = lst.begin (); + p != lst.end (); + p++) + { + std::string nm = p->first; + + int types = p->second; + + if (types & load_path::OCT_FILE) + nm += ".oct"; + else if (types & load_path::MEX_FILE) + nm += ".mex"; + else + nm += ".m"; + + retval[count++] = nm; + } + + return retval; +} + +void load_path::do_display (std::ostream& os) const { for (const_dir_info_list_iterator i = dir_info_list.begin (); @@ -1002,53 +1329,32 @@ fcn_files.list_in_columns (os); } -#if defined (DEBUG_LOAD_PATH) - - const std::map& private_function_map - = i->private_function_map; + const dir_info::method_file_map_type& method_file_map + = i->method_file_map; - if (private_function_map.size () > 0) + if (! method_file_map.empty ()) { - os << "private:\n"; - - for (std::map::const_iterator p = private_function_map.begin (); - p != private_function_map.end (); + for (dir_info::const_method_file_map_iterator p = method_file_map.begin (); + p != method_file_map.end (); p++) { - os << " " << p->first << " ("; - - bool printed_type = false; - - int types = p->second; + os << "\n*** methods in " << i->dir_name + << "/@" << p->first << ":\n\n"; - if (types & load_path::OCT_FILE) - { - os << "oct"; - printed_type = true; - } + string_vector method_files = get_file_list (p->second); - if (types & load_path::MEX_FILE) - { - if (printed_type) - os << "|"; - os << "mex"; - printed_type = true; - } + method_files.list_in_columns (os); + } + } + } - if (types & load_path::M_FILE) - { - if (printed_type) - os << "|"; - os << "m"; - printed_type = true; - } + 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"; - os << ")\n"; - } - - os << "\n"; - } -#endif + print_fcn_list (os, i->second); } #if defined (DEBUG_LOAD_PATH) @@ -1059,7 +1365,7 @@ { os << i->first << ":\n"; - const std::list& file_info_list = i->second; + 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 (); @@ -1067,34 +1373,41 @@ { os << " " << p->dir_name << " ("; - bool printed_type = false; - - if (p->types & load_path::OCT_FILE) - { - os << "oct"; - printed_type = true; - } - - if (p->types & load_path::MEX_FILE) - { - if (printed_type) - os << "|"; - os << "mex"; - printed_type = true; - } - - if (p->types & load_path::M_FILE) - { - if (printed_type) - os << "|"; - os << "m"; - printed_type = true; - } + 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 @@ -1124,7 +1437,7 @@ ext = fname.substr (pos); } - std::list& file_info_list = fcn_map[base]; + file_info_list_type& file_info_list = fcn_map[base]; file_info_list_iterator p = file_info_list.begin (); @@ -1162,6 +1475,78 @@ } } +void +load_path::add_to_private_fcn_map (const dir_info& di) const +{ + dir_info::fcn_file_map_type private_file_map = di.private_file_map; + + if (! private_file_map.empty ()) + private_fcn_map[di.dir_name] = private_file_map; +} + +void +load_path::add_to_method_map (const dir_info& di, bool at_end) const +{ + std::string dir_name = di.dir_name; + + // > + dir_info::method_file_map_type method_file_map = di.method_file_map; + + for (dir_info::const_method_file_map_iterator q = method_file_map.begin (); + q != method_file_map.end (); + q++) + { + std::string class_name = q->first; + + fcn_map_type& fm = method_map[class_name]; + + std::string full_dir_name + = file_ops::concat (dir_name, "@" + class_name); + + // + const dir_info::fcn_file_map_type& m = q->second; + + for (dir_info::const_fcn_file_map_iterator p = m.begin (); + p != m.end (); + p++) + { + std::string base = p->first; + + int types = p->second; + + file_info_list_type& file_info_list = fm[base]; + + file_info_list_iterator p2 = file_info_list.begin (); + + while (p2 != file_info_list.end ()) + { + if (p2->dir_name == full_dir_name) + break; + + p2++; + } + + if (p2 == file_info_list.end ()) + { + file_info fi (full_dir_name, types); + + if (at_end) + file_info_list.push_back (fi); + else + file_info_list.push_front (fi); + } + else + { + // FIXME -- is this possible? + + file_info& fi = *p2; + + fi.types = types; + } + } + } +} + std::string genpath (const std::string& dirname, const string_vector& skip) { @@ -1182,9 +1567,10 @@ std::string elt = dirlist[i]; // FIXME -- the caller should be able to specify the list of - // directories to skip in addition to "." and "..". + // directories to skip in addition to ".", "..", and + // directories beginning with "@". - bool skip_p = (elt == "." || elt == ".."); + bool skip_p = (elt == "." || elt == ".." || elt[0] == '@'); if (! skip_p) { diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/load-path.h --- a/src/load-path.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/load-path.h Fri Dec 28 20:56:58 2007 +0000 @@ -37,11 +37,11 @@ { protected: - load_path (void) : dir_info_list (), fcn_map () { } + load_path (void) : dir_info_list (), fcn_map (), method_map () { } public: - typedef void (*hook_function_ptr) (const std::string& dir); + typedef void (*hook_fcn_ptr) (const std::string& dir); ~load_path (void) { } @@ -86,28 +86,68 @@ instance->do_update (); } + static std::string find_method (const std::string& class_name, + const std::string& meth, + std::string& dir_name) + { + return instance_ok () + ? instance->do_find_method (class_name, meth, dir_name) : std::string (); + } + + static std::string find_method (const std::string& class_name, + const std::string& meth) + { + std::string dir_name; + return find_method (class_name, meth, dir_name); + } + + static std::list methods (const std::string& class_name) + { + return instance_ok () + ? instance->do_methods (class_name) : std::list (); + } + + static std::string find_fcn (const std::string& fcn, std::string& dir_name) + { + return instance_ok () + ? instance->do_find_fcn (fcn, dir_name) : std::string (); + } + static std::string find_fcn (const std::string& fcn) { + std::string dir_name; + return find_fcn (fcn, dir_name); + } + + static std::string find_private_fcn (const std::string& dir, + const std::string& fcn) + { return instance_ok () - ? instance->do_find_fcn (fcn) : std::string (); + ? instance->do_find_private_fcn (dir, fcn) : std::string (); } static std::string find_fcn_file (const std::string& fcn) { + std::string dir_name; + return instance_ok () ? - instance->do_find_fcn (fcn, M_FILE) : std::string (); + instance->do_find_fcn (fcn, dir_name, M_FILE) : std::string (); } static std::string find_oct_file (const std::string& fcn) { + std::string dir_name; + return instance_ok () ? - instance->do_find_fcn (fcn, OCT_FILE) : std::string (); + instance->do_find_fcn (fcn, dir_name, OCT_FILE) : std::string (); } static std::string find_mex_file (const std::string& fcn) { + std::string dir_name; + return instance_ok () ? - instance->do_find_fcn (fcn, MEX_FILE) : std::string (); + instance->do_find_fcn (fcn, dir_name, MEX_FILE) : std::string (); } static std::string find_file (const std::string& file) @@ -160,9 +200,9 @@ instance->do_display (os); } - static void set_add_hook (hook_function_ptr f) { add_hook = f; } + static void set_add_hook (hook_fcn_ptr f) { add_hook = f; } - static void set_remove_hook (hook_function_ptr f) { remove_hook = f; } + static void set_remove_hook (hook_fcn_ptr f) { remove_hook = f; } static void set_command_line_path (const std::string& p) { @@ -187,13 +227,26 @@ { public: + // + typedef std::map fcn_file_map_type; + + typedef fcn_file_map_type::const_iterator const_fcn_file_map_iterator; + typedef fcn_file_map_type::iterator fcn_file_map_iterator; + + // > + typedef std::map method_file_map_type; + + typedef method_file_map_type::const_iterator const_method_file_map_iterator; + typedef method_file_map_type::iterator method_file_map_iterator; + dir_info (const std::string& d) : dir_name (d) { initialize (); } dir_info (const dir_info& di) : dir_name (di.dir_name), is_relative (di.is_relative), dir_mtime (di.dir_mtime), all_files (di.all_files), fcn_files (di.fcn_files), - private_function_map (di.private_function_map) { } + private_file_map (di.private_file_map), + method_file_map (di.method_file_map) { } ~dir_info (void) { } @@ -206,7 +259,8 @@ dir_mtime = di.dir_mtime; all_files = di.all_files; fcn_files = di.fcn_files; - private_function_map = di.private_function_map; + private_file_map = di.private_file_map; + method_file_map = di.method_file_map; } return *this; @@ -219,15 +273,21 @@ octave_time dir_mtime; string_vector all_files; string_vector fcn_files; - std::map private_function_map; + fcn_file_map_type private_file_map; + method_file_map_type method_file_map; private: void initialize (void); - bool get_file_list (const std::string& d); + void get_file_list (const std::string& d); + + void get_private_file_map (const std::string& d); - void get_private_function_map (const std::string& d); + void get_method_file_map (const std::string& d, + const std::string& class_name); + + friend fcn_file_map_type get_fcn_files (const std::string& d); }; class file_info @@ -263,21 +323,53 @@ // in each directory. // // Second, a map from file names (the union of all "public" files for all - // directories, but without filename exteinsions) to a list of + // directories, but without filename extensions) to a list of // corresponding information (directory name and file types). This // way, we can quickly find shadowed file names and look up all // overloaded functions (in the "@" directories used to implement // classes). - mutable std::list dir_info_list; + typedef std::list dir_info_list_type; + + typedef dir_info_list_type::const_iterator const_dir_info_list_iterator; + typedef dir_info_list_type::iterator dir_info_list_iterator; + + typedef std::list file_info_list_type; + + typedef file_info_list_type::const_iterator const_file_info_list_iterator; + typedef file_info_list_type::iterator file_info_list_iterator; + + // + typedef std::map fcn_map_type; + + typedef fcn_map_type::const_iterator const_fcn_map_iterator; + typedef fcn_map_type::iterator fcn_map_iterator; - mutable std::map > fcn_map; + // > + typedef std::map private_fcn_map_type; + + typedef private_fcn_map_type::const_iterator const_private_fcn_map_iterator; + typedef private_fcn_map_type::iterator private_fcn_map_iterator; + + // > + typedef std::map method_map_type; + + 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; + + mutable fcn_map_type fcn_map; + + mutable private_fcn_map_type private_fcn_map; + + mutable method_map_type method_map; static load_path *instance; - static hook_function_ptr add_hook; + static hook_fcn_ptr add_hook; - static hook_function_ptr remove_hook; + static hook_fcn_ptr remove_hook; static std::string command_line_path; @@ -285,20 +377,16 @@ static bool instance_ok (void); - typedef std::list::const_iterator const_dir_info_list_iterator; - typedef std::list::iterator dir_info_list_iterator; - - typedef std::map >::const_iterator const_fcn_map_iterator; - typedef std::map >::iterator fcn_map_iterator; - - typedef std::list::const_iterator const_file_info_list_iterator; - typedef std::list::iterator file_info_list_iterator; - const_dir_info_list_iterator find_dir_info (const std::string& dir) const; dir_info_list_iterator find_dir_info (const std::string& dir); bool contains (const std::string& dir) const; + 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); + void move (std::list::iterator i, bool at_end); void do_initialize (bool set_initial_path); @@ -313,13 +401,35 @@ 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; + static bool + 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; + std::string do_find_private_fcn (const std::string& dir, + const std::string& fcn, + int type = M_FILE | OCT_FILE | MEX_FILE) const; + + 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; + + std::list do_methods (const std::string& class_name) const; + std::string do_find_file (const std::string& file) const; std::string do_find_first_of (const string_vector& files) const; @@ -336,11 +446,24 @@ std::string do_path (void) const; + friend void print_types (std::ostream& os, int types); + + friend string_vector get_file_list (const dir_info::fcn_file_map_type& lst); + + friend void + print_fcn_list (std::ostream& os, const dir_info::fcn_file_map_type& lst); + void do_display (std::ostream& os) const; std::string do_system_path (void) const { return sys_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; + + friend dir_info::fcn_file_map_type get_fcn_files (const std::string& d); }; extern std::string diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/load-save.cc --- a/src/load-save.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/load-save.cc Fri Dec 28 20:56:58 2007 +0000 @@ -132,149 +132,22 @@ error ("%s: unable to open file `%s'", fcn.c_str (), file.c_str ()); } -// FIXME -- shouldn't this be implemented in terms of other -// functions that are already available? - -// Install a variable with name NAME and the value specified TC in the -// symbol table. If FORCE is TRUE, replace any existing definition -// for NAME. If GLOBAL is TRUE, make the variable global. -// -// Assumes TC is defined. +// Install a variable with name NAME and the value VAL in the +// symbol table. If GLOBAL is TRUE, make the variable global. static void -install_loaded_variable (int force, const std::string& name, +install_loaded_variable (const std::string& name, const octave_value& val, - int global, const std::string& doc) + bool global, const std::string& /*doc*/) { - // Is there already a symbol by this name? If so, what is it? - - symbol_record *lsr = curr_sym_tab->lookup (name); - - bool is_undefined = true; - bool is_variable = false; - bool is_function = false; - bool is_global = false; - - if (lsr) - { - is_undefined = ! lsr->is_defined (); - is_variable = lsr->is_variable (); - is_function = lsr->is_function (); - is_global = lsr->is_linked_to_global (); - } - - symbol_record *sr = 0; - if (global) { - if (is_global || is_undefined) - { - if (force || is_undefined) - { - lsr = curr_sym_tab->lookup (name, true); - link_to_global_variable (lsr); - sr = lsr; - } - else - { - warning ("load: global variable name `%s' exists", - name.c_str ()); - warning ("use `load -force' to overwrite"); - } - } - else if (is_function) - { - if (force) - { - lsr = curr_sym_tab->lookup (name, true); - link_to_global_variable (lsr); - sr = lsr; - } - else - { - warning ("load: `%s' is currently a function in this scope", - name.c_str ()); - warning ("`load -force' will load variable and hide function"); - } - } - else if (is_variable) - { - if (force) - { - lsr = curr_sym_tab->lookup (name, true); - link_to_global_variable (lsr); - sr = lsr; - } - else - { - warning ("load: local variable name `%s' exists", - name.c_str ()); - warning ("use `load -force' to overwrite"); - } - } - else - error ("load: unable to load data for unknown symbol type"); + symbol_table::clear (name); + symbol_table::mark_global (name); + symbol_table::varref (name, symbol_table::global_scope ()) = val; } else - { - if (is_global) - { - if (force || is_undefined) - { - lsr = curr_sym_tab->lookup (name, true); - link_to_global_variable (lsr); - sr = lsr; - } - else - { - warning ("load: global variable name `%s' exists", - name.c_str ()); - warning ("use `load -force' to overwrite"); - } - } - else if (is_function) - { - if (force) - { - lsr = curr_sym_tab->lookup (name, true); - link_to_global_variable (lsr); - sr = lsr; - } - else - { - warning ("load: `%s' is currently a function in this scope", - name.c_str ()); - warning ("`load -force' will load variable and hide function"); - } - } - else if (is_variable || is_undefined) - { - if (force || is_undefined) - { - lsr = curr_sym_tab->lookup (name, true); - sr = lsr; - } - else - { - warning ("load: local variable name `%s' exists", - name.c_str ()); - warning ("use `load -force' to overwrite"); - } - } - else - error ("load: unable to load data for unknown symbol type"); - } - - if (sr) - { - sr->define (val); - sr->document (doc); - return; - } - else - error ("load: unable to load variable `%s'", name.c_str ()); - - return; + symbol_table::varref (name) = val; } // Return TRUE if NAME matches one of the given globbing PATTERNS. @@ -451,7 +324,7 @@ } octave_value -do_load (std::istream& stream, const std::string& orig_fname, bool force, +do_load (std::istream& stream, const std::string& orig_fname, load_save_format format, oct_mach_info::float_format flt_fmt, bool list_only, bool swap, bool verbose, const string_vector& argv, int argv_idx, int argc, int nargout) @@ -552,7 +425,7 @@ retstruct.assign (name, tc); } else - install_loaded_variable (force, name, tc, global, doc); + install_loaded_variable (name, tc, global, doc); } } @@ -766,7 +639,6 @@ load_save_format format = LS_UNKNOWN; - bool force = true; bool list_only = false; bool verbose = false; @@ -857,7 +729,7 @@ // that we can get additional input? I'm afraid that we // can't fix this using std::cin only. - retval = do_load (std::cin, orig_fname, force, format, flt_fmt, + retval = do_load (std::cin, orig_fname, format, flt_fmt, list_only, swap, verbose, argv, i, argc, nargout); } @@ -887,7 +759,7 @@ if (hdf5_file.file_id >= 0) { - retval = do_load (hdf5_file, orig_fname, force, format, + retval = do_load (hdf5_file, orig_fname, format, flt_fmt, list_only, swap, verbose, argv, i, argc, nargout); @@ -940,7 +812,7 @@ } } - retval = do_load (file, orig_fname, force, format, + retval = do_load (file, orig_fname, format, flt_fmt, list_only, swap, verbose, argv, i, argc, nargout); @@ -974,7 +846,7 @@ } } - retval = do_load (file, orig_fname, force, format, + retval = do_load (file, orig_fname, format, flt_fmt, list_only, swap, verbose, argv, i, argc, nargout); @@ -1033,7 +905,7 @@ static void do_save (std::ostream& os, const octave_value& tc, const std::string& name, const std::string& help, - int global, load_save_format fmt, bool save_as_floats) + bool global, load_save_format fmt, bool save_as_floats) { switch (fmt) { @@ -1078,46 +950,42 @@ // Save the info from SR on stream OS in the format specified by FMT. void -do_save (std::ostream& os, symbol_record *sr, load_save_format fmt, - bool save_as_floats) +do_save (std::ostream& os, const symbol_table::symbol_record& sr, + load_save_format fmt, bool save_as_floats) { - if (! sr->is_variable ()) - { - error ("save: can only save variables, not functions"); - return; - } + octave_value val = sr.varval (); - octave_value tc = sr->def (); - - if (tc.is_defined ()) + if (val.is_defined ()) { - std::string name = sr->name (); - std::string help = sr->help (); + std::string name = sr.name (); + std::string help; + bool global = sr.is_global (); - int global = sr->is_linked_to_global (); - - do_save (os, tc, name, help, global, fmt, save_as_floats); + do_save (os, val, name, help, global, fmt, save_as_floats); } } // Save variables with names matching PATTERN on stream OS in the // format specified by FMT. -static int +static size_t save_vars (std::ostream& os, const std::string& pattern, load_save_format fmt, bool save_as_floats) { - Array vars = curr_sym_tab->glob - (pattern, symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES); + std::list vars = symbol_table::glob (pattern); + + size_t saved = 0; - int saved = vars.length (); + typedef std::list::const_iterator const_vars_iterator; - for (int i = 0; i < saved; i++) + for (const_vars_iterator p = vars.begin (); p != vars.end (); p++) { - do_save (os, vars(i), fmt, save_as_floats); + do_save (os, *p, fmt, save_as_floats); if (error_state) break; + + saved++; } return saved; @@ -1333,43 +1201,35 @@ { write_header (os, fmt); - Array vars = curr_sym_tab->glob - ("*", symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES); - - int num_to_save = vars.length (); + std::list vars = symbol_table::all_variables (); double save_mem_size = 0; - for (int i = 0; i < num_to_save; i++) + typedef std::list::const_iterator const_vars_iterator; + + for (const_vars_iterator p = vars.begin (); p != vars.end (); p++) { - symbol_record *sr = vars(i); + octave_value val = p->varval (); - if (sr->is_variable ()) + if (val.is_defined ()) { - octave_value tc = sr->def (); - - if (tc.is_defined ()) - { - double tc_size = tc.byte_size () / 1024; - - // FIXME -- maybe we should try to throw out the - // largest first... + std::string name = p->name (); + std::string help; + bool global = p->is_global (); - if (Voctave_core_file_limit < 0 - || save_mem_size + tc_size < Voctave_core_file_limit) - { - save_mem_size += tc_size; + double val_size = val.byte_size () / 1024; - std::string name = sr->name (); - std::string help = sr->help (); + // FIXME -- maybe we should try to throw out the largest first... - int global = sr->is_linked_to_global (); - - do_save (os, tc, name, help, global, fmt, save_as_floats); + if (Voctave_core_file_limit < 0 + || save_mem_size + val_size < Voctave_core_file_limit) + { + save_mem_size += val_size; - if (error_state) - break; - } + do_save (os, val, name, help, global, fmt, save_as_floats); + + if (error_state) + break; } } } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/load-save.h --- a/src/load-save.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/load-save.h Fri Dec 28 20:56:58 2007 +0000 @@ -59,8 +59,8 @@ const string_vector& argv, int argv_idx, int argc, int nargout); extern void -do_save (std::ostream& os, symbol_record *sr, load_save_format fmt, - bool save_as_floats); +do_save (std::ostream& os, const symbol_table::symbol_record& sr, + load_save_format fmt, bool save_as_floats); extern void write_header (std::ostream& os, load_save_format format); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-hdf5.cc --- a/src/ls-hdf5.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-hdf5.cc Fri Dec 28 20:56:58 2007 +0000 @@ -61,7 +61,6 @@ #include "ov-cell.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-mat-ascii.cc --- a/src/ls-mat-ascii.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-mat-ascii.cc Fri Dec 28 20:56:58 2007 +0000 @@ -56,7 +56,6 @@ #include "ov-cell.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-mat4.cc --- a/src/ls-mat4.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-mat4.cc Fri Dec 28 20:56:58 2007 +0000 @@ -55,7 +55,6 @@ #include "ov-cell.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-mat5.cc --- a/src/ls-mat5.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-mat5.cc Fri Dec 28 20:56:58 2007 +0000 @@ -61,7 +61,6 @@ #include "ov-fcn-inline.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" @@ -775,21 +774,18 @@ if (fs.exists ()) { - symbol_record *sr = fbi_sym_tab->lookup (str, true); - - if (sr) - { - load_fcn_from_file (sr, false); + size_t xpos = str.find_last_of (file_ops::dir_sep_chars); + + std::string dir_name = str.substr (0, xpos); - tc = octave_value (new octave_fcn_handle - (sr->def (), fname)); + octave_function *fcn + = load_fcn_from_file (str, dir_name, "", fname); + + if (fcn) + { + octave_value tmp (fcn); - // The next two lines are needed to force the - // definition of the function back to the one - // that is on the user path. - sr = fbi_sym_tab->lookup (fname, true); - - load_fcn_from_file (sr, false); + tc = octave_value (new octave_fcn_handle (tmp, fname)); } } else @@ -806,21 +802,18 @@ str = octave_env::make_absolute (p.find_first_of (names), octave_env::getcwd ()); - symbol_record *sr = fbi_sym_tab->lookup (str, true); + size_t xpos = str.find_last_of (file_ops::dir_sep_chars); - if (sr) - { - load_fcn_from_file (sr, false); + std::string dir_name = str.substr (0, xpos); - tc = octave_value (new octave_fcn_handle - (sr->def (), fname)); + octave_function *fcn + = load_fcn_from_file (str, dir_name, "", fname); - // The next two lines are needed to force the - // definition of the function back to the one - // that is on the user path. - sr = fbi_sym_tab->lookup (fname, true); + if (fcn) + { + octave_value tmp (fcn); - load_fcn_from_file (sr, false); + tc = octave_value (new octave_fcn_handle (tmp, fname)); } else { @@ -832,18 +825,18 @@ } else { - symbol_record *sr = fbi_sym_tab->lookup (fpath, true); + size_t xpos = fpath.find_last_of (file_ops::dir_sep_chars); - if (sr) - { - load_fcn_from_file (sr, false); + std::string dir_name = fpath.substr (0, xpos); - tc = octave_value (new octave_fcn_handle (sr->def (), - fname)); + octave_function *fcn + = load_fcn_from_file (fpath, dir_name, "", fname); - sr = fbi_sym_tab->lookup (fname, true); + if (fcn) + { + octave_value tmp (fcn); - load_fcn_from_file (sr, false); + tc = octave_value (new octave_fcn_handle (tmp, fname)); } else { @@ -868,37 +861,28 @@ m2 = m2.contents("MCOS")(0).map_value(); tc2 = m2.contents("MCOS")(0).cell_value()(1 + off).cell_value()(1); m2 = tc2.map_value(); - symbol_table *local_sym_tab = 0; + + symbol_table::scope_id local_scope = symbol_table::alloc_scope (); + if (m2.nfields() > 0) { octave_value tmp; - - local_sym_tab = new symbol_table (((m2.nfields() + 1) & ~1), - "LOCAL"); - + for (Octave_map::iterator p0 = m2.begin() ; p0 != m2.end(); p0++) { std::string key = m2.key(p0); octave_value val = m2.contents(p0)(0); - symbol_record *sr = local_sym_tab->lookup (key, true); - - if (sr) - sr->define (val); - else - { - error ("load: failed to load anonymous function handle"); - goto skip_ahead; - } + symbol_table::varref (key, local_scope) = val; } } unwind_protect::begin_frame ("anon_mat5_load"); - unwind_protect_ptr (curr_sym_tab); + + symbol_table::push_scope (local_scope); - if (local_sym_tab) - curr_sym_tab = local_sym_tab; + unwind_protect::add (symbol_table::pop_scope); int parse_status; octave_value anon_fcn_handle = @@ -924,8 +908,7 @@ unwind_protect::run_frame ("anon_mat5_load"); - if (local_sym_tab) - delete local_sym_tab; + symbol_table::erase_scope (local_scope); } else { diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-oct-ascii.cc --- a/src/ls-oct-ascii.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-oct-ascii.cc Fri Dec 28 20:56:58 2007 +0000 @@ -56,8 +56,6 @@ #include "ov-cell.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" -#include "sysdep.h" #include "unwind-prot.h" #include "utils.h" #include "variables.h" diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ls-oct-binary.cc --- a/src/ls-oct-binary.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ls-oct-binary.cc Fri Dec 28 20:56:58 2007 +0000 @@ -55,7 +55,6 @@ #include "ov-cell.h" #include "pager.h" #include "pt-exp.h" -#include "symtab.h" #include "sysdep.h" #include "unwind-prot.h" #include "utils.h" diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/mex.cc --- a/src/mex.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/mex.cc Fri Dec 28 20:56:58 2007 +0000 @@ -3242,31 +3242,26 @@ { mxArray *retval = 0; - // FIXME -- this should be in variable.cc, but the correct - // functionality is not exported. Particularly, get_global_value() - // generates an error if the symbol is undefined. - - symbol_record *sr = 0; + // FIXME -- should this be in variables.cc? + + symbol_table::scope_id scope = -1; if (! strcmp (space, "global")) - sr = global_sym_tab->lookup (name); + scope = symbol_table::global_scope (); else if (! strcmp (space, "caller")) - sr = curr_sym_tab->lookup (name); + scope = symbol_table::current_caller_scope (); else if (! strcmp (space, "base")) - sr = top_level_sym_tab->lookup (name); + scope = symbol_table::top_scope (); else mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); - if (sr) + octave_value val = symbol_table::varval (name, scope); + + if (val.is_defined ()) { - octave_value sr_def = sr->def (); - - if (sr_def.is_defined ()) - { - retval = mex_context->make_value (sr_def); - - retval->set_name (name); - } + retval = mex_context->make_value (val); + + retval->set_name (name); } return retval; @@ -3297,21 +3292,20 @@ set_global_value (name, mxArray::as_octave_value (ptr)); else { - // FIXME -- this belongs in variables.cc. - - symbol_record *sr = 0; - - if (! strcmp (space, "caller")) - sr = curr_sym_tab->lookup (name, true); + // FIXME -- should this be in variables.cc? + + symbol_table::scope_id scope = -1; + + if (! strcmp (space, "global")) + scope = symbol_table::global_scope (); + else if (! strcmp (space, "caller")) + scope = symbol_table::current_caller_scope (); else if (! strcmp (space, "base")) - sr = top_level_sym_tab->lookup (name, true); + scope = symbol_table::top_scope (); else mexErrMsgTxt ("mexPutVariable: symbol table does not exist"); - if (sr) - sr->define (mxArray::as_octave_value (ptr)); - else - panic_impossible (); + symbol_table::varref (name, scope) = mxArray::as_octave_value (ptr); } return 0; @@ -3390,7 +3384,7 @@ else mex_lock_count[fname]++; - mlock (fname); + mlock (); } } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/oct-lvalue.cc --- a/src/oct-lvalue.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/oct-lvalue.cc Fri Dec 28 20:56:58 2007 +0000 @@ -37,7 +37,7 @@ ? val->assign (op, rhs) : val->assign (op, type, idx, rhs)); - if (! (error_state || (chg_fcn && chg_fcn () < 0))) + if (! error_state) *val = tmp; } @@ -62,7 +62,7 @@ ? val->do_non_const_unary_op (op) : val->do_non_const_unary_op (op, type, idx)); - if (! (error_state || (chg_fcn && chg_fcn () < 0))) + if (! error_state) *val = tmp; } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/oct-lvalue.h --- a/src/oct-lvalue.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/oct-lvalue.h Fri Dec 28 20:56:58 2007 +0000 @@ -31,7 +31,6 @@ #include "oct-obj.h" #include "pt-idx.h" -#include "symtab.h" // FIXME -- eliminate the following kluge? @@ -43,13 +42,12 @@ { public: - octave_lvalue (octave_value *v = &dummy_val, - symbol_record::change_function f = 0) - : val (v), type (), idx (), chg_fcn (f), nel (1), index_set (false) { } + octave_lvalue (octave_value *v = &dummy_val) + : val (v), type (), idx (), nel (1), index_set (false) { } octave_lvalue (const octave_lvalue& vr) - : val (vr.val), type (vr.type), idx (vr.idx), chg_fcn (vr.chg_fcn), - nel (vr.nel), index_set (vr.index_set) { } + : val (vr.val), type (vr.type), idx (vr.idx), nel (vr.nel), + index_set (vr.index_set) { } octave_lvalue& operator = (const octave_lvalue& vr) { @@ -58,7 +56,6 @@ val = vr.val; type = vr.type; idx = vr.idx; - chg_fcn = vr.chg_fcn; nel = vr.nel; index_set = vr.index_set; } @@ -100,8 +97,6 @@ std::list idx; - symbol_record::change_function chg_fcn; - octave_idx_type nel; bool index_set; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/octave.cc --- a/src/octave.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/octave.cc Fri Dec 28 20:56:58 2007 +0000 @@ -189,15 +189,13 @@ static void intern_argv (int argc, char **argv) { - symbol_record *nargin_sr = top_level_sym_tab->lookup ("__nargin__", true); + symbol_table::varref (".nargin.", symbol_table::top_scope ()) = argc - 1; - nargin_sr->mark_as_static (); - - nargin_sr->define (argc-1); + symbol_table::mark_hidden (".nargin.", symbol_table::top_scope ()); if (argc > 1) { - octave_argv.resize (argc-1); + octave_argv.resize (argc - 1); // Skip program name in argv. int i = argc; @@ -599,8 +597,6 @@ initialize_file_io (); - initialize_symbol_tables (); - install_types (); install_ops (); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-base.cc --- a/src/ov-base.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-base.cc Fri Dec 28 20:56:58 2007 +0000 @@ -58,12 +58,9 @@ DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_base_value, "", "unknown"); -// If TRUE, print the name along with the value. -static bool Vprint_answer_id_name = true; - // If TRUE, turn off printing of results in functions (as if a // semicolon has been appended to each statement). -static bool Vsilent_functions = false; +bool Vsilent_functions = false; // TRUE means to perform automatic sparse to real mutation if there // is memory to be saved @@ -347,10 +344,7 @@ { if (! (evaluating_function_body && Vsilent_functions)) { - bool pad_after = false; - - if (Vprint_answer_id_name) - pad_after = print_name_tag (output_buf, name); + bool pad_after = print_name_tag (output_buf, name); print (output_buf); @@ -1111,17 +1105,6 @@ INSTALL_WIDENOP (octave_base_value, octave_cell, cell_conv); } -DEFUN (print_answer_id_name, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{val} =} print_answer_id_name ()\n\ -@deftypefnx {Built-in Function} {@var{old_val} =} print_answer_id_name (@var{new_val})\n\ -Query or set the internal variable that controls whether variable\n\ -names are printed along with results produced by evaluating an expression.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (print_answer_id_name); -} - DEFUN (silent_functions, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} silent_functions ()\n\ diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-base.h --- a/src/ov-base.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-base.h Fri Dec 28 20:56:58 2007 +0000 @@ -222,6 +222,8 @@ virtual bool is_map (void) const { return false; } + virtual bool is_object (void) const { return false; } + virtual bool is_streamoff (void) const { return false; } virtual bool is_cs_list (void) const { return false; } @@ -288,6 +290,10 @@ virtual bool is_function (void) const { return false; } + virtual bool is_user_script (void) const { return false; } + + virtual bool is_user_function (void) const { return false; } + virtual bool is_builtin_function (void) const { return false; } virtual bool is_dld_function (void) const { return false; } @@ -487,6 +493,10 @@ DECLARE_OV_BASE_TYPEID_FUNCTIONS_AND_DATA }; +// If TRUE, turn off printing of results in functions (as if a +// semicolon has been appended to each statement). +extern bool Vsilent_functions; + // TRUE means to perform automatic sparse to real mutation if there // is memory to be saved extern bool Vsparse_auto_mutate; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-fcn-handle.cc --- a/src/ov-fcn-handle.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-fcn-handle.cc Fri Dec 28 20:56:58 2007 +0000 @@ -28,6 +28,8 @@ #include #include +#include "file-ops.h" + #include "defun.h" #include "error.h" #include "gripes.h" @@ -63,18 +65,6 @@ "function handle", "function_handle"); -void -octave_fcn_handle::reload_warning (const std::string& fcn_type) const -{ - if (warn_reload) - { - warn_reload = false; - - warning ("reloading %s functions referenced by function handles is not implemented", - fcn_type.c_str ()); - } -} - octave_value_list octave_fcn_handle::subsref (const std::string& type, const std::list& idx, @@ -86,47 +76,22 @@ { case '(': { - octave_function *f = function_value (); - - if (f && f->time_checked () < Vlast_prompt_time) - { - std::string ff_nm = f->fcn_file_name (); + out_of_date_check (fcn); - octave_time ottp = f->time_parsed (); - time_t tp = ottp.unix_time (); + if (fcn.is_defined ()) + { + octave_function *f = function_value (); - if (ff_nm.empty ()) - { - // FIXME -- need to handle inline and - // command-line functions here. - } + if (f) + retval = f->subsref (type, idx, nargout); else - { - if (fcn_out_of_date (f, ff_nm, tp)) - { - // FIXME -- there is currently no way to - // parse a .m file or reload a .oct file that - // leaves the fbi symbol table untouched. We need - // a function that will parse the file and return - // a pointer to the new function definition - // without altering the symbol table. - - if (f->is_nested_function ()) - reload_warning ("nested"); - else - reload_warning ("functions"); - } - } + error ("invalid function handle"); } - - if (f) - retval = f->subsref (type, idx, nargout); else error ("invalid function handle"); } break; - case '{': case '.': { @@ -167,21 +132,18 @@ if (fs.exists ()) { - symbol_record *sr = fbi_sym_tab->lookup (str, true); - - if (sr) - { - load_fcn_from_file (sr, false); + size_t xpos = str.find_last_of (file_ops::dir_sep_chars); - fcn = octave_value (new octave_fcn_handle (sr->def (), nm)); + std::string dir_name = str.substr (0, xpos); - // The next two lines are needed to force the - // definition of the function back to the one - // that is on the user path. - sr = fbi_sym_tab->lookup (nm, true); + octave_function *xfcn + = load_fcn_from_file (str, dir_name, "", nm); - load_fcn_from_file (sr, false); + if (xfcn) + { + octave_value tmp (xfcn); + fcn = octave_value (new octave_fcn_handle (tmp, nm)); } else { @@ -202,20 +164,17 @@ str = octave_env::make_absolute (p.find_first_of (names), octave_env::getcwd ()); - symbol_record *sr = fbi_sym_tab->lookup (str, true); + size_t xpos = str.find_last_of (file_ops::dir_sep_chars); - if (sr) - { - load_fcn_from_file (sr, false); + std::string dir_name = str.substr (0, xpos); + + octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm); - fcn = octave_value (new octave_fcn_handle (sr->def (), nm)); + if (xfcn) + { + octave_value tmp (xfcn); - // The next two lines are needed to force the - // definition of the function back to the one - // that is on the user path. - sr = fbi_sym_tab->lookup (nm, true); - - load_fcn_from_file (sr, false); + fcn = octave_value (new octave_fcn_handle (tmp, nm)); } else { @@ -228,17 +187,17 @@ { if (fpath.length () > 0) { - symbol_record *sr = fbi_sym_tab->lookup (fpath, true); + size_t xpos = fpath.find_last_of (file_ops::dir_sep_chars); - if (sr) - { - load_fcn_from_file (sr, false); + std::string dir_name = fpath.substr (0, xpos); + + octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm); - fcn = octave_value (new octave_fcn_handle (sr->def (), nm)); + if (xfcn) + { + octave_value tmp (xfcn); - sr = fbi_sym_tab->lookup (nm, true); - - load_fcn_from_file (sr, false); + fcn = octave_value (new octave_fcn_handle (tmp, nm)); } else { @@ -248,7 +207,8 @@ } else { - fcn = lookup_function (nm); + fcn = symbol_table::find_function (nm); + if (! fcn.is_function ()) { error ("function handle points to non-existent function"); @@ -270,30 +230,24 @@ print_raw (os, true); os << "\n"; - if (fcn.is_undefined()) + if (fcn.is_undefined ()) return false; octave_user_function *f = fcn.user_function_value (); - Array vars = f->sym_tab()->symbol_list(); - octave_idx_type varlen = vars.length(); + std::list vars + = symbol_table::all_variables (f->scope ()); - // Exclude undefined values like __retval__ - for (octave_idx_type i = 0; i < vars.length(); i++) - { - if (! vars(i)->is_defined ()) - varlen--; - } + size_t varlen = vars.size (); if (varlen > 0) { os << "# length: " << varlen << "\n"; - for (octave_idx_type i = 0; i < vars.length(); i++) + for (std::list::const_iterator p = vars.begin (); + p != vars.end (); p++) { - if (vars(i)->is_defined () && - ! save_ascii_data (os, vars(i)->def(), vars(i)->name(), - false, 0)) + if (! save_ascii_data (os, p->varval (), p->name (), false, 0)) return os; } } @@ -357,18 +311,13 @@ } pos = is.tellg (); - symbol_table *local_sym_tab = 0; + + symbol_table::scope_id local_scope = symbol_table::alloc_scope (); if (extract_keyword (is, "length", len, true) && len >= 0) { if (len > 0) { - octave_idx_type nlen = len; - if (nlen % 2) - nlen++; - - local_sym_tab = new symbol_table (((nlen + 1) & ~1) , "LOCAL"); - for (octave_idx_type i = 0; i < len; i++) { octave_value t2; @@ -383,16 +332,7 @@ break; } - symbol_record *sr = local_sym_tab->lookup (name, true); - - if (sr) - sr->define (t2); - else - { - error ("load: failed to load anonymous function handle"); - success = false; - break; - } + symbol_table::varref (name, local_scope) = t2; } } } @@ -405,10 +345,10 @@ if (is && success) { unwind_protect::begin_frame ("anon_ascii_load"); - unwind_protect_ptr (curr_sym_tab); - if (local_sym_tab) - curr_sym_tab = local_sym_tab; + symbol_table::push_scope (local_scope); + + unwind_protect::add (symbol_table::pop_scope); int parse_status; octave_value anon_fcn_handle = @@ -431,8 +371,7 @@ else success = false; - if (local_sym_tab) - delete local_sym_tab; + symbol_table::erase_scope (local_scope); } else success = set_fcn (octaveroot, fpath); @@ -473,20 +412,15 @@ { std::ostringstream nmbuf; - if (fcn.is_undefined()) + if (fcn.is_undefined ()) return false; octave_user_function *f = fcn.user_function_value (); - Array vars = f->sym_tab()->symbol_list(); - octave_idx_type varlen = vars.length(); + std::list vars + = symbol_table::all_variables (f->scope ()); - // Exclude undefined values like __retval__ - for (octave_idx_type i = 0; i < vars.length(); i++) - { - if (! vars(i)->is_defined ()) - varlen--; - } + size_t varlen = vars.size (); if (varlen > 0) nmbuf << nm << " " << varlen; @@ -507,10 +441,10 @@ if (varlen > 0) { - for (octave_idx_type i = 0; i < vars.length(); i++) + for (std::list::const_iterator p = vars.begin (); + p != vars.end (); p++) { - if (vars(i)->is_defined () && - ! save_binary_data (os, vars(i)->def(), vars(i)->name(), + if (! save_binary_data (os, p->varval (), p->name (), "", 0, save_as_floats)) return os; } @@ -528,6 +462,7 @@ os.write (reinterpret_cast (&tmp), 4); os.write (buf_str.c_str (), buf_str.length ()); } + return true; } @@ -536,6 +471,7 @@ oct_mach_info::float_format fmt) { bool success = true; + int32_t tmp; if (! is.read (reinterpret_cast (&tmp), 4)) return false; @@ -568,15 +504,10 @@ OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1); is.read (ctmp2, tmp); - symbol_table *local_sym_tab = 0; + symbol_table::scope_id local_scope = symbol_table::alloc_scope (); + if (len > 0) { - octave_idx_type nlen = len; - if (nlen % 2) - nlen++; - - local_sym_tab = new symbol_table (nlen, "LOCAL"); - for (octave_idx_type i = 0; i < len; i++) { octave_value t2; @@ -593,29 +524,17 @@ break; } - symbol_record *sr = local_sym_tab->lookup (name, true); - - if (sr) - { - sr->define (t2); - sr->document (doc); - } - else - { - error ("load: failed to load anonymous function handle"); - success = false; - break; - } + symbol_table::varref (name, local_scope) = t2; } } if (is && success) { unwind_protect::begin_frame ("anon_binary_load"); - unwind_protect_ptr (curr_sym_tab); - if (local_sym_tab) - curr_sym_tab = local_sym_tab; + symbol_table::push_scope (local_scope); + + unwind_protect::add (symbol_table::pop_scope); int parse_status; octave_value anon_fcn_handle = @@ -635,8 +554,7 @@ unwind_protect::run_frame ("anon_binary_load"); } - if (local_sym_tab) - delete local_sym_tab; + symbol_table::erase_scope (local_scope); } else { @@ -689,12 +607,14 @@ octave_fcn_handle::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) { + bool retval = true; + hid_t group_hid = -1; group_hid = H5Gcreate (loc_id, name, 0); - if (group_hid < 0 ) return false; + if (group_hid < 0) + return false; hid_t space_hid = -1, data_hid = -1, type_hid = -1;; - bool retval = true; // attach the type of the variable type_hid = H5Tcopy (H5T_C_S1); @@ -756,15 +676,11 @@ H5Dclose (data_hid); octave_user_function *f = fcn.user_function_value (); - Array vars = f->sym_tab()->symbol_list(); - octave_idx_type varlen = vars.length(); - // Exclude undefined values like __retval__ - for (octave_idx_type i = 0; i < vars.length(); i++) - { - if (! vars(i)->is_defined ()) - varlen--; - } + std::list vars + = symbol_table::all_variables (f->scope ()); + + size_t varlen = vars.size (); if (varlen > 0) { @@ -798,10 +714,10 @@ return false; } - for (octave_idx_type i = 0; i < vars.length(); i++) + for (std::list::const_iterator p = vars.begin (); + p != vars.end (); p++) { - if (vars(i)->is_defined () && - ! add_hdf5_data (data_hid, vars(i)->def(), vars(i)->name(), + if (! add_hdf5_data (data_hid, p->varval (), p->name (), "", false, save_as_floats)) break; } @@ -883,13 +799,15 @@ octave_fcn_handle::load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug) { + bool success = true; + hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id; hsize_t rank; int slen; - bool success = true; group_hid = H5Gopen (loc_id, name); - if (group_hid < 0 ) return false; + if (group_hid < 0) + return false; data_hid = H5Dopen (group_hid, "nm"); @@ -1017,7 +935,6 @@ H5Tclose (st_id); H5Dclose (data_hid); - symbol_table *local_sym_tab = 0; octave_idx_type len = 0; // we have to pull some shenanigans here to make sure @@ -1045,14 +962,10 @@ // restore error reporting: H5Eset_auto (err_func, err_func_data); + symbol_table::scope_id local_scope = symbol_table::alloc_scope (); + if (len > 0 && success) { - octave_idx_type nlen = len; - if (nlen % 2) - nlen++; - - local_sym_tab = new symbol_table (nlen, "LOCAL"); - #ifdef HAVE_H5GGET_NUM_OBJS hsize_t num_obj = 0; data_hid = H5Gopen (group_hid, "symbol table"); @@ -1083,16 +996,7 @@ if (have_h5giterate_bug) current_item++; // H5Giterate returns last index processed - symbol_record *sr = local_sym_tab->lookup (dsub.name, true); - - if (sr) - sr->define (dsub.tc); - else - { - error ("load: failed to load anonymous function handle"); - success = false; - break; - } + symbol_table::varref (dsub.name, local_scope) = dsub.tc; } } } @@ -1100,10 +1004,10 @@ if (success) { unwind_protect::begin_frame ("anon_hdf5_load"); - unwind_protect_ptr (curr_sym_tab); - if (local_sym_tab) - curr_sym_tab = local_sym_tab; + symbol_table::push_scope (local_scope); + + unwind_protect::add (symbol_table::pop_scope); int parse_status; octave_value anon_fcn_handle = @@ -1123,8 +1027,7 @@ unwind_protect::run_frame ("anon_hdf5_load"); } - if (local_sym_tab) - delete local_sym_tab; + symbol_table::erase_scope (local_scope); } else { @@ -1318,21 +1221,9 @@ { octave_value retval; - octave_function *fcn = octave_call_stack::current (); - - std::string parent_name = fcn ? fcn->name () : std::string (); - - if (! parent_name.empty ()) - { - size_t pos = parent_name.find (':'); + octave_value f = symbol_table::find_function (nm); - if (pos != NPOS) - parent_name = parent_name.substr (0, pos); - } - - octave_value f = lookup_function (nm, parent_name); - - if (f.is_function ()) + if (f.is_defined ()) retval = octave_value (new octave_fcn_handle (f, nm)); else error ("error creating function handle \"@%s\"", nm.c_str ()); @@ -1396,25 +1287,19 @@ m.assign ("file", ""); octave_user_function *fu = fh->user_function_value (); - Array vars = - fu->sym_tab ()->symbol_list (); - octave_idx_type varlen = vars.length (); - // Exclude undefined values like __retval__ - for (int i = 0; i < vars.length (); i++) - { - if (! vars (i)->is_defined ()) - varlen--; - } + std::list vars + = symbol_table::all_variables (fu->scope ()); + + size_t varlen = vars.size (); if (varlen > 0) { Octave_map ws; - for (octave_idx_type i = 0; i < vars.length (); i++) + for (std::list::const_iterator p = vars.begin (); + p != vars.end (); p++) { - if (vars (i)->is_defined ()) - ws.assign (vars (i)->name (), - vars (i)->def ()); + ws.assign (p->name (), p->varval ()); } m.assign ("workspace", ws); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-fcn-handle.h --- a/src/ov-fcn-handle.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-fcn-handle.h Fri Dec 28 20:56:58 2007 +0000 @@ -118,8 +118,6 @@ // implemented. mutable bool warn_reload; - void reload_warning (const std::string& fcn_type) const; - protected: // The function we are handling. diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-fcn.h --- a/src/ov-fcn.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-fcn.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ #include "oct-obj.h" #include "ov-base.h" #include "ov-typeinfo.h" +#include "symtab.h" class tree_walker; @@ -65,6 +66,8 @@ virtual void mark_fcn_file_up_to_date (const octave_time&) { } + virtual symbol_table::scope_id scope (void) { return -1; } + virtual octave_time time_parsed (void) const { return octave_time (static_cast (0)); } @@ -73,14 +76,26 @@ virtual bool is_nested_function (void) const { return false; } - virtual bool is_user_script (void) const { return false; } + virtual bool is_class_constructor (void) const { return false; } - virtual bool is_user_function (void) const { return false; } + virtual bool is_class_method (void) const { return false; } + + virtual std::string dispatch_class (void) const { return std::string (); } virtual bool takes_varargs (void) const { return false; } virtual bool takes_var_return (void) const { return false; } + std::string dir_name (void) const { return my_dir_name; } + + void stash_dir_name (const std::string& dir) { my_dir_name = dir; } + + void lock (void) { locked = true; } + + void unlock (void) { locked = false; } + + bool islocked (void) { return locked; } + void mark_relative (void) { relative = true; } bool is_relative (void) const { return relative; } @@ -104,9 +119,16 @@ // TRUE if this function was found from a relative path element. bool relative; + // TRUE if this function is tagged so that it can't be cleared. + bool locked; + // The name of this function. std::string my_name; + // The name of the directory in the path where we found this + // function. May be relative. + std::string my_dir_name; + // The help text for this function. std::string doc; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-struct.cc --- a/src/ov-struct.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-struct.cc Fri Dec 28 20:56:58 2007 +0000 @@ -772,10 +772,14 @@ if (nargin == 1) { - if (args(0).is_map ()) + octave_value arg = args(0); + + if (arg.is_map () || arg.is_object ()) { - Octave_map m = args(0).map_value (); + Octave_map m = arg.map_value (); + string_vector keys = m.keys (); + if (keys.length () == 0) retval = Cell (0, 1); else diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-struct.h --- a/src/ov-struct.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-struct.h Fri Dec 28 20:56:58 2007 +0000 @@ -142,11 +142,13 @@ mxArray *as_mxArray (void) const; -private: +protected: // The associative array used to manage the structure data. Octave_map map; +private: + DECLARE_OCTAVE_ALLOCATOR DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-typeinfo.cc --- a/src/ov-typeinfo.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-typeinfo.cc Fri Dec 28 20:56:58 2007 +0000 @@ -93,6 +93,14 @@ } bool +octave_value_typeinfo::register_unary_class_op (octave_value::unary_op op, + octave_value_typeinfo::unary_class_op_fcn f) +{ + return (instance_ok ()) + ? instance->do_register_unary_class_op (op, f) : false; +} + +bool octave_value_typeinfo::register_unary_op (octave_value::unary_op op, int t, octave_value_typeinfo::unary_op_fcn f) { @@ -110,6 +118,14 @@ } bool +octave_value_typeinfo::register_binary_class_op (octave_value::binary_op op, + octave_value_typeinfo::binary_class_op_fcn f) +{ + return (instance_ok ()) + ? instance->do_register_binary_class_op (op, f) : false; +} + +bool octave_value_typeinfo::register_binary_op (octave_value::binary_op op, int t1, int t2, octave_value_typeinfo::binary_op_fcn f) @@ -225,6 +241,23 @@ } bool +octave_value_typeinfo::do_register_unary_class_op (octave_value::unary_op op, + octave_value_typeinfo::unary_class_op_fcn f) +{ + if (lookup_unary_class_op (op)) + { + std::string op_name = octave_value::unary_op_as_string (op); + + warning ("duplicate unary operator `%s' for class dispatch", + op_name.c_str ()); + } + + unary_class_ops.checkelem (static_cast (op)) = f; + + return false; +} + +bool octave_value_typeinfo::do_register_unary_op (octave_value::unary_op op, int t, octave_value_typeinfo::unary_op_fcn f) { @@ -261,6 +294,23 @@ } bool +octave_value_typeinfo::do_register_binary_class_op (octave_value::binary_op op, + octave_value_typeinfo::binary_class_op_fcn f) +{ + if (lookup_binary_class_op (op)) + { + std::string op_name = octave_value::binary_op_as_string (op); + + warning ("duplicate binary operator `%s' for class dispatch", + op_name.c_str ()); + } + + binary_class_ops.checkelem (static_cast (op)) = f; + + return false; +} + +bool octave_value_typeinfo::do_register_binary_op (octave_value::binary_op op, int t1, int t2, octave_value_typeinfo::binary_op_fcn f) @@ -407,6 +457,12 @@ return retval; } +octave_value_typeinfo::unary_class_op_fcn +octave_value_typeinfo::do_lookup_unary_class_op (octave_value::unary_op op) +{ + return unary_class_ops.checkelem (static_cast (op)); +} + octave_value_typeinfo::unary_op_fcn octave_value_typeinfo::do_lookup_unary_op (octave_value::unary_op op, int t) { @@ -420,6 +476,12 @@ return non_const_unary_ops.checkelem (static_cast (op), t); } +octave_value_typeinfo::binary_class_op_fcn +octave_value_typeinfo::do_lookup_binary_class_op (octave_value::binary_op op) +{ + return binary_class_ops.checkelem (static_cast (op)); +} + octave_value_typeinfo::binary_op_fcn octave_value_typeinfo::do_lookup_binary_op (octave_value::binary_op op, int t1, int t2) @@ -499,25 +561,6 @@ return retval; } -DEFUN (class, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} class (@var{expr})\n\ -\n\ -Return the class of the expression @var{expr}, as a string.\n\ -@end deftypefn") -{ - octave_value retval; - - int nargin = args.length (); - - if (nargin == 1) - retval = args(0).class_name (); - else - print_usage (); - - return retval; -} - /* ;;; Local Variables: *** ;;; mode: C++ *** diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-typeinfo.h --- a/src/ov-typeinfo.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-typeinfo.h Fri Dec 28 20:56:58 2007 +0000 @@ -40,10 +40,15 @@ { public: + typedef octave_value (*unary_class_op_fcn) (const octave_value&); + typedef octave_value (*unary_op_fcn) (const octave_base_value&); typedef void (*non_const_unary_op_fcn) (octave_base_value&); + typedef octave_value (*binary_class_op_fcn) + (const octave_value&, const octave_value&); + typedef octave_value (*binary_op_fcn) (const octave_base_value&, const octave_base_value&); @@ -61,11 +66,17 @@ static int register_type (const std::string&, const std::string&, const octave_value&); + static bool register_unary_class_op (octave_value::unary_op, + unary_class_op_fcn); + static bool register_unary_op (octave_value::unary_op, int, unary_op_fcn); static bool register_non_const_unary_op (octave_value::unary_op, int, non_const_unary_op_fcn); + static bool register_binary_class_op (octave_value::binary_op, + binary_class_op_fcn); + static bool register_binary_op (octave_value::binary_op, int, int, binary_op_fcn); @@ -91,6 +102,12 @@ return instance->do_lookup_type (nm); } + static unary_class_op_fcn + lookup_unary_class_op (octave_value::unary_op op) + { + return instance->do_lookup_unary_class_op (op); + } + static unary_op_fcn lookup_unary_op (octave_value::unary_op op, int t) { @@ -103,6 +120,12 @@ return instance->do_lookup_non_const_unary_op (op, t); } + static binary_class_op_fcn + lookup_binary_class_op (octave_value::binary_op op) + { + return instance->do_lookup_binary_class_op (op); + } + static binary_op_fcn lookup_binary_op (octave_value::binary_op op, int t1, int t2) { @@ -155,8 +178,10 @@ octave_value_typeinfo (void) : num_types (0), types (init_tab_sz, std::string ()), vals (init_tab_sz), + unary_class_ops (octave_value::num_unary_ops, 0), unary_ops (octave_value::num_unary_ops, init_tab_sz, 0), non_const_unary_ops (octave_value::num_unary_ops, init_tab_sz, 0), + binary_class_ops (octave_value::num_binary_ops, 0), binary_ops (octave_value::num_binary_ops, init_tab_sz, init_tab_sz, 0), cat_ops (init_tab_sz, init_tab_sz, 0), assign_ops (octave_value::num_assign_ops, init_tab_sz, init_tab_sz, 0), @@ -177,10 +202,14 @@ Array vals; + Array unary_class_ops; + Array2 unary_ops; Array2 non_const_unary_ops; + Array binary_class_ops; + Array3 binary_ops; Array2 cat_ops; @@ -198,11 +227,16 @@ int do_register_type (const std::string&, const std::string&, const octave_value&); + bool do_register_unary_class_op (octave_value::unary_op, unary_class_op_fcn); + bool do_register_unary_op (octave_value::unary_op, int, unary_op_fcn); bool do_register_non_const_unary_op (octave_value::unary_op, int, non_const_unary_op_fcn); + bool do_register_binary_class_op (octave_value::binary_op, + binary_class_op_fcn); + bool do_register_binary_op (octave_value::binary_op, int, int, binary_op_fcn); @@ -222,11 +256,15 @@ octave_value do_lookup_type (const std::string& nm); + unary_class_op_fcn do_lookup_unary_class_op (octave_value::unary_op); + unary_op_fcn do_lookup_unary_op (octave_value::unary_op, int); non_const_unary_op_fcn do_lookup_non_const_unary_op (octave_value::unary_op, int); + binary_class_op_fcn do_lookup_binary_class_op (octave_value::binary_op); + binary_op_fcn do_lookup_binary_op (octave_value::binary_op, int, int); cat_op_fcn do_lookup_cat_op (int, int); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-usr-fcn.cc --- a/src/ov-usr-fcn.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-usr-fcn.cc Fri Dec 28 20:56:58 2007 +0000 @@ -51,6 +51,31 @@ // Maximum nesting level for functions called recursively. static int Vmax_recursion_depth = 256; +// Scripts. + +octave_value_list +octave_user_script::do_multi_index_op (int nargout, + const octave_value_list& args) +{ + octave_value_list retval; + + if (! error_state) + { + if (args.length () == 0) + { + // FIXME -- I think we need a way to protect against + // recursion, but we can't use the same method as we use for + // functions. + + source_file (file_name); + } + else + error ("invalid call to script"); + } + + return retval; +} + // User defined functions. DEFINE_OCTAVE_ALLOCATOR (octave_user_function); @@ -69,17 +94,17 @@ // extrinsic/intrinsic state?). octave_user_function::octave_user_function - (tree_parameter_list *pl, tree_parameter_list *rl, - tree_statement_list *cl, symbol_table *st) + (symbol_table::scope_id sid, tree_parameter_list *pl, + tree_parameter_list *rl, tree_statement_list *cl) : octave_function (std::string (), std::string ()), param_list (pl), ret_list (rl), cmd_list (cl), - local_sym_tab (st), lead_comm (), trail_comm (), file_name (), + lead_comm (), trail_comm (), file_name (), parent_name (), t_parsed (static_cast (0)), t_checked (static_cast (0)), system_fcn_file (false), call_depth (0), num_named_args (0), - nested_function (false), inline_function (false), args_passed (), - num_args_passed (0), symtab_entry (0), argn_sr (0), - nargin_sr (0), nargout_sr (0), varargin_sr (0) + nested_function (false), inline_function (false), + class_constructor (false), class_method (false), xdispatch_class (), + args_passed (), num_args_passed (0), local_scope (sid) { if (param_list) num_named_args = param_list->length (); @@ -89,10 +114,11 @@ { delete param_list; delete ret_list; - delete local_sym_tab; delete cmd_list; delete lead_comm; delete trail_comm; + + symbol_table::erase_scope (local_scope); } octave_user_function * @@ -163,22 +189,6 @@ return retval; } -// For unwind protect. - -static void -pop_symbol_table_context (void *table) -{ - symbol_table *tmp = static_cast (table); - tmp->pop_context (); -} - -static void -clear_symbol_table (void *table) -{ - symbol_table *tmp = static_cast (table); - tmp->clear (); -} - static void clear_param_list (void *lst) { @@ -197,13 +207,6 @@ tmp->restore_args_passed (); } -static void -unprotect_function (void *sr_arg) -{ - symbol_record *sr = static_cast (sr_arg); - sr->unprotect (); -} - octave_value_list octave_user_function::subsref (const std::string& type, const std::list& idx, @@ -269,32 +272,23 @@ return retval; } - if (symtab_entry && ! symtab_entry->is_read_only ()) - { - symtab_entry->protect (); - unwind_protect::add (unprotect_function, symtab_entry); - } + // Save old and set current symbol table context, for + // eval_undefined_error(). + + symbol_table::push_scope (local_scope); + unwind_protect::add (symbol_table::pop_scope); if (call_depth > 1) { - local_sym_tab->push_context (); - unwind_protect::add (pop_symbol_table_context, local_sym_tab); - } - - install_automatic_vars (); - - // Force symbols to be undefined again when this function exits. + symbol_table::push_context (); - unwind_protect::add (clear_symbol_table, local_sym_tab); - - // Save old and set current symbol table context, for - // eval_undefined_error(). - - unwind_protect_ptr (curr_caller_sym_tab); - curr_caller_sym_tab = curr_sym_tab; - - unwind_protect_ptr (curr_sym_tab); - curr_sym_tab = local_sym_tab; + unwind_protect::add (symbol_table::pop_context); + } + else + { + // Force symbols to be undefined again when this function exits. + unwind_protect::add (symbol_table::clear_variables); + } unwind_protect_ptr (curr_caller_statement); curr_caller_statement = curr_statement; @@ -390,13 +384,11 @@ if (ret_list->takes_varargs ()) { - symbol_record *sr = local_sym_tab->lookup ("varargout"); + octave_value varargout_varval = symbol_table::varval ("varargout"); - if (sr && sr->is_variable ()) + if (varargout_varval.is_defined ()) { - octave_value v = sr->def (); - - varargout = v.cell_value (); + varargout = varargout_varval.cell_value (); if (error_state) error ("expecting varargout to be a cell array object"); @@ -443,14 +435,13 @@ tw.visit_octave_user_function (*this); } +#if 0 void octave_user_function::print_symtab_info (std::ostream& os) const { - if (local_sym_tab) - local_sym_tab->print_info (os); - else - warning ("%s: no symbol table info!", my_name.c_str ()); + symbol_table::print_info (os, local_scope); } +#endif void octave_user_function::print_code_function_header (void) @@ -469,29 +460,18 @@ } void -octave_user_function::install_automatic_vars (void) -{ - if (local_sym_tab) - { - argn_sr = local_sym_tab->lookup ("argn", true); - nargin_sr = local_sym_tab->lookup ("__nargin__", true); - nargout_sr = local_sym_tab->lookup ("__nargout__", true); - - if (takes_varargs ()) - varargin_sr = local_sym_tab->lookup ("varargin", true); - } -} - -void octave_user_function::bind_automatic_vars (const string_vector& arg_names, int nargin, int nargout, const octave_value_list& va_args) { if (! arg_names.empty ()) - argn_sr->define (arg_names); + symbol_table::varref ("argn") = arg_names; - nargin_sr->define (nargin); - nargout_sr->define (nargout); + symbol_table::varref (".nargin.") = nargin; + symbol_table::varref (".nargout.") = nargout; + + symbol_table::mark_hidden (".nargin."); + symbol_table::mark_hidden (".nargout."); if (takes_varargs ()) { @@ -502,7 +482,7 @@ for (int i = 0; i < n; i++) varargin(0,i) = va_args(i); - varargin_sr->define (varargin); + symbol_table::varref ("varargin") = varargin; } } @@ -528,7 +508,7 @@ if (! error_state) { - octave_value fcn_val = lookup_user_function (fname); + octave_value fcn_val = symbol_table::find_user_function (fname); octave_user_function *fcn = fcn_val.user_function_value (true); @@ -551,9 +531,10 @@ } else if (nargin == 0) { - symbol_record *sr = curr_sym_tab->lookup ("__nargin__"); + retval = symbol_table::varval (".nargin."); - retval = sr ? sr->def () : 0; + if (retval.is_undefined ()) + retval = 0; } else print_usage (); @@ -601,7 +582,7 @@ if (! error_state) { - octave_value fcn_val = lookup_user_function (fname); + octave_value fcn_val = symbol_table::find_user_function (fname); octave_user_function *fcn = fcn_val.user_function_value (true); @@ -624,11 +605,12 @@ } else if (nargin == 0) { - if (! at_top_level ()) + if (! symbol_table::at_top_level ()) { - symbol_record *sr = curr_sym_tab->lookup ("__nargout__"); + retval = symbol_table::varval (".nargout."); - retval = sr ? sr->def () : 0; + if (retval.is_undefined ()) + retval = 0; } else error ("nargout: invalid call at top level"); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov-usr-fcn.h --- a/src/ov-usr-fcn.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov-usr-fcn.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ #include "oct-obj.h" #include "ov-fcn.h" #include "ov-typeinfo.h" +#include "symtab.h" class string_vector; @@ -41,8 +42,6 @@ class tree_statement_list; class tree_va_return_list; class tree_walker; -class symbol_table; -class symbol_record; // Scripts. @@ -54,7 +53,7 @@ octave_user_script (void) { } octave_user_script (const std::string& fnm, const std::string& nm, - const std::string& ds) + const std::string& ds = std::string ()) : octave_function (nm, ds), file_name (fnm) { } ~octave_user_script (void) { } @@ -68,9 +67,12 @@ std::string fcn_file_name (void) const { return file_name; } + octave_value_list + do_multi_index_op (int nargout, const octave_value_list& args); + private: - // The name of the file we parsed + // The name of the file to parse. std::string file_name; // No copying! @@ -91,10 +93,10 @@ { public: - octave_user_function (tree_parameter_list *pl = 0, + octave_user_function (symbol_table::scope_id sid = -1, + tree_parameter_list *pl = 0, tree_parameter_list *rl = 0, - tree_statement_list *cl = 0, - symbol_table *st = 0); + tree_statement_list *cl = 0); ~octave_user_function (void); @@ -122,12 +124,12 @@ mark_fcn_file_up_to_date (t); } - void stash_symtab_ptr (symbol_record *sr) { symtab_entry = sr; } - std::string fcn_file_name (void) const { return file_name; } std::string parent_fcn_name (void) const { return parent_name; } + symbol_table::scope_id scope (void) { return local_scope; } + octave_time time_parsed (void) const { return t_parsed; } octave_time time_checked (void) const { return t_checked; } @@ -154,6 +156,18 @@ bool is_inline_function (void) const { return inline_function; } + void mark_as_class_constructor (void) { class_constructor = true; } + + bool is_class_constructor (void) const { return class_constructor; } + + void mark_as_class_method (void) { class_method = true; } + + bool is_class_method (void) const { return class_method; } + + void stash_dispatch_class (const std::string& nm) { xdispatch_class = nm; } + + std::string dispatch_class (void) const { return xdispatch_class; } + void save_args_passed (const octave_value_list& args) { if (call_depth > 1) @@ -195,15 +209,15 @@ tree_statement_list *body (void) { return cmd_list; } - symbol_table *sym_tab (void) { return local_sym_tab; } - octave_comment_list *leading_comment (void) { return lead_comm; } octave_comment_list *trailing_comment (void) { return trail_comm; } void accept (tree_walker& tw); +#if 0 void print_symtab_info (std::ostream& os) const; +#endif private: @@ -217,9 +231,6 @@ // The list of commands that make up the body of this function. tree_statement_list *cmd_list; - // The local symbol table for this function. - symbol_table *local_sym_tab; - // The comments preceding the FUNCTION token. octave_comment_list *lead_comm; @@ -256,6 +267,16 @@ // TRUE means this is an inline function. bool inline_function; + // TRUE means this function is the constructor for class object. + bool class_constructor; + + // TRUE means this function is a method for a class. + bool class_method; + + // If this object is a class method or constructor, this is the name + // of the class to which the method belongs. + std::string xdispatch_class; + // The values that were passed as arguments. octave_value_list args_passed; @@ -265,27 +286,26 @@ // The number of arguments passed in. int num_args_passed; - // The symbol record for this function. - symbol_record *symtab_entry; + symbol_table::scope_id local_scope; +#if 0 // The symbol record for argn in the local symbol table. - symbol_record *argn_sr; + octave_value& argn_varref; // The symbol record for nargin in the local symbol table. - symbol_record *nargin_sr; + octave_value& nargin_varref; // The symbol record for nargout in the local symbol table. - symbol_record *nargout_sr; + octave_value& nargout_varref; // The symbol record for varargin in the local symbol table. - symbol_record *varargin_sr; + octave_value& varargin_varref; +#endif void print_code_function_header (void); void print_code_function_trailer (void); - void install_automatic_vars (void); - void bind_automatic_vars (const string_vector& arg_names, int nargin, int nargout, const octave_value_list& va_args); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov.cc --- a/src/ov.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov.cc Fri Dec 28 20:56:58 2007 +0000 @@ -55,6 +55,7 @@ #include "ov-str-mat.h" #include "ov-range.h" #include "ov-struct.h" +#include "ov-class.h" #include "ov-streamoff.h" #include "ov-list.h" #include "ov-cs-list.h" @@ -73,6 +74,7 @@ #include "pager.h" #include "parse.h" #include "pr-output.h" +#include "symtab.h" #include "utils.h" #include "variables.h" @@ -127,6 +129,40 @@ } std::string +octave_value::unary_op_fcn_name (unary_op op) +{ + std::string retval; + + switch (op) + { + case op_not: + retval = "not"; + break; + + case op_uplus: + retval = "uplus"; + break; + + case op_uminus: + retval = "uminus"; + break; + + case op_transpose: + retval = "transpose"; + break; + + case op_hermitian: + retval = "ctranspose"; + break; + + default: + break; + } + + return retval; +} + +std::string octave_value::binary_op_as_string (binary_op op) { std::string retval; @@ -225,6 +261,92 @@ } std::string +octave_value::binary_op_fcn_name (binary_op op) +{ + std::string retval; + + switch (op) + { + case op_add: + retval = "plus"; + break; + + case op_sub: + retval = "minus"; + break; + + case op_mul: + retval = "mtimes"; + break; + + case op_div: + retval = "mrdivide"; + break; + + case op_pow: + retval = "mpower"; + break; + + case op_ldiv: + retval = "mldivide"; + break; + + case op_lt: + retval = "lt"; + break; + + case op_le: + retval = "le"; + break; + + case op_eq: + retval = "eq"; + break; + + case op_ge: + retval = "ge"; + break; + + case op_gt: + retval = "gt"; + break; + + case op_ne: + retval = "ne"; + break; + + case op_el_mul: + retval = "times"; + break; + + case op_el_div: + retval = "rdivide"; + break; + + case op_el_pow: + retval = "power"; + break; + + case op_el_ldiv: + retval = "ldivide"; + break; + + case op_el_and: + retval = "and"; + break; + + case op_el_or: + retval = "or"; + break; + + default: + break; + } + + return retval; +} + +std::string octave_value::assign_op_as_string (assign_op op) { std::string retval; @@ -719,6 +841,11 @@ { } +octave_value::octave_value (const Octave_map& m, const std::string& id) + : rep (new octave_class (m, id)) +{ +} + octave_value::octave_value (const streamoff_array& off) : rep (new octave_streamoff (off)) { @@ -741,6 +868,12 @@ { } +octave_value::octave_value (octave_base_value *new_rep, int xcount) + : rep (new_rep) +{ + rep->count = xcount; +} + octave_base_value * octave_value::clone (void) const { @@ -886,7 +1019,7 @@ if (! error_state) { - if (type[0] == '.' && ! is_map ()) + if (type[0] == '.' && ! (is_map () || is_object ())) { octave_value tmp = Octave_map (); retval = tmp.subsasgn (type, idx, t_rhs); @@ -1369,68 +1502,86 @@ int t1 = v1.type_id (); int t2 = v2.type_id (); - octave_value_typeinfo::binary_op_fcn f - = octave_value_typeinfo::lookup_binary_op (op, t1, t2); + if (t1 == octave_class::static_type_id () + || t2 == octave_class::static_type_id ()) + { + octave_value_typeinfo::binary_class_op_fcn f + = octave_value_typeinfo::lookup_binary_class_op (op); - if (f) - retval = f (*v1.rep, *v2.rep); + if (f) + retval = f (v1, v2); + else + gripe_binary_op (octave_value::binary_op_as_string (op), + v1.class_name (), v2.class_name ()); + } else { - octave_value tv1; - octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function (); + // FIXME -- we need to handle overloading operators for built-in + // classes (double, char, int8, etc.) - if (cf1) + octave_value_typeinfo::binary_op_fcn f + = octave_value_typeinfo::lookup_binary_op (op, t1, t2); + + if (f) + retval = f (*v1.rep, *v2.rep); + else { - octave_base_value *tmp = cf1 (*v1.rep); + octave_value tv1; + octave_base_value::type_conv_fcn cf1 = v1.numeric_conversion_function (); + + if (cf1) + { + octave_base_value *tmp = cf1 (*v1.rep); - if (tmp) - { - tv1 = octave_value (tmp); - t1 = tv1.type_id (); + if (tmp) + { + tv1 = octave_value (tmp); + t1 = tv1.type_id (); + } + else + { + gripe_binary_op_conv (octave_value::binary_op_as_string (op)); + return retval; + } } else + tv1 = v1; + + octave_value tv2; + octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function (); + + if (cf2) { - gripe_binary_op_conv (octave_value::binary_op_as_string (op)); - return retval; - } - } - else - tv1 = v1; + octave_base_value *tmp = cf2 (*v2.rep); - octave_value tv2; - octave_base_value::type_conv_fcn cf2 = v2.numeric_conversion_function (); - - if (cf2) - { - octave_base_value *tmp = cf2 (*v2.rep); - - if (tmp) - { - tv2 = octave_value (tmp); - t2 = tv2.type_id (); + if (tmp) + { + tv2 = octave_value (tmp); + t2 = tv2.type_id (); + } + else + { + gripe_binary_op_conv (octave_value::binary_op_as_string (op)); + return retval; + } } else + tv2 = v2; + + if (cf1 || cf2) { - gripe_binary_op_conv (octave_value::binary_op_as_string (op)); - return retval; + f = octave_value_typeinfo::lookup_binary_op (op, t1, t2); + + if (f) + retval = f (*tv1.rep, *tv2.rep); + else + gripe_binary_op (octave_value::binary_op_as_string (op), + v1.type_name (), v2.type_name ()); } - } - else - tv2 = v2; - - if (cf1 || cf2) - { - f = octave_value_typeinfo::lookup_binary_op (op, t1, t2); - - if (f) - retval = f (*tv1.rep, *tv2.rep); else gripe_binary_op (octave_value::binary_op_as_string (op), v1.type_name (), v2.type_name ()); } - else - gripe_binary_op (octave_value::binary_op_as_string (op), - v1.type_name (), v2.type_name ()); } return retval; @@ -1560,39 +1711,57 @@ int t = v.type_id (); - octave_value_typeinfo::unary_op_fcn f - = octave_value_typeinfo::lookup_unary_op (op, t); + if (t == octave_class::static_type_id ()) + { + octave_value_typeinfo::unary_class_op_fcn f + = octave_value_typeinfo::lookup_unary_class_op (op); - if (f) - retval = f (*v.rep); + if (f) + retval = f (v); + else + gripe_unary_op (octave_value::unary_op_as_string (op), + v.class_name ()); + } else { - octave_value tv; - octave_base_value::type_conv_fcn cf = v.numeric_conversion_function (); + // FIXME -- we need to handle overloading operators for built-in + // classes (double, char, int8, etc.) + + octave_value_typeinfo::unary_op_fcn f + = octave_value_typeinfo::lookup_unary_op (op, t); - if (cf) + if (f) + retval = f (*v.rep); + else { - octave_base_value *tmp = cf (*v.rep); + octave_value tv; + octave_base_value::type_conv_fcn cf + = v.numeric_conversion_function (); - if (tmp) + if (cf) { - tv = octave_value (tmp); - t = tv.type_id (); + octave_base_value *tmp = cf (*v.rep); - f = octave_value_typeinfo::lookup_unary_op (op, t); + if (tmp) + { + tv = octave_value (tmp); + t = tv.type_id (); + + f = octave_value_typeinfo::lookup_unary_op (op, t); - if (f) - retval = f (*tv.rep); + if (f) + retval = f (*tv.rep); + else + gripe_unary_op (octave_value::unary_op_as_string (op), + v.type_name ()); + } else - gripe_unary_op (octave_value::unary_op_as_string (op), - v.type_name ()); + gripe_unary_op_conv (octave_value::unary_op_as_string (op)); } else - gripe_unary_op_conv (octave_value::unary_op_as_string (op)); + gripe_unary_op (octave_value::unary_op_as_string (op), + v.type_name ()); } - else - gripe_unary_op (octave_value::unary_op_as_string (op), - v.type_name ()); } return retval; @@ -1882,6 +2051,7 @@ octave_sparse_matrix::register_type (); octave_sparse_complex_matrix::register_type (); octave_struct::register_type (); + octave_class::register_type (); octave_list::register_type (); octave_cs_list::register_type (); octave_magic_colon::register_type (); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/ov.h --- a/src/ov.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/ov.h Fri Dec 28 20:56:58 2007 +0000 @@ -130,8 +130,10 @@ }; static std::string unary_op_as_string (unary_op); + static std::string unary_op_fcn_name (unary_op); static std::string binary_op_as_string (binary_op); + static std::string binary_op_fcn_name (binary_op); static std::string assign_op_as_string (assign_op); @@ -225,11 +227,13 @@ octave_value (double base, double limit, double inc); octave_value (const Range& r); octave_value (const Octave_map& m); + octave_value (const Octave_map& m, const std::string& id); octave_value (const streamoff_array& off); octave_value (const octave_value_list& m, bool is_cs_list = false); octave_value (octave_value::magic_colon); octave_value (octave_base_value *new_rep); + octave_value (octave_base_value *new_rep, int xcount); // Copy constructor. @@ -442,6 +446,9 @@ bool is_map (void) const { return rep->is_map (); } + bool is_object (void) const + { return rep->is_object (); } + bool is_streamoff (void) const { return rep->is_streamoff (); } @@ -550,6 +557,12 @@ bool is_function (void) const { return rep->is_function (); } + bool is_user_script (void) const + { return rep->is_user_script (); } + + bool is_user_function (void) const + { return rep->is_user_function (); } + bool is_builtin_function (void) const { return rep->is_builtin_function (); } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/parse.h --- a/src/parse.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/parse.h Fri Dec 28 20:56:58 2007 +0000 @@ -38,14 +38,9 @@ class tree_matrix; class tree_identifier; class octave_function; -class symbol_record; -class symbol_table; #include "oct-obj.h" -// Temporary symbol table pointer used to cope with bogus function syntax. -extern symbol_table *tmp_local_sym_tab; - // Nonzero means print parser debugging info (-d). extern int octave_debug; @@ -73,12 +68,16 @@ extern bool evaluating_function_body; // Keep track of symbol table information when parsing functions. -extern std::stack symtab_context; +extern std::stack symtab_context; // Name of parent function when parsing function files that might // contain nested functions. extern std::string parent_function_name; +// Name of the current class when we are parsing class methods or +// constructors. +extern std::string current_class_name; + // Keep a count of how many END tokens we expect. extern int end_tokens_expected; @@ -102,11 +101,12 @@ extern OCTINTERP_API string_vector reverse_lookup_autoload (const std::string& nm); -extern OCTINTERP_API bool -load_fcn_from_file (const std::string& nm, bool exec_script); - -extern OCTINTERP_API bool -load_fcn_from_file (symbol_record *sym_rec, bool exec_script); +extern OCTINTERP_API octave_function * +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& fcn_name = std::string (), + bool autoload = false); extern OCTINTERP_API void source_file (const std::string& file_name, diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/parse.y --- a/src/parse.y Fri Feb 01 23:56:51 2008 -0500 +++ b/src/parse.y Fri Dec 28 20:56:58 2007 +0000 @@ -75,9 +75,6 @@ #include "utils.h" #include "variables.h" -// Temporary symbol table pointer used to cope with bogus function syntax. -symbol_table *tmp_local_sym_tab = 0; - // The current input line number. int input_line_number = 0; @@ -109,12 +106,16 @@ int end_tokens_expected = 0; // Keep track of symbol table information when parsing functions. -std::stack symtab_context; +std::stack symtab_context; // Name of parent function when parsing function files that might // contain nested functions. std::string parent_function_name; +// Name of the current class when we are parsing class methods or +// constructors. +std::string current_class_name; + // TRUE means we are in the process of autoloading a function. static bool autoloading = false; @@ -122,6 +123,10 @@ // element. static bool fcn_file_from_relative_lookup = false; +// If nonzero, this is a pointer to the function we just finished +// parsing. +static octave_function *curr_fcn_ptr = 0; + // List of autoloads (function -> file mapping). static std::map autoload_map; @@ -263,12 +268,7 @@ frob_function (const std::string& fname, octave_user_function *fcn); // Finish defining a function. -static octave_user_function * -finish_function (tree_identifier *id, octave_user_function *fcn, - octave_comment_list *lc); - -// Finish defining a function a different way. -static octave_user_function * +static void finish_function (tree_parameter_list *ret_list, octave_user_function *fcn, octave_comment_list *lc); @@ -316,7 +316,7 @@ yyerrok; \ if (! symtab_context.empty ()) \ { \ - curr_sym_tab = symtab_context.top (); \ + symbol_table::set_scope (symtab_context.top ()); \ symtab_context.pop (); \ } \ if (interactive || forced_interactive) \ @@ -415,7 +415,7 @@ %type primary_expr postfix_expr prefix_expr binary_expr %type simple_expr colon_expr assign_expr expression %type identifier fcn_name -%type function1 function2 function3 +%type function1 function2 %type word_list_cmd %type colon_expr1 %type arg_list word_list assign_lhs @@ -435,7 +435,7 @@ %type declaration %type statement %type simple_list simple_list1 list list1 -%type opt_list input1 function4 +%type opt_list input1 // Precedence and associativity. %left ';' ',' '\n' @@ -554,8 +554,8 @@ identifier : NAME { - $$ = new tree_identifier - ($1->sym_rec (), $1->line (), $1->column ()); + symbol_table::symbol_record *sr = $1->sym_rec (); + $$ = new tree_identifier (*sr, $1->line (), $1->column ()); } ; @@ -1098,16 +1098,14 @@ // Some `subroutines' for function definitions // =========================================== -save_symtab : // empty - { symtab_context.push (curr_sym_tab); } - ; - -function_symtab : // empty - { curr_sym_tab = fbi_sym_tab; } - ; - -local_symtab : // empty - { curr_sym_tab = tmp_local_sym_tab; } +push_fcn_symtab : // empty + { + symtab_context.push (symbol_table::current_scope ()); + symbol_table::set_scope (symbol_table::alloc_scope ()); + + if (! lexer_flags.parsing_nested_function) + symbol_table::set_parent_scope (symbol_table::current_scope ()); + } ; // =========================== @@ -1120,12 +1118,8 @@ if (lexer_flags.looking_at_function_handle) { - symtab_context.push (curr_sym_tab); - - tmp_local_sym_tab = new symbol_table (); - - curr_sym_tab = tmp_local_sym_tab; - + symtab_context.push (symbol_table::current_scope ()); + symbol_table::set_scope (symbol_table::alloc_scope ()); lexer_flags.looking_at_function_handle--; } } @@ -1182,15 +1176,12 @@ // List of function return value names // =================================== -return_list_beg : '[' local_symtab - ; - -return_list : return_list_beg return_list_end +return_list : '[' ']' { lexer_flags.looking_at_return_list = false; $$ = new tree_parameter_list (); } - | return_list_beg VARARGOUT return_list_end + | '[' VARARGOUT ']' { lexer_flags.looking_at_return_list = false; tree_parameter_list *tmp = new tree_parameter_list (); @@ -1204,12 +1195,17 @@ tmp->mark_varargs_only (); $$ = tmp; } - | return_list_beg return_list1 return_list_end + | return_list1 + { + lexer_flags.looking_at_return_list = false; + $$ = $1; + } + | '[' return_list1 ']' { lexer_flags.looking_at_return_list = false; $$ = $2; } - | return_list_beg return_list1 ',' VARARGOUT return_list_end + | '[' return_list1 ',' VARARGOUT ']' { lexer_flags.looking_at_return_list = false; $2->mark_varargs (); @@ -1226,42 +1222,29 @@ } ; -return_list_end : function_symtab ']' - ; - // =================== // Function definition // =================== -function_beg : save_symtab FCN function_symtab stash_comment - { $$ = $4; } +function_beg : push_fcn_symtab FCN stash_comment + { $$ = $3; } ; -function : function_beg function2 +function : function_beg function1 { $2->stash_leading_comment ($1); recover_from_parsing_function (); $$ = 0; } - | function_beg identifier function1 + | function_beg return_list '=' function1 { - finish_function ($2, $3, $1); - recover_from_parsing_function (); - $$ = 0; - } - | function_beg return_list function1 - { - finish_function ($2, $3, $1); + finish_function ($2, $4, $1); recover_from_parsing_function (); $$ = 0; } ; -function1 : function_symtab '=' function2 - { $$ = $3; } - ; - -fcn_name : identifier local_symtab +fcn_name : identifier { std::string id_name = $1->name (); @@ -1276,7 +1259,7 @@ } ; -function2 : fcn_name function3 +function1 : fcn_name function2 { std::string fname = $1->name (); @@ -1287,14 +1270,10 @@ } ; -function3 : param_list function4 - { $$ = start_function ($1, $2); } - | function4 - { $$ = start_function (0, $1); } - ; - -function4 : opt_sep opt_list function_end - { $$ = $2; } +function2 : param_list opt_sep opt_list function_end + { $$ = start_function ($1, $3); } + | opt_sep opt_list function_end + { $$ = start_function (0, $2); } ; function_end : END @@ -1772,24 +1751,45 @@ tree_parameter_list *ret_list = 0; - symbol_table *fcn_sym_tab = curr_sym_tab; + symbol_table::scope_id fcn_scope = symbol_table::current_scope (); if (symtab_context.empty ()) panic_impossible (); - curr_sym_tab = symtab_context.top (); + symbol_table::set_scope (symtab_context.top ()); symtab_context.pop (); if (stmt && stmt->is_expression ()) - stmt->set_print_flag (false); + { + symbol_table::symbol_record& sr = symbol_table::insert ("__retval__"); + + tree_expression *e = stmt->expression (); + + tree_identifier *id = new tree_identifier (sr); + + tree_simple_assignment *asn = new tree_simple_assignment (id, e); + + stmt->set_expression (asn); + + stmt->set_print_flag (false); + + // FIXME -- would like to delete old_stmt here or + // replace expression inside it with the new expression we just + // created so we don't have to create a new statement at all. + + id = new tree_identifier (sr); + tree_decl_elt *elt = new tree_decl_elt (id); + + ret_list = new tree_parameter_list (elt); + } tree_statement_list *body = new tree_statement_list (stmt); body->mark_as_function_body (); tree_anon_fcn_handle *retval - = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_sym_tab, l, c); + = new tree_anon_fcn_handle (param_list, ret_list, body, fcn_scope, l, c); return retval; } @@ -2423,7 +2423,9 @@ // We'll fill in the return list later. octave_user_function *fcn - = new octave_user_function (param_list, 0, body, curr_sym_tab); + = new octave_user_function (symbol_table::current_scope (), + param_list, 0, body); + if (fcn) { @@ -2449,15 +2451,30 @@ if (reading_fcn_file || autoloading) { - if (! (lexer_flags.parsing_nested_function || autoloading) - && curr_fcn_file_name != id_name) + if (! (autoloading + || lexer_flags.parsing_nested_function + || lexer_flags.parsing_class_method)) { - warning_with_id - ("Octave:function-name-clash", - "function name `%s' does not agree with function file name `%s'", - id_name.c_str (), curr_fcn_file_full_name.c_str ()); - - id_name = curr_fcn_file_name; + // FIXME -- should curr_fcn_file_name already be + // preprocessed when we get here? It seems to only be a + // problem with relative file names. + + std::string nm = curr_fcn_file_name; + + size_t pos = nm.find_last_of (file_ops::dir_sep_chars); + + if (pos != NPOS) + nm = curr_fcn_file_name.substr (pos+1); + + if (nm != id_name) + { + warning_with_id + ("Octave:function-name-clash", + "function name `%s' does not agree with function file name `%s'", + id_name.c_str (), curr_fcn_file_full_name.c_str ()); + + id_name = nm; + } } octave_time now; @@ -2472,6 +2489,16 @@ if (lexer_flags.parsing_nested_function) fcn->stash_parent_fcn_name (parent_function_name); + if (lexer_flags.parsing_class_method) + { + if (current_class_name == id_name) + fcn->mark_as_class_constructor (); + else + fcn->mark_as_class_method (); + + fcn->stash_dispatch_class (current_class_name); + } + std::string nm = fcn->fcn_file_name (); file_stat fs (nm); @@ -2490,105 +2517,47 @@ fcn->stash_function_name (id_name); - // Enter the new function in fbi_sym_tab. If there is already a - // variable of the same name in the current symbol table, we won't - // find the new function when we try to call it, so we need to clear - // the old symbol from the current symbol table. Note that this - // means that for things like - // - // function f () eval ("function g () 1, end"); end - // g = 13; - // f (); - // g - // - // G will still refer to the variable G (with value 13) rather - // than the function G, until the variable G is cleared. - - curr_sym_tab->clear (id_name); - - if (! lexer_flags.parsing_nested_function - && symtab_context.top () == top_level_sym_tab) + if (! help_buf.empty ()) + { + fcn->document (help_buf.top ()); + + help_buf.pop (); + } + + if (lexer_flags.parsing_nested_function) { - symbol_record *sr = top_level_sym_tab->lookup (id_name); - - // Only clear the existing name if it is already defined as a - // function. If there is already a variable defined with the - // same name as a the current function, it will continue to - // shadow this name until the variable is cleared. This means - // that for something like the following at the command line, - // - // f = 13; - // function f () 7, end - // f - // - // F will still refer to the variable F (with value 13) rather - // than the function F, until the variable F is cleared. - - if (sr && sr->is_function ()) - top_level_sym_tab->clear (id_name); - } - - symbol_record *sr = fbi_sym_tab->lookup (id_name, true); - - if (sr) - { - fcn->stash_symtab_ptr (sr); - - if (lexer_flags.parsing_nested_function) - { - fcn->mark_as_nested_function (); - sr->hide (); + std::string nm = fcn->name (); + + fcn->mark_as_nested_function (); + + symbol_table::install_subfunction (nm, octave_value (fcn)); + + if (lexer_flags.parsing_nested_function < 0) + { + lexer_flags.parsing_nested_function = 0; + symbol_table::reset_parent_scope (); } } - else - panic_impossible (); - - sr->define (fcn, symbol_record::USER_FUNCTION); - - if (! help_buf.empty ()) + else if (! reading_fcn_file) { - sr->document (help_buf.top ()); - help_buf.pop (); + std::string nm = fcn->name (); + + symbol_table::install_cmdline_function (nm, octave_value (fcn)); + + // Make sure that any variable with the same name as the new + // function is cleared. + + symbol_table::varref (nm) = octave_value (); } - - // Also insert the full name in the symbol table. This way, we can - // properly cope with changes to LOADPATH. - - if (reading_fcn_file) - { - symbol_record *full_sr - = fbi_sym_tab->lookup (curr_fcn_file_full_name, true); - - full_sr->alias (sr, true); - full_sr->hide (); - } - - if (lexer_flags.parsing_nested_function < 0) - lexer_flags.parsing_nested_function = 0; + else + curr_fcn_ptr = fcn; return fcn; } // Finish defining a function. -static octave_user_function * -finish_function (tree_identifier *id, octave_user_function *fcn, - octave_comment_list *lc) -{ - tree_decl_elt *tmp = new tree_decl_elt (id); - - tree_parameter_list *tpl = new tree_parameter_list (tmp); - - tpl->mark_as_formal_parameters (); - - fcn->stash_leading_comment (lc); - - return fcn->define_ret_list (tpl); -} - -// Finish defining a function a different way. - -static octave_user_function * +static void finish_function (tree_parameter_list *ret_list, octave_user_function *fcn, octave_comment_list *lc) { @@ -2596,7 +2565,7 @@ fcn->stash_leading_comment (lc); - return fcn->define_ret_list (ret_list); + fcn->define_ret_list (ret_list); } static void @@ -2605,7 +2574,7 @@ if (symtab_context.empty ()) panic_impossible (); - curr_sym_tab = symtab_context.top (); + symbol_table::set_scope (symtab_context.top ()); symtab_context.pop (); lexer_flags.defining_func = false; @@ -2848,8 +2817,6 @@ get_input_from_eval_string = false; parser_end_of_input = false; - unwind_protect_ptr (curr_sym_tab); - int retval; do { @@ -3205,6 +3172,23 @@ return status; } +static int +is_function_file (const std::string& fname) +{ + int retval = 0; + + FILE *fid = fopen (fname.c_str (), "r"); + + if (fid) + { + retval = is_function_file (fid); + + fclose (fid); + } + + return retval; +} + static void restore_command_history (void *) { @@ -3217,13 +3201,15 @@ command_editor::set_input_stream (static_cast (f)); } -static bool -parse_fcn_file (const std::string& ff, bool exec_script, - bool force_script = false) +typedef octave_function * octave_function_ptr; + +static octave_function * +parse_fcn_file (const std::string& ff, const std::string& dispatch_type, + bool exec_script, bool force_script = false) { unwind_protect::begin_frame ("parse_fcn_file"); - int script_file_executed = false; + octave_function *fcn_ptr = 0; // Open function file and parse. @@ -3241,6 +3227,7 @@ unwind_protect_bool (reading_fcn_file); unwind_protect_bool (line_editing); unwind_protect_str (parent_function_name); + unwind_protect_str (current_class_name); input_line_number = 0; current_input_column = 1; @@ -3248,6 +3235,7 @@ reading_fcn_file = true; line_editing = false; parent_function_name = ""; + current_class_name = dispatch_type; FILE *ffile = get_input_from_file (ff, 0); @@ -3287,7 +3275,8 @@ switch_to_buffer (new_buf); - unwind_protect_ptr (curr_sym_tab); + unwind_protect_ptr (curr_fcn_ptr); + curr_fcn_ptr = 0; reset_parser (); @@ -3301,14 +3290,14 @@ // FIXME -- this should not be necessary. gobble_leading_white_space (ffile, false, true, false, false); + lexer_flags.parsing_class_method = ! dispatch_type.empty (); + int status = yyparse (); + fcn_ptr = curr_fcn_ptr; + if (status != 0) - { - error ("parse error while reading function file %s", - ff.c_str ()); - fbi_sym_tab->clear (curr_fcn_file_name); - } + error ("parse error while reading function file %s", ff.c_str ()); } else if (exec_script) { @@ -3334,8 +3323,6 @@ unwind_protect::add (octave_call_stack::unwind_pop_script, 0); parse_and_execute (ffile); - - script_file_executed = true; } } else @@ -3343,7 +3330,7 @@ unwind_protect::run_frame ("parse_fcn_file"); - return script_file_executed; + return fcn_ptr; } std::string @@ -3387,14 +3374,16 @@ return names; } -bool -load_fcn_from_file (const std::string& nm_arg, bool exec_script) +octave_function * +load_fcn_from_file (const std::string& file_name, const std::string& dir_name, + const std::string& dispatch_type, + const std::string& fcn_name, bool autoload) { + octave_function *retval = 0; + unwind_protect::begin_frame ("load_fcn_from_file"); - bool script_file_executed = false; - - std::string nm = nm_arg; + std::string nm = file_name; size_t nm_len = nm.length (); @@ -3404,30 +3393,24 @@ fcn_file_from_relative_lookup = false; - if (octave_env::absolute_pathname (nm) - && ((nm_len > 4 && nm.substr (nm_len-4) == ".oct") - || (nm_len > 4 && nm.substr (nm_len-4) == ".mex") - || (nm_len > 2 && nm.substr (nm_len-2) == ".m"))) + file = nm; + + if ((nm_len > 4 && nm.substr (nm_len-4) == ".oct") + || (nm_len > 4 && nm.substr (nm_len-4) == ".mex") + || (nm_len > 2 && nm.substr (nm_len-2) == ".m")) { - file = nm; - nm = octave_env::base_pathname (file); nm = nm.substr (0, nm.find_last_of ('.')); } - else + + if (autoload) { - file = lookup_autoload (nm); - - if (! file.empty ()) - { - unwind_protect_bool (autoloading); - - autoloading = true; - exec_script = true; - } - else - file = load_path::find_fcn (nm); - + unwind_protect_bool (autoloading); + autoloading = true; + } + + if (! file.empty ()) + { fcn_file_from_relative_lookup = ! octave_env::absolute_pathname (file); file = octave_env::make_absolute (file, octave_env::getcwd ()); @@ -3437,47 +3420,37 @@ if (len > 4 && file.substr (len-4, len-1) == ".oct") { - if (octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup)) - force_link_to_function (nm); + if (autoload && ! fcn_name.empty ()) + nm = fcn_name; + + retval = octave_dynamic_loader::load_oct (nm, file, fcn_file_from_relative_lookup); } else if (len > 4 && file.substr (len-4, len-1) == ".mex") - { - if (octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup)) - force_link_to_function (nm); - } + retval = octave_dynamic_loader::load_mex (nm, file, fcn_file_from_relative_lookup); else if (len > 2) { - // These are needed by yyparse. - - unwind_protect_str (curr_fcn_file_name); - unwind_protect_str (curr_fcn_file_full_name); - - curr_fcn_file_name = nm; - curr_fcn_file_full_name = file; - - script_file_executed = parse_fcn_file (file, exec_script, autoloading); - - if (! error_state) + if (is_function_file (file)) { - if (autoloading) - { - script_file_executed = false; - force_link_to_function (nm); - } - else if (! script_file_executed) - force_link_to_function (nm); + // These are needed by yyparse. + + unwind_protect_str (curr_fcn_file_name); + unwind_protect_str (curr_fcn_file_full_name); + + curr_fcn_file_name = nm; + curr_fcn_file_full_name = file; + + retval = parse_fcn_file (file, dispatch_type, false, autoloading); } + else + retval = new octave_user_script (file, fcn_name); } + if (retval) + retval->stash_dir_name (dir_name); + unwind_protect::run_frame ("load_fcn_from_file"); - return script_file_executed; -} - -bool -load_fcn_from_file (symbol_record *sym_rec, bool exec_script) -{ - return load_fcn_from_file (sym_rec->name (), exec_script); + return retval; } DEFCMD (autoload, args, , @@ -3598,19 +3571,20 @@ if (! context.empty ()) { - unwind_protect_ptr (curr_sym_tab); - if (context == "caller") - curr_sym_tab = curr_caller_sym_tab; + symbol_table::push_scope (symbol_table::current_caller_scope ()); else if (context == "base") - curr_sym_tab = top_level_sym_tab; + symbol_table::push_scope (symbol_table::top_scope ()); else error ("source: context must be \"caller\" or \"base\""); + + if (! error_state) + unwind_protect::add (symbol_table::pop_scope); } if (! error_state) { - parse_fcn_file (file_full_name, true, true); + parse_fcn_file (file_full_name, "", true, true); if (error_state) error ("source: error sourcing file `%s'", @@ -3736,10 +3710,12 @@ { octave_value_list retval; - octave_function *fcn = is_valid_function (name, "feval", 1); - - if (fcn) - retval = fcn->do_multi_index_op (nargout, args); + octave_value fcn = symbol_table::find_function (name, args); + + if (fcn.is_defined ()) + retval = fcn.do_multi_index_op (nargout, args); + else + error ("feval: function `%s' not found", name.c_str ()); return retval; } @@ -3896,8 +3872,6 @@ switch_to_buffer (new_buf); - unwind_protect_ptr (curr_sym_tab); - do { reset_parser (); @@ -4048,14 +4022,20 @@ if (! error_state) { - unwind_protect::begin_frame ("Fassignin"); - - unwind_protect_ptr (curr_sym_tab); + symbol_table::scope_id scope = -1; if (context == "caller") - curr_sym_tab = curr_caller_sym_tab; + { + if (symbol_table::current_scope () == symbol_table::current_caller_scope ()) + { + error ("assignin: assignment in caller not implemented yet for direct recursion"); + return retval; + } + else + scope = symbol_table::current_caller_scope (); + } else if (context == "base") - curr_sym_tab = top_level_sym_tab; + scope = symbol_table::top_scope (); else error ("assignin: context must be \"caller\" or \"base\""); @@ -4066,27 +4046,13 @@ if (! error_state) { if (valid_identifier (nm)) - { - symbol_record *sr = curr_sym_tab->lookup (nm, true); - - if (sr) - { - tree_identifier *id = new tree_identifier (sr); - tree_constant *rhs = new tree_constant (args(2)); - - tree_simple_assignment tsa (id, rhs); - - tsa.rvalue (); - } - } + symbol_table::varref (nm, scope) = args(2); else error ("assignin: invalid variable name"); } else error ("assignin: expecting variable name as second argument"); } - - unwind_protect::run_frame ("Fassignin"); } else error ("assignin: expecting string as first argument"); @@ -4117,17 +4083,25 @@ { unwind_protect::begin_frame ("Fevalin"); - unwind_protect_ptr (curr_sym_tab); - if (context == "caller") - curr_sym_tab = curr_caller_sym_tab; + { + if (symbol_table::current_scope () == symbol_table::current_caller_scope ()) + { + error ("evalin: evaluation in caller not implemented yet for direct recursion"); + return retval; + } + else + symbol_table::push_scope (symbol_table::current_caller_scope ()); + } else if (context == "base") - curr_sym_tab = top_level_sym_tab; + symbol_table::push_scope (symbol_table::top_scope ()); else error ("evalin: context must be \"caller\" or \"base\""); if (! error_state) { + unwind_protect::add (symbol_table::pop_scope); + if (nargin > 2) { unwind_protect_int (buffer_error_messages); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-arg-list.cc --- a/src/pt-arg-list.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-arg-list.cc Fri Dec 28 20:56:58 2007 +0000 @@ -254,7 +254,7 @@ } tree_argument_list * -tree_argument_list::dup (symbol_table *sym_tab) +tree_argument_list::dup (symbol_table::scope_id scope) { tree_argument_list *new_list = new tree_argument_list (); @@ -265,7 +265,7 @@ { tree_expression *elt = *p; - new_list->append (elt ? elt->dup (sym_tab) : 0); + new_list->append (elt ? elt->dup (scope) : 0); } return new_list; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-arg-list.h --- a/src/pt-arg-list.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-arg-list.h Fri Dec 28 20:56:58 2007 +0000 @@ -78,7 +78,7 @@ string_vector get_arg_names (void) const; - tree_argument_list *dup (symbol_table *sym_tab); + tree_argument_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-assign.cc --- a/src/pt-assign.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-assign.cc Fri Dec 28 20:56:58 2007 +0000 @@ -279,11 +279,11 @@ } tree_expression * -tree_simple_assignment::dup (symbol_table *sym_tab) +tree_simple_assignment::dup (symbol_table::scope_id scope) { tree_simple_assignment *new_sa - = new tree_simple_assignment (lhs ? lhs->dup (sym_tab) : 0, - rhs ? rhs->dup (sym_tab) : 0, + = new tree_simple_assignment (lhs ? lhs->dup (scope) : 0, + rhs ? rhs->dup (scope) : 0, preserve, etype); new_sa->copy_base (*this); @@ -507,11 +507,11 @@ } tree_expression * -tree_multi_assignment::dup (symbol_table *sym_tab) +tree_multi_assignment::dup (symbol_table::scope_id scope) { tree_multi_assignment *new_ma - = new tree_multi_assignment (lhs ? lhs->dup (sym_tab) : 0, - rhs ? rhs->dup (sym_tab) : 0, + = new tree_multi_assignment (lhs ? lhs->dup (scope) : 0, + rhs ? rhs->dup (scope) : 0, preserve, etype); new_ma->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-assign.h --- a/src/pt-assign.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-assign.h Fri Dec 28 20:56:58 2007 +0000 @@ -36,6 +36,7 @@ #include "ov.h" #include "pt-exp.h" +#include "symtab.h" // Simple assignment expressions. @@ -72,7 +73,7 @@ tree_expression *right_hand_side (void) { return rhs; } - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -142,7 +143,7 @@ tree_expression *right_hand_side (void) { return rhs; } - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-binop.cc --- a/src/pt-binop.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-binop.cc Fri Dec 28 20:56:58 2007 +0000 @@ -106,11 +106,11 @@ } tree_expression * -tree_binary_expression::dup (symbol_table *sym_tab) +tree_binary_expression::dup (symbol_table::scope_id scope) { tree_binary_expression *new_be - = new tree_binary_expression (op_lhs ? op_lhs->dup (sym_tab) : 0, - op_rhs ? op_rhs->dup (sym_tab) : 0, + = new tree_binary_expression (op_lhs ? op_lhs->dup (scope) : 0, + op_rhs ? op_rhs->dup (scope) : 0, line (), column (), etype); new_be->copy_base (*this); @@ -233,11 +233,11 @@ } tree_expression * -tree_boolean_expression::dup (symbol_table *sym_tab) +tree_boolean_expression::dup (symbol_table::scope_id scope) { tree_boolean_expression *new_be - = new tree_boolean_expression (op_lhs ? op_lhs->dup (sym_tab) : 0, - op_rhs ? op_rhs->dup (sym_tab) : 0, + = new tree_boolean_expression (op_lhs ? op_lhs->dup (scope) : 0, + op_rhs ? op_rhs->dup (scope) : 0, line (), column (), etype); new_be->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-binop.h --- a/src/pt-binop.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-binop.h Fri Dec 28 20:56:58 2007 +0000 @@ -34,6 +34,7 @@ #include "ov.h" #include "pt-exp.h" +#include "symtab.h" // Binary expressions. @@ -82,7 +83,7 @@ tree_expression *lhs (void) { return op_lhs; } tree_expression *rhs (void) { return op_rhs; } - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -139,7 +140,7 @@ type op_type (void) const { return etype; } - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); private: diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-cell.cc --- a/src/pt-cell.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-cell.cc Fri Dec 28 20:56:58 2007 +0000 @@ -102,7 +102,7 @@ } tree_expression * -tree_cell::dup (symbol_table *sym_tab) +tree_cell::dup (symbol_table::scope_id scope) { tree_cell *new_cell = new tree_cell (0, line (), column ()); @@ -110,7 +110,7 @@ { tree_argument_list *elt = *p; - new_cell->append (elt ? elt->dup (sym_tab) : 0); + new_cell->append (elt ? elt->dup (scope) : 0); } new_cell->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-cell.h --- a/src/pt-cell.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-cell.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ class tree_walker; #include "pt-mat.h" +#include "symtab.h" // General cells. @@ -52,7 +53,7 @@ octave_value_list rvalue (int); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-cmd.cc --- a/src/pt-cmd.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-cmd.cc Fri Dec 28 20:56:58 2007 +0000 @@ -31,7 +31,7 @@ // No-op. tree_command * -tree_no_op_command::dup (symbol_table *sym_tab) +tree_no_op_command::dup (symbol_table::scope_id) { return new tree_no_op_command (orig_cmd, line (), column ()); } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-cmd.h --- a/src/pt-cmd.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-cmd.h Fri Dec 28 20:56:58 2007 +0000 @@ -27,10 +27,10 @@ #include class tree_walker; -class symbol_table; #include "pt.h" #include "pt-bp.h" +#include "symtab.h" // A base class for commands. @@ -46,7 +46,7 @@ virtual void eval (void) = 0; - virtual tree_command *dup (symbol_table *) = 0; + virtual tree_command *dup (symbol_table::scope_id) = 0; private: @@ -71,7 +71,7 @@ void eval (void) { MAYBE_DO_BREAKPOINT; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-colon.cc --- a/src/pt-colon.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-colon.cc Fri Dec 28 20:56:58 2007 +0000 @@ -210,12 +210,12 @@ } tree_expression * -tree_colon_expression::dup (symbol_table *sym_tab) +tree_colon_expression::dup (symbol_table::scope_id scope) { tree_colon_expression *new_ce - = new tree_colon_expression (op_base ? op_base->dup (sym_tab) : 0, - op_limit ? op_limit->dup (sym_tab) : 0, - op_increment ? op_increment->dup (sym_tab) : 0, + = new tree_colon_expression (op_base ? op_base->dup (scope) : 0, + op_limit ? op_limit->dup (scope) : 0, + op_increment ? op_increment->dup (scope) : 0, line (), column ()); new_ce->copy_base (*new_ce); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-colon.h --- a/src/pt-colon.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-colon.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ class octave_lvalue; #include "pt-exp.h" +#include "symtab.h" // Colon expressions. @@ -91,7 +92,7 @@ int line (void) const; int column (void) const; - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-const.cc --- a/src/pt-const.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-const.cc Fri Dec 28 20:56:58 2007 +0000 @@ -71,7 +71,7 @@ } tree_expression * -tree_constant::dup (symbol_table *) +tree_constant::dup (symbol_table::scope_id) { tree_constant *new_tc = new tree_constant (val, orig_text, line (), column ()); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-const.h --- a/src/pt-const.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-const.h Fri Dec 28 20:56:58 2007 +0000 @@ -29,14 +29,13 @@ #include "oct-alloc.h" -#include "pt-bp.h" -#include "pt-exp.h" - class octave_value_list; - class tree_walker; #include "ov.h" +#include "pt-bp.h" +#include "pt-exp.h" +#include "symtab.h" class tree_constant : public tree_expression @@ -83,7 +82,7 @@ octave_value_list rvalue (int nargout); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-decl.cc --- a/src/pt-decl.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-decl.cc Fri Dec 28 20:56:58 2007 +0000 @@ -69,10 +69,10 @@ } tree_decl_elt * -tree_decl_elt::dup (symbol_table *sym_tab) +tree_decl_elt::dup (symbol_table::scope_id scope) { - return new tree_decl_elt (id ? id->dup (sym_tab) : 0, - expr ? expr->dup (sym_tab) : 0); + return new tree_decl_elt (id ? id->dup (scope) : 0, + expr ? expr->dup (scope) : 0); } void @@ -98,7 +98,7 @@ } tree_decl_init_list * -tree_decl_init_list::dup (symbol_table *sym_tab) +tree_decl_init_list::dup (symbol_table::scope_id scope) { tree_decl_init_list *new_dil = new tree_decl_init_list (); @@ -106,7 +106,7 @@ { tree_decl_elt *elt = *p; - new_dil->append (elt ? elt->dup (sym_tab) : 0); + new_dil->append (elt ? elt->dup (scope) : 0); } return new_dil; @@ -140,7 +140,7 @@ if (id) { - id->link_to_global (); + id->mark_global (); if (! error_state) { @@ -169,11 +169,7 @@ MAYBE_DO_BREAKPOINT; if (init_list) - { - init_list->eval (do_init); - - initialized = true; - } + init_list->eval (do_init); if (error_state) ::error ("evaluating global command near line %d, column %d", @@ -181,9 +177,9 @@ } tree_command * -tree_global_command::dup (symbol_table *sym_tab) +tree_global_command::dup (symbol_table::scope_id scope) { - return new tree_global_command (init_list ? init_list->dup (sym_tab) : 0, + return new tree_global_command (init_list ? init_list->dup (scope) : 0, line (), column ()); } @@ -223,22 +219,18 @@ // Static variables only need to be marked and initialized once. - if (init_list && ! initialized) - { - init_list->eval (do_init); + if (init_list) + init_list->eval (do_init); - initialized = true; - - if (error_state) - ::error ("evaluating static command near line %d, column %d", - line (), column ()); - } + if (error_state) + ::error ("evaluating static command near line %d, column %d", + line (), column ()); } tree_command * -tree_static_command::dup (symbol_table *sym_tab) +tree_static_command::dup (symbol_table::scope_id scope) { - return new tree_static_command (init_list ? init_list->dup (sym_tab) : 0, + return new tree_static_command (init_list ? init_list->dup (scope) : 0, line (), column ()); } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-decl.h --- a/src/pt-decl.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-decl.h Fri Dec 28 20:56:58 2007 +0000 @@ -35,6 +35,7 @@ #include "oct-lvalue.h" #include "pt-cmd.h" #include "pt-id.h" +#include "symtab.h" // List of expressions that make up a declaration statement. @@ -54,6 +55,8 @@ bool is_defined (void) { return id ? id->is_defined () : false; } + bool is_variable (void) { return id ? id->is_variable () : false; } + void mark_as_formal_parameter (void) { if (id) @@ -75,7 +78,7 @@ tree_expression *expression (void) { return expr; } - tree_decl_elt *dup (symbol_table *sym_tab); + tree_decl_elt *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -115,7 +118,7 @@ void eval (tree_decl_elt::eval_fcn); - tree_decl_init_list *dup (symbol_table *sym_tab); + tree_decl_init_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -136,11 +139,11 @@ public: tree_decl_command (const std::string& n, int l = -1, int c = -1) - : tree_command (l, c), cmd_name (n), initialized (false), init_list (0) { } + : tree_command (l, c), cmd_name (n), init_list (0) { } tree_decl_command (const std::string& n, tree_decl_init_list *t, int l = -1, int c = -1) - : tree_command (l, c), cmd_name (n), initialized (false), init_list (t) { } + : tree_command (l, c), cmd_name (n), init_list (t) { } ~tree_decl_command (void); @@ -155,9 +158,6 @@ // The name of this command -- global, static, etc. std::string cmd_name; - // TRUE if this command has been evaluated. - bool initialized; - // The list of variables or initializers in this declaration command. tree_decl_init_list *init_list; @@ -187,7 +187,7 @@ void eval (void); - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); private: @@ -217,7 +217,7 @@ void eval (void); - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); private: diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-except.cc --- a/src/pt-except.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-except.cc Fri Dec 28 20:56:58 2007 +0000 @@ -127,10 +127,10 @@ } tree_command * -tree_try_catch_command::dup (symbol_table *sym_tab) +tree_try_catch_command::dup (symbol_table::scope_id scope) { - return new tree_try_catch_command (try_code ? try_code->dup (sym_tab) : 0, - catch_code ? catch_code->dup (sym_tab) : 0, + return new tree_try_catch_command (try_code ? try_code->dup (scope) : 0, + catch_code ? catch_code->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, mid_comm ? mid_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, @@ -243,11 +243,11 @@ } tree_command * -tree_unwind_protect_command::dup (symbol_table *sym_tab) +tree_unwind_protect_command::dup (symbol_table::scope_id scope) { return new tree_unwind_protect_command - (unwind_protect_code ? unwind_protect_code->dup (sym_tab) : 0, - cleanup_code ? cleanup_code->dup (sym_tab) : 0, + (unwind_protect_code ? unwind_protect_code->dup (scope) : 0, + cleanup_code ? cleanup_code->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, mid_comm ? mid_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-except.h --- a/src/pt-except.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-except.h Fri Dec 28 20:56:58 2007 +0000 @@ -30,6 +30,7 @@ #include "comment-list.h" #include "pt-cmd.h" +#include "symtab.h" // Simple exception handling. @@ -64,7 +65,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -126,7 +127,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-exp.h --- a/src/pt-exp.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-exp.h Fri Dec 28 20:56:58 2007 +0000 @@ -28,9 +28,9 @@ class octave_value; class octave_lvalue; -class symbol_table; #include "pt.h" +#include "symtab.h" // A base class for expressions. @@ -47,7 +47,7 @@ virtual bool has_magic_end (void) const = 0; - virtual tree_expression *dup (symbol_table *) = 0; + virtual tree_expression *dup (symbol_table::scope_id) = 0; virtual bool is_constant (void) const { return false; } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-fcn-handle.cc --- a/src/pt-fcn-handle.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-fcn-handle.cc Fri Dec 28 20:56:58 2007 +0000 @@ -71,7 +71,7 @@ } tree_expression * -tree_fcn_handle::dup (symbol_table *) +tree_fcn_handle::dup (symbol_table::scope_id) { tree_fcn_handle *new_fh = new tree_fcn_handle (nm, line (), column ()); @@ -91,28 +91,21 @@ { MAYBE_DO_BREAKPOINT; - tree_parameter_list *param_list = fcn.parameter_list (); - tree_parameter_list *ret_list = fcn.return_list (); - tree_statement_list *cmd_list = fcn.body (); - symbol_table *sym_tab = fcn.sym_tab (); - - symbol_table *new_sym_tab = sym_tab ? sym_tab->dup () : 0; + tree_parameter_list *param_list = parameter_list (); + tree_parameter_list *ret_list = return_list (); + tree_statement_list *cmd_list = body (); + symbol_table::scope_id this_scope = scope (); - if (new_sym_tab) - new_sym_tab->inherit (curr_sym_tab); - - tree_parameter_list *new_param_list - = param_list ? param_list->dup (new_sym_tab) : 0; + symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope); - tree_statement_list *new_cmd_list - = cmd_list ? cmd_list->dup (new_sym_tab) : 0; - - tree_parameter_list *new_ret_list - = ret_list ? ret_list->dup (new_sym_tab) : 0; + if (new_scope > 0) + symbol_table::inherit (new_scope, symbol_table::current_scope ()); octave_user_function *uf - = new octave_user_function (new_param_list, new_ret_list, - new_cmd_list, new_sym_tab); + = new octave_user_function (new_scope, + param_list ? param_list->dup (new_scope) : 0, + ret_list ? ret_list->dup (new_scope) : 0, + cmd_list ? cmd_list->dup (new_scope) : 0); octave_function *curr_fcn = octave_call_stack::current (); @@ -142,23 +135,23 @@ } tree_expression * -tree_anon_fcn_handle::dup (symbol_table *st) +tree_anon_fcn_handle::dup (symbol_table::scope_id parent_scope) { - tree_parameter_list *param_list = fcn.parameter_list (); - tree_parameter_list *ret_list = fcn.return_list (); - tree_statement_list *cmd_list = fcn.body (); - symbol_table *sym_tab = fcn.sym_tab (); + tree_parameter_list *param_list = parameter_list (); + tree_parameter_list *ret_list = return_list (); + tree_statement_list *cmd_list = body (); + symbol_table::scope_id this_scope = scope (); - symbol_table *new_sym_tab = sym_tab ? sym_tab->dup () : 0; + symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope); - if (new_sym_tab) - new_sym_tab->inherit (st); + if (new_scope > 0) + symbol_table::inherit (new_scope, parent_scope); tree_anon_fcn_handle *new_afh - = new tree_anon_fcn_handle (param_list ? param_list->dup (new_sym_tab) : 0, - ret_list ? ret_list->dup (new_sym_tab) : 0, - cmd_list ? cmd_list->dup (new_sym_tab) : 0, - new_sym_tab, line (), column ()); + = new tree_anon_fcn_handle (param_list ? param_list->dup (new_scope) : 0, + ret_list ? ret_list->dup (new_scope) : 0, + cmd_list ? cmd_list->dup (new_scope) : 0, + new_scope, line (), column ()); new_afh->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-fcn-handle.h --- a/src/pt-fcn-handle.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-fcn-handle.h Fri Dec 28 20:56:58 2007 +0000 @@ -30,6 +30,7 @@ #include "pt-exp.h" #include "pt-misc.h" #include "pt-stmt.h" +#include "symtab.h" class octave_value_list; @@ -37,6 +38,7 @@ #include "ov.h" #include "ov-usr-fcn.h" +#include "symtab.h" class tree_fcn_handle : public tree_expression @@ -67,7 +69,7 @@ octave_value_list rvalue (int nargout); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -89,14 +91,15 @@ public: tree_anon_fcn_handle (int l = -1, int c = -1) - : tree_expression (l, c), fcn () { } + : tree_expression (l, c), fcn (0) { } tree_anon_fcn_handle (tree_parameter_list *pl, tree_parameter_list *rl, - tree_statement_list *cl, symbol_table *st, + tree_statement_list *cl, symbol_table::scope_id sid, int l = -1, int c = -1) - : tree_expression (l, c), fcn (pl, rl, cl, st) { } + : tree_expression (l, c), + fcn (new octave_user_function (sid, pl, rl, cl)) { } - ~tree_anon_fcn_handle (void) { } + ~tree_anon_fcn_handle (void) { delete fcn; } bool has_magic_end (void) const { return false; } @@ -106,18 +109,28 @@ octave_value_list rvalue (int nargout); - tree_parameter_list *parameter_list (void) { return fcn.parameter_list (); } + tree_parameter_list *parameter_list (void) + { + return fcn ? fcn->parameter_list () : 0; + } - tree_statement_list *body (void) { return fcn.body (); } + tree_parameter_list *return_list (void) + { + return fcn ? fcn->return_list () : 0; + } - tree_expression *dup (symbol_table *sym_tab); + tree_statement_list *body (void) { return fcn ? fcn->body () : 0; } + + symbol_table::scope_id scope (void) { return fcn ? fcn->scope () : -1; } + + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); private: // The function. - octave_user_function fcn; + octave_user_function *fcn; // No copying! diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-id.cc --- a/src/pt-id.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-id.cc Fri Dec 28 20:56:58 2007 +0000 @@ -39,41 +39,6 @@ // Symbols from the symbol table. -std::string -tree_identifier::name (void) const -{ - std::string retval; - if (sym) - retval = sym->name (); - return retval; -} - -tree_identifier * -tree_identifier::define (octave_function *f, unsigned int sym_type) -{ - int status = sym->define (f, sym_type); - return status ? this : 0; -} - -void -tree_identifier::document (const std::string& s) -{ - if (sym) - sym->document (s); -} - -bool -tree_identifier::is_defined (void) -{ - return (sym && sym->is_defined ()); -} - -bool -tree_identifier::is_function (void) -{ - return (sym && sym->is_function ()); -} - void tree_identifier::eval_undefined_error (void) { @@ -87,65 +52,6 @@ name ().c_str (), l, c); } -// Try to find a definition for an identifier. Here's how: -// -// * If the identifier is already defined and is a function defined -// in an function file that has been modified since the last time -// we parsed it, parse it again. -// -// * If the identifier is not defined, try to find a builtin -// variable or an already compiled function with the same name. -// -// * If the identifier is still undefined, try looking for an -// function file to parse. -// -// * On systems that support dynamic linking, we prefer .oct files, -// then .mex files, then .m files. - -octave_value -tree_identifier::do_lookup (bool& script_file_executed, bool exec_script) -{ - static octave_value foo; - - script_file_executed = lookup (sym, exec_script); - - return script_file_executed ? foo : sym->def (); -} - -void -tree_identifier::link_to_global (void) -{ - if (sym) - { - if (! sym->is_linked_to_global ()) - { - if (sym->is_defined () && sym->is_variable ()) - { - std::string nm = sym->name (); - - warning ("value of local variable `%s' may have changed to match global", - nm.c_str ()); - } - - link_to_global_variable (sym); - } - } -} - -void -tree_identifier::mark_as_static (void) -{ - if (sym) - sym->mark_as_static (); -} - -void -tree_identifier::mark_as_formal_parameter (void) -{ - if (sym) - sym->mark_as_formal_parameter (); -} - octave_value_list tree_identifier::rvalue (int nargout) { @@ -156,42 +62,41 @@ if (error_state) return retval; - bool script_file_executed = false; + octave_value_list evaluated_args; + bool args_evaluated; - octave_value val = do_lookup (script_file_executed); + octave_value val = sym.find (0, string_vector (), evaluated_args, + args_evaluated); - if (! script_file_executed) + if (val.is_defined ()) { - if (val.is_defined ()) + // GAGME -- this would be cleaner if we required + // parens to indicate function calls. + // + // 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. + + if (val.is_function () && ! is_postfix_indexed ()) { - // GAGME -- this would be cleaner if we required - // parens to indicate function calls. - // - // 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. + octave_value_list tmp_args; - if (val.is_function () && ! is_postfix_indexed ()) - { - octave_value_list tmp_args; - - retval = val.do_multi_index_op (nargout, tmp_args); - } - else - { - if (print_result () && nargout == 0) - val.print_with_name (octave_stdout, name ()); - - retval = val; - } + retval = val.do_multi_index_op (nargout, tmp_args); } else - eval_undefined_error (); + { + if (print_result () && nargout == 0) + val.print_with_name (octave_stdout, name ()); + + retval = val; + } } + else + eval_undefined_error (); return retval; } @@ -214,15 +119,21 @@ { MAYBE_DO_BREAKPOINT; - return sym->variable_reference (); + return octave_lvalue (&(sym.varref ())); } tree_identifier * -tree_identifier::dup (symbol_table *sym_tab) +tree_identifier::dup (symbol_table::scope_id scope) { - symbol_record *sr = (sym_tab && sym) ? sym_tab->lookup (sym->name ()) : 0; + // The new tree_identifier object contains a symbol_record + // entry from the duplicated scope. - tree_identifier *new_id = new tree_identifier (sr, line (), column ()); + // FIXME -- is this the best way? + symbol_table::symbol_record new_sym + = symbol_table::find_symbol (sym.name (), scope); + + tree_identifier *new_id + = new tree_identifier (new_sym, line (), column ()); new_id->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-id.h --- a/src/pt-id.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-id.h Fri Dec 28 20:56:58 2007 +0000 @@ -30,11 +30,11 @@ class octave_value; class octave_value_list; class octave_function; -class symbol_record; class tree_walker; #include "pt-exp.h" +#include "symtab.h" // Symbols from the symbol table. @@ -46,9 +46,9 @@ public: tree_identifier (int l = -1, int c = -1) - : tree_expression (l, c), sym (0) { } + : tree_expression (l, c), sym () { } - tree_identifier (symbol_record *s, int l = -1, int c = -1) + tree_identifier (const symbol_table::symbol_record& s, int l = -1, int c = -1) : tree_expression (l, c), sym (s) { } ~tree_identifier (void) { } @@ -57,24 +57,48 @@ bool is_identifier (void) const { return true; } - std::string name (void) const; + std::string name (void) const { return sym.name (); } - tree_identifier *define (octave_function *f, unsigned int sym_type); + bool is_defined (void) { return sym.is_defined (); } + + bool is_variable (void) { return sym.is_variable (); } - void document (const std::string& s); - - bool is_defined (void); - - bool is_function (void); + // Try to find a definition for an identifier. Here's how: + // + // * If the identifier is already defined and is a function defined + // in an function file that has been modified since the last time + // we parsed it, parse it again. + // + // * If the identifier is not defined, try to find a builtin + // variable or an already compiled function with the same name. + // + // * If the identifier is still undefined, try looking for an + // function file to parse. + // + // * On systems that support dynamic linking, we prefer .oct files, + // then .mex files, then .m files. octave_value - do_lookup (bool& script_file_executed, bool exec_script = true); - - void link_to_global (void); + do_lookup (bool& script_file_executed, bool exec_script = true) + { + // FIXME -- SYMTAB: what about executing script files? + octave_value_list evaluated_args; + bool args_evaluated; + return sym.find (0, string_vector (), evaluated_args, args_evaluated); + } - void mark_as_static (void); + octave_value + do_lookup (tree_argument_list *args, const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated) + { + return sym.find (args, arg_names, evaluated_args, args_evaluated); + } - void mark_as_formal_parameter (void); + void mark_global (void) { sym.mark_global (); } + + void mark_as_static (void) { sym.init_persistent (); } + + void mark_as_formal_parameter (void) { sym.mark_formal (); } // We really need to know whether this symbol referst to a variable // or a function, but we may not know that yet. @@ -89,14 +113,14 @@ void eval_undefined_error (void); - tree_identifier *dup (symbol_table *sym_tab); + tree_identifier *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); private: // The symbol record that this identifier references. - symbol_record *sym; + symbol_table::symbol_record sym; // No copying! diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-idx.cc --- a/src/pt-idx.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-idx.cc Fri Dec 28 20:56:58 2007 +0000 @@ -34,6 +34,7 @@ #include "pager.h" #include "pt-arg-list.h" #include "pt-bp.h" +#include "pt-id.h" #include "pt-idx.h" #include "pt-walk.h" #include "utils.h" @@ -219,9 +220,8 @@ { int n = args.size (); - // FIXME -- why not just make these Cell objects? - octave_value_list subs_list (n, octave_value ()); - octave_value_list type_list (n, octave_value ()); + Cell type_field (n, 1); + Cell subs_field (n, 1); std::list::const_iterator p_args = args.begin (); std::list::const_iterator p_arg_nm = arg_nm.begin (); @@ -234,16 +234,16 @@ switch (type[i]) { case '(': - subs_list(i) = make_subs_cell (*p_args, *p_arg_nm); + subs_field(i) = make_subs_cell (*p_args, *p_arg_nm); break; case '{': - subs_list(i) = make_subs_cell (*p_args, *p_arg_nm); + subs_field(i) = make_subs_cell (*p_args, *p_arg_nm); break; case '.': { - subs_list(i) = get_struct_index (p_arg_nm, p_dyn_field); + subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field); if (error_state) eval_error (); @@ -262,8 +262,8 @@ p_dyn_field++; } - m.assign ("subs", Cell (subs_list)); - m.assign ("type", Cell (type_list)); + m.assign ("type", type_field); + m.assign ("subs", subs_field); return m; } @@ -276,11 +276,38 @@ if (error_state) return retval; - octave_value first_expr_val = expr->rvalue (); - octave_value tmp = first_expr_val; + octave_value first_expr_val; + + octave_value_list first_args; + + bool have_args = false; + + if (expr->is_identifier () && type[0] == '(') + { + tree_identifier *id = dynamic_cast (expr); + + if (! (id->is_variable () || args.empty ())) + { + tree_argument_list *al = *(args.begin ()); + + size_t n = al ? al->length () : 0; + + if (n > 0) + { + string_vector anm = *(arg_nm.begin ()); + + first_expr_val = id->do_lookup (al, anm, first_args, have_args); + } + } + } if (! error_state) { + if (first_expr_val.is_undefined ()) + first_expr_val = expr->rvalue (); + + octave_value tmp = first_expr_val; + std::list idx; int n = args.size (); @@ -304,11 +331,11 @@ // and we are looking at the argument list that // contains the second (or third, etc.) "end" token, // so we must evaluate everything up to the point of - // that argument list so we pass the appropiate + // that argument list so we can pass the appropriate // value to the built-in __end__ function. octave_value_list tmp_list - = first_expr_val.subsref (type, idx, nargout); + = first_expr_val.subsref (type.substr (0, i), idx, nargout); tmp = tmp_list(0); @@ -320,7 +347,13 @@ switch (type[i]) { case '(': - idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp)); + if (have_args) + { + idx.push_back (first_args); + have_args = false; + } + else + idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp)); break; case '{': @@ -415,11 +448,11 @@ // and we are looking at the argument list that // contains the second (or third, etc.) "end" token, // so we must evaluate everything up to the point of - // that argument list so we pass the appropiate + // that argument list so we pass the appropriate // value to the built-in __end__ function. octave_value_list tmp_list - = first_retval_object.subsref (type, idx, 1); + = first_retval_object.subsref (type.substr (0, i), idx, 1); tmp = tmp_list(0); @@ -656,12 +689,12 @@ } tree_index_expression * -tree_index_expression::dup (symbol_table *sym_tab) +tree_index_expression::dup (symbol_table::scope_id scope) { tree_index_expression *new_idx_expr = new tree_index_expression (line (), column ()); - new_idx_expr->expr = expr ? expr->dup (sym_tab) : 0; + new_idx_expr->expr = expr ? expr->dup (scope) : 0; std::list new_args; @@ -671,7 +704,7 @@ { tree_argument_list *elt = *p; - new_args.push_back (elt ? elt->dup (sym_tab) : 0); + new_args.push_back (elt ? elt->dup (scope) : 0); } new_idx_expr->args = new_args; @@ -688,7 +721,7 @@ { tree_expression *elt = *p; - new_dyn_field.push_back (elt ? elt->dup (sym_tab) : 0); + new_dyn_field.push_back (elt ? elt->dup (scope) : 0); } new_idx_expr->dyn_field = new_dyn_field; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-idx.h --- a/src/pt-idx.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-idx.h Fri Dec 28 20:56:58 2007 +0000 @@ -38,6 +38,7 @@ #include "str-vec.h" #include "pt-exp.h" +#include "symtab.h" // Index expressions. @@ -89,7 +90,7 @@ void eval_error (void) const; - tree_index_expression *dup (symbol_table *sym_tab); + tree_index_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-jump.cc --- a/src/pt-jump.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-jump.cc Fri Dec 28 20:56:58 2007 +0000 @@ -49,7 +49,7 @@ } tree_command * -tree_break_command::dup (symbol_table *) +tree_break_command::dup (symbol_table::scope_id) { return new tree_break_command (line (), column ()); } @@ -75,7 +75,7 @@ } tree_command * -tree_continue_command::dup (symbol_table *) +tree_continue_command::dup (symbol_table::scope_id) { return new tree_continue_command (line (), column ()); } @@ -101,7 +101,7 @@ } tree_command * -tree_return_command::dup (symbol_table *) +tree_return_command::dup (symbol_table::scope_id) { return new tree_return_command (line (), column ()); } diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-jump.h --- a/src/pt-jump.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-jump.h Fri Dec 28 20:56:58 2007 +0000 @@ -26,6 +26,7 @@ class tree_walker; #include "pt-cmd.h" +#include "symtab.h" // Break. @@ -41,7 +42,7 @@ void eval (void); - tree_command *dup (symbol_table *); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -70,7 +71,7 @@ void eval (void); - tree_command *dup (symbol_table *); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -99,7 +100,7 @@ void eval (void); - tree_command *dup (symbol_table *); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-loop.cc --- a/src/pt-loop.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-loop.cc Fri Dec 28 20:56:58 2007 +0000 @@ -126,10 +126,10 @@ } tree_command * -tree_while_command::dup (symbol_table *sym_tab) +tree_while_command::dup (symbol_table::scope_id scope) { - return new tree_while_command (expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_while_command (expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup (): 0, line (), column ()); @@ -189,10 +189,10 @@ } tree_command * -tree_do_until_command::dup (symbol_table *sym_tab) +tree_do_until_command::dup (symbol_table::scope_id scope) { - return new tree_do_until_command (expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_do_until_command (expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup (): 0, line (), column ()); @@ -487,11 +487,11 @@ } tree_command * -tree_simple_for_command::dup (symbol_table *sym_tab) +tree_simple_for_command::dup (symbol_table::scope_id scope) { - return new tree_simple_for_command (lhs ? lhs->dup (sym_tab) : 0, - expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_simple_for_command (lhs ? lhs->dup (scope) : 0, + expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, line (), column ()); @@ -608,11 +608,11 @@ } tree_command * -tree_complex_for_command::dup (symbol_table *sym_tab) +tree_complex_for_command::dup (symbol_table::scope_id scope) { - return new tree_complex_for_command (lhs ? lhs->dup (sym_tab) : 0, - expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_complex_for_command (lhs ? lhs->dup (scope) : 0, + expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, line (), column ()); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-loop.h --- a/src/pt-loop.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-loop.h Fri Dec 28 20:56:58 2007 +0000 @@ -35,6 +35,7 @@ #include "comment-list.h" #include "pt-cmd.h" +#include "symtab.h" // TRUE means we are evaluating some kind of looping construct. extern bool evaluating_looping_command; @@ -78,7 +79,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -133,7 +134,7 @@ void eval_error (void); - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -181,7 +182,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -245,7 +246,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-mat.cc --- a/src/pt-mat.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-mat.cc Fri Dec 28 20:56:58 2007 +0000 @@ -951,7 +951,7 @@ } tree_expression * -tree_matrix::dup (symbol_table *sym_tab) +tree_matrix::dup (symbol_table::scope_id scope) { tree_matrix *new_matrix = new tree_matrix (0, line (), column ()); @@ -959,7 +959,7 @@ { tree_argument_list *elt = *p; - new_matrix->append (elt ? elt->dup (sym_tab) : 0); + new_matrix->append (elt ? elt->dup (scope) : 0); } new_matrix->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-mat.h --- a/src/pt-mat.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-mat.h Fri Dec 28 20:56:58 2007 +0000 @@ -34,6 +34,7 @@ #include "base-list.h" #include "pt-exp.h" +#include "symtab.h" // General matrices. This allows us to construct matrices from // other matrices, variables, and functions. @@ -63,7 +64,7 @@ octave_value_list rvalue (int nargout); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-misc.cc --- a/src/pt-misc.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-misc.cc Fri Dec 28 20:56:58 2007 +0000 @@ -75,7 +75,7 @@ tree_decl_elt *elt = *p; - if (! elt->is_defined ()) + if (! elt->is_variable ()) { if (! warned) { @@ -177,7 +177,7 @@ { tree_decl_elt *elt = *p; - if (! elt->is_defined ()) + if (! elt->is_variable ()) { status = false; break; @@ -188,7 +188,7 @@ } tree_parameter_list * -tree_parameter_list::dup (symbol_table *sym_tab) +tree_parameter_list::dup (symbol_table::scope_id scope) { tree_parameter_list *new_list = new tree_parameter_list (); @@ -199,7 +199,7 @@ { tree_decl_elt *elt = *p; - new_list->append (elt->dup (sym_tab)); + new_list->append (elt->dup (scope)); } return new_list; @@ -224,7 +224,7 @@ } tree_return_list * -tree_return_list::dup (symbol_table *sym_tab) +tree_return_list::dup (symbol_table::scope_id scope) { tree_return_list *new_list = new tree_return_list (); @@ -232,7 +232,7 @@ { tree_index_expression *elt = *p; - new_list->append (elt->dup (sym_tab)); + new_list->append (elt->dup (scope)); } return new_list; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-misc.h --- a/src/pt-misc.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-misc.h Fri Dec 28 20:56:58 2007 +0000 @@ -37,6 +37,7 @@ #include "base-list.h" #include "pt-decl.h" +#include "symtab.h" // Parameter lists. Used to hold the list of input and output // parameters in a function definition. Elements are identifiers @@ -76,7 +77,7 @@ octave_value_list convert_to_const_vector (const Cell& varargout); - tree_parameter_list *dup (symbol_table *sym_tab); + tree_parameter_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -105,7 +106,7 @@ ~tree_return_list (void); - tree_return_list *dup (symbol_table *sym_tab); + tree_return_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-select.cc --- a/src/pt-select.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-select.cc Fri Dec 28 20:56:58 2007 +0000 @@ -60,10 +60,10 @@ } tree_if_clause * -tree_if_clause::dup (symbol_table *sym_tab) +tree_if_clause::dup (symbol_table::scope_id scope) { - return new tree_if_clause (expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_if_clause (expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0); } @@ -88,7 +88,7 @@ } tree_if_command_list * -tree_if_command_list::dup (symbol_table *sym_tab) +tree_if_command_list::dup (symbol_table::scope_id scope) { tree_if_command_list *new_icl = new tree_if_command_list (); @@ -96,7 +96,7 @@ { tree_if_clause *elt = *p; - new_icl->append (elt ? elt->dup (sym_tab) : 0); + new_icl->append (elt ? elt->dup (scope) : 0); } return new_icl; @@ -129,9 +129,9 @@ } tree_command * -tree_if_command::dup (symbol_table *sym_tab) +tree_if_command::dup (symbol_table::scope_id scope) { - return new tree_if_command (list ? list->dup (sym_tab) : 0, + return new tree_if_command (list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, line (), column ()); @@ -243,10 +243,10 @@ } tree_switch_case * -tree_switch_case::dup (symbol_table *sym_tab) +tree_switch_case::dup (symbol_table::scope_id scope) { - return new tree_switch_case (label ? label->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_switch_case (label ? label->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0); } @@ -271,7 +271,7 @@ } tree_switch_case_list * -tree_switch_case_list::dup (symbol_table *sym_tab) +tree_switch_case_list::dup (symbol_table::scope_id scope) { tree_switch_case_list *new_scl = new tree_switch_case_list (); @@ -279,7 +279,7 @@ { tree_switch_case *elt = *p; - new_scl->append (elt ? elt->dup (sym_tab) : 0); + new_scl->append (elt ? elt->dup (scope) : 0); } return new_scl; @@ -332,10 +332,10 @@ } tree_command * -tree_switch_command::dup (symbol_table *sym_tab) +tree_switch_command::dup (symbol_table::scope_id scope) { - return new tree_switch_command (expr ? expr->dup (sym_tab) : 0, - list ? list->dup (sym_tab) : 0, + return new tree_switch_command (expr ? expr->dup (scope) : 0, + list ? list->dup (scope) : 0, lead_comm ? lead_comm->dup () : 0, trail_comm ? trail_comm->dup () : 0, line (), column ()); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-select.h --- a/src/pt-select.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-select.h Fri Dec 28 20:56:58 2007 +0000 @@ -32,6 +32,7 @@ #include "base-list.h" #include "comment-list.h" #include "pt-cmd.h" +#include "symtab.h" // If. @@ -63,7 +64,7 @@ octave_comment_list *leading_comment (void) { return lead_comm; } - tree_if_clause *dup (symbol_table *sym_tab); + tree_if_clause *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -106,7 +107,7 @@ void eval (void); - tree_if_command_list *dup (symbol_table *sym_tab); + tree_if_command_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -141,7 +142,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -196,7 +197,7 @@ octave_comment_list *leading_comment (void) { return lead_comm; } - tree_switch_case *dup (symbol_table *sym_tab); + tree_switch_case *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -239,7 +240,7 @@ void eval (const octave_value& val); - tree_switch_case_list *dup (symbol_table *sym_tab); + tree_switch_case_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -281,7 +282,7 @@ octave_comment_list *trailing_comment (void) { return trail_comm; } - tree_command *dup (symbol_table *sym_tab); + tree_command *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-stmt.cc --- a/src/pt-stmt.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-stmt.cc Fri Dec 28 20:56:58 2007 +0000 @@ -115,26 +115,19 @@ bool do_bind_ans = false; - bool script_file_executed = false; - if (expr->is_identifier ()) { tree_identifier *id = dynamic_cast (expr); - id->do_lookup (script_file_executed, true); - - do_bind_ans = id->is_function (); + do_bind_ans = (! id->is_variable ()); } else do_bind_ans = (! expr->is_assignment_expression ()); - if (! script_file_executed) - { - retval = expr->rvalue (nargout); + retval = expr->rvalue (nargout); - if (do_bind_ans && ! (error_state || retval.empty ())) - bind_ans (retval(0), pf); - } + if (do_bind_ans && ! (error_state || retval.empty ())) + bind_ans (retval(0), pf); } unwind_protect::run (); @@ -144,13 +137,13 @@ } tree_statement * -tree_statement::dup (symbol_table *sym_tab) +tree_statement::dup (symbol_table::scope_id scope) { tree_statement *new_stmt = new tree_statement (); - new_stmt->cmd = cmd ? cmd->dup (sym_tab) : 0; + new_stmt->cmd = cmd ? cmd->dup (scope) : 0; - new_stmt->expr = expr ? expr->dup (sym_tab) : 0; + new_stmt->expr = expr ? expr->dup (scope) : 0; new_stmt->comm = comm ? comm->dup () : 0; @@ -268,7 +261,7 @@ } tree_statement_list * -tree_statement_list::dup (symbol_table *sym_tab) +tree_statement_list::dup (symbol_table::scope_id scope) { tree_statement_list *new_list = new tree_statement_list (); @@ -278,7 +271,7 @@ { tree_statement *elt = *p; - new_list->append (elt ? elt->dup (sym_tab) : 0); + new_list->append (elt ? elt->dup (scope) : 0); } return new_list; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-stmt.h --- a/src/pt-stmt.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-stmt.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ #include "base-list.h" #include "comment-list.h" +#include "symtab.h" // A statement is either a command to execute or an expression to // evaluate. @@ -82,7 +83,7 @@ void set_expression (tree_expression *e) { expr = e; } - tree_statement *dup (symbol_table *sym_tab); + tree_statement *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -141,7 +142,7 @@ octave_value_list list_breakpoints (void); - tree_statement_list *dup (symbol_table *sym_tab); + tree_statement_list *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-unop.cc --- a/src/pt-unop.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-unop.cc Fri Dec 28 20:56:58 2007 +0000 @@ -121,10 +121,10 @@ } tree_expression * -tree_prefix_expression::dup (symbol_table *sym_tab) +tree_prefix_expression::dup (symbol_table::scope_id scope) { tree_prefix_expression *new_pe - = new tree_prefix_expression (op ? op->dup (sym_tab) : 0, + = new tree_prefix_expression (op ? op->dup (scope) : 0, line (), column (), etype); new_pe->copy_base (*this); @@ -218,10 +218,10 @@ } tree_expression * -tree_postfix_expression::dup (symbol_table *sym_tab) +tree_postfix_expression::dup (symbol_table::scope_id scope) { tree_postfix_expression *new_pe - = new tree_postfix_expression (op ? op->dup (sym_tab) : 0, + = new tree_postfix_expression (op ? op->dup (scope) : 0, line (), column (), etype); new_pe->copy_base (*this); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/pt-unop.h --- a/src/pt-unop.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/pt-unop.h Fri Dec 28 20:56:58 2007 +0000 @@ -33,6 +33,7 @@ class octave_lvalue; #include "pt-exp.h" +#include "symtab.h" // Unary expressions. @@ -103,7 +104,7 @@ void eval_error (void); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); @@ -141,7 +142,7 @@ void eval_error (void); - tree_expression *dup (symbol_table *sym_tab); + tree_expression *dup (symbol_table::scope_id scope); void accept (tree_walker& tw); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/symtab.cc --- a/src/symtab.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/symtab.cc Fri Dec 28 20:56:58 2007 +0000 @@ -2,7 +2,7 @@ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 John W. Eaton - + This file is part of Octave. Octave is free software; you can redistribute it and/or modify it @@ -25,1066 +25,167 @@ #include #endif -#include -#include -#include -#include - -#include -#include -#include - -#include "glob-match.h" -#include "str-vec.h" +#include "oct-env.h" +#include "oct-time.h" +#include "file-ops.h" +#include "file-stat.h" #include "defun.h" -#include "error.h" -#include "oct-lvalue.h" -#include "ov.h" -#include "pt-pr-code.h" +#include "dirfns.h" +#include "input.h" +#include "load-path.h" #include "symtab.h" +#include "ov-fcn.h" +#include "pager.h" +#include "parse.h" +#include "pt-arg-list.h" +#include "toplev.h" +#include "unwind-prot.h" #include "utils.h" -#include "variables.h" -#include "ov-usr-fcn.h" -#include "toplev.h" + +symbol_table *symbol_table::instance = 0; -#include "gripes.h" -#include "lo-mappers.h" +std::map symbol_table::all_instances; -#include "parse.h" +std::map symbol_table::fcn_table; -unsigned long int symbol_table::symtab_count = 0; +const symbol_table::scope_id symbol_table::xglobal_scope = 0; +const symbol_table::scope_id symbol_table::xtop_scope = 1; -// Should variables be allowed to hide functions of the same name? A -// positive value means yes. A negative value means yes, but print a -// warning message. Zero means it should be considered an error. -static int Vvariables_can_hide_functions = 1; +symbol_table::scope_id symbol_table::xcurrent_scope = 1; +symbol_table::scope_id symbol_table::xcurrent_caller_scope = -1; -// Nonzero means we print debugging info about symbol table lookups. -static bool Vdebug_symtab_lookups = false; +symbol_table::scope_id symbol_table::xparent_scope = -1; + +std::deque symbol_table::scope_stack; -// Defines layout for the whos/who -long command -std::string Vwhos_line_format - = " %p:4; %ln:6; %cs:16:6:8:1; %rb:12; %lc:-1;\n"; - -octave_allocator -symbol_record::symbol_def::allocator (sizeof (symbol_record::symbol_def)); +symbol_table::scope_id symbol_table::next_available_scope = 2; +std::set symbol_table::scope_ids_in_use; +std::set symbol_table::scope_ids_free_list; -#define SYMBOL_DEF symbol_record::symbol_def - -std::string -SYMBOL_DEF::type_as_string (void) const -{ - std::string retval = ""; +// Should Octave always check to see if function files have changed +// since they were last compiled? +static int Vignore_function_time_stamp = 1; - if (is_user_variable ()) - retval = "user-defined variable"; - else if (is_command ()) - retval = "built-in command"; - else if (is_mapper_function ()) - retval = "built-in mapper function"; - else if (is_user_function ()) - retval = "user-defined function"; - else if (is_builtin_function ()) - retval = "built-in function"; - else if (is_dld_function ()) - retval = "dynamically-linked function"; - else if (is_mex_function ()) - retval = "dynamically-linked mex function"; +octave_value +symbol_table::symbol_record::find (tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, + bool& args_evaluated) const +{ + octave_value retval; - return retval; + if (is_global ()) + return symbol_table::varref (name (), symbol_table::xglobal_scope); + else + { + octave_value val = varval (); + + if (val.is_defined ()) + return val; + } + + return symbol_table::find_function (name (), args, arg_names, + evaluated_args, args_evaluated); } -void -SYMBOL_DEF::type (std::ostream& os, const std::string& name, bool pr_type_info, - bool quiet, bool pr_orig_txt) -{ - if (is_user_function ()) - { - octave_function *defn = definition.function_value (); - - std::string fn = defn ? defn->fcn_file_name () : std::string (); - - if (pr_orig_txt && ! fn.empty ()) - { - std::ifstream fs (fn.c_str (), std::ios::in); - - if (fs) - { - if (pr_type_info && ! quiet) - os << name << " is the " << type_as_string () - << " defined from: " << fn << "\n\n"; - - char ch; - - while (fs.get (ch)) - os << ch; - } - else - os << "unable to open `" << fn << "' for reading!\n"; - } - else - { - if (pr_type_info && ! quiet) - os << name << " is a " << type_as_string () << ":\n\n"; - - tree_print_code tpc (os, "", pr_orig_txt); - - defn->accept (tpc); - } - } - else if (is_user_variable ()) - { - if (pr_type_info && ! quiet) - os << name << " is a " << type_as_string () << "\n"; - - definition.print_raw (os, true); - - if (pr_type_info) - os << "\n"; - } - else - os << name << " is a " << type_as_string () << "\n"; -} - -std::string -SYMBOL_DEF::which (const std::string& name) -{ - std::string retval; - - if (is_user_function () || is_dld_function () || is_mex_function ()) - { - octave_function *defn = definition.function_value (); - - if (defn) - retval = defn->fcn_file_name (); - } - else - retval = name + " is a " + type_as_string (); +// 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 +// need to check to see whether the file has changed since the the +// function was loaded/parsed. However, this check should only +// happen once per prompt (for files found from relative path +// elements, we also check if the working directory has changed +// since the last time the function was loaded/parsed). +// +// FIXME -- perhaps this should be done for all loaded functions when +// the prompt is printed or the directory has changed, and then we +// would not check for it when finding symbol definitions. - return retval; -} - -void -SYMBOL_DEF::which (std::ostream& os, const std::string& name) -{ - os << name; - - if (is_user_function () || is_dld_function () || is_mex_function ()) - { - octave_function *defn = definition.function_value (); - - std::string fn = defn ? defn->fcn_file_name () : std::string (); - - if (! fn.empty ()) - { - os << " is the " << type_as_string () << " from the file\n" - << fn << "\n"; - - return; - } - } - - os << " is a " << type_as_string () << "\n"; -} - -void -SYMBOL_DEF::document (const std::string& h) -{ - help_string = h; - - if (is_function ()) - { - octave_function *defn = definition.function_value (); - - if (defn) - defn->document (h); - } -} - - -void -SYMBOL_DEF::print_info (std::ostream& os, const std::string& prefix) const -{ - os << prefix << "symbol_def::count: " << count << "\n"; - - definition.print_info (os, prefix + " "); -} - -// Individual records in a symbol table. - -void -symbol_record::rename (const std::string& new_name) -{ - if (! read_only_error ("rename")) - nm = new_name; -} - -void -symbol_record::define (const octave_value& v, unsigned int sym_type) -{ - if (! (is_variable () && read_only_error ("redefine"))) - definition->define (v, sym_type); -} - -bool -symbol_record::define (octave_function *f, unsigned int sym_type) +static inline bool +out_of_date_check_internal (octave_value& function) { bool retval = false; - if (! read_only_error ("redefine")) - { - maybe_delete_def (); - - octave_value tmp (f); - - definition = new symbol_def (tmp, sym_type); - - retval = true; - } - - return retval; -} - -void -symbol_record::clear (void) -{ - if (is_defined ()) - { - if (! (tagged_static || is_eternal ())) - { - while (! aliases_to_clear.empty ()) - { - symbol_record *sr = aliases_to_clear.top (); - aliases_to_clear.pop (); - sr->clear (); - } - - maybe_delete_def (); - - definition = new symbol_def (); - } - - if (linked_to_global) - linked_to_global = 0; - } -} - -void -symbol_record::alias (symbol_record *s, bool mark_to_clear) -{ - chg_fcn = s->chg_fcn; - - maybe_delete_def (); - - if (mark_to_clear) - s->push_alias_to_clear (this); - - definition = s->definition; - - definition->count++; -} - -void -symbol_record::mark_as_formal_parameter (void) -{ - if (is_linked_to_global ()) - error ("can't mark global variable `%s' as function parameter", - nm.c_str ()); - else if (is_static ()) - error ("can't mark static variable `%s' as function parameter", - nm.c_str ()); - else - formal_param = 1; -} - -void -symbol_record::mark_as_automatic_variable (void) -{ - if (is_linked_to_global ()) - error ("can't mark global variable `%s' as automatic variable", - nm.c_str ()); - else if (is_static ()) - error ("can't mark static variable `%s' as automatic variable", - nm.c_str ()); - else - automatic_variable = 1; -} + octave_function *fcn = function.function_value (true); -void -symbol_record::mark_as_linked_to_global (void) -{ - if (is_formal_parameter ()) - error ("can't make function parameter `%s' global", nm.c_str ()); - else if (is_static ()) - error ("can't make static variable `%s' global", nm.c_str ()); - else - linked_to_global = 1; -} - -void -symbol_record::mark_as_static (void) -{ - if (is_linked_to_global ()) - error ("can't make global variable `%s' static", nm.c_str ()); - else if (is_formal_parameter ()) - error ("can't make formal parameter `%s' static", nm.c_str ()); - else - tagged_static = 1; -} - -octave_value& -symbol_record::variable_value (void) -{ - static octave_value foo; - - return is_variable () ? def () : foo; -} - -octave_lvalue -symbol_record::variable_reference (void) -{ - if ((Vvariables_can_hide_functions <= 0 || ! can_hide_function) - && (is_function () - || (! is_defined () && is_valid_function (nm)))) - { - if (Vvariables_can_hide_functions < 0 && can_hide_function) - warning ("variable `%s' hides function", nm.c_str ()); - else - { - error ("variable `%s' hides function", nm.c_str ()); - return octave_lvalue (); - } - } - - if (is_function ()) - clear (); - - if (! is_defined ()) - { - octave_value tmp; - define (tmp); - } - - return octave_lvalue (&(def ()), chg_fcn); -} - -void -symbol_record::push_context (void) -{ - if (! is_static ()) - { - context.push (definition); - - definition = new symbol_def (); - - global_link_context.push (static_cast (linked_to_global)); - - linked_to_global = 0; - } -} - -void -symbol_record::pop_context (void) -{ - // It is possible for context to be empty if new symbols have been - // inserted in the symbol table during recursive calls. This can - // happen as a result of calls to eval() and feval(). - - if (! context.empty ()) + if (fcn) { - maybe_delete_def (); - - definition = context.top (); - context.pop (); - - linked_to_global = global_link_context.top (); - global_link_context.pop (); - } -} - -// Calculate how much space needs to be reserved for the first part of -// the dimensions string. For example, -// -// mat is a 12x3 matrix -// ^^ => 2 columns + // FIXME -- we need to handle nested functions properly here. -int -symbol_record::dimensions_string_req_first_space (int print_dims) const -{ - int first_param_space = 0; - - // Calculating dimensions. - - std::string dim_str = ""; - std::stringstream ss; - dim_vector dimensions = dims (); - long dim = dimensions.length (); - - first_param_space = (first_param_space >= 1 ? first_param_space : 1); - - // Preparing dimension string. - - if ((dim <= print_dims || print_dims < 0) && print_dims != 0) - { - // Dimensions string must be printed like this: 2x3x4x2. + if (! fcn->is_nested_function ()) + { + std::string ff = fcn->fcn_file_name (); - if (dim == 0 || dim == 1) - first_param_space = 1; // First parameter is 1. - else - { - ss << dimensions (0); - - dim_str = ss.str (); - first_param_space = dim_str.length (); - } - } - else - { - // Printing dimension string as: a-D. - - ss << dim; - - dim_str = ss.str (); - first_param_space = dim_str.length (); - } + if (! ff.empty ()) + { + octave_time tc = fcn->time_checked (); - return first_param_space; -} - -// Calculate how much space needs to be reserved for the -// dimensions string. For example, -// -// mat is a 12x3 matrix -// ^^^^ => 4 columns -// -// FIXME -- why not just use the dim_vector::str () method? - -int -symbol_record::dimensions_string_req_total_space (int print_dims) const -{ - std::string dim_str = ""; - std::stringstream ss; - - ss << make_dimensions_string (print_dims); - dim_str = ss.str (); - - return dim_str.length (); -} + bool relative = fcn->is_relative (); -// Make the dimensions-string. For example: mat is a 2x3 matrix. -// ^^^ -// -// FIXME -- why not just use the dim_vector::str () method? - -std::string -symbol_record::make_dimensions_string (int print_dims) const -{ - // Calculating dimensions. - - std::string dim_str = ""; - std::stringstream ss; - dim_vector dimensions = dims (); - long dim = dimensions.length (); - - // Preparing dimension string. - - if ((dim <= print_dims || print_dims < 0) && print_dims != 0) - { - // Only printing the dimension string as: axbxc... - - if (dim == 0) - ss << "1x1"; - else - { - for (int i = 0; i < dim; i++) - { - if (i == 0) + if (tc < Vlast_prompt_time + || (relative && tc < Vlast_chdir_time)) { - if (dim == 1) - { - // Looks like this is not going to happen in - // Octave, but ... + octave_time ottp = fcn->time_parsed (); + time_t tp = ottp.unix_time (); - ss << "1x" << dimensions (i); - } - else - ss << dimensions (i); - } - else if (i < dim && dim != 1) - ss << "x" << dimensions (i); - } - } - } - else - { - // Printing dimension string as: a-D. - - ss << dim << "-D"; - } - - dim_str = ss.str (); - - return dim_str; -} - -// Print a line of information on a given symbol. + std::string nm = fcn->name (); -void -symbol_record::print_symbol_info_line (std::ostream& os, - std::list& params) const -{ - std::list::iterator i = params.begin (); - while (i != params.end ()) - { - whos_parameter param = * i; + int nm_len = nm.length (); - if (param.command != '\0') - { - // Do the actual printing. - - switch (param.modifier) - { - case 'l': - os << std::setiosflags (std::ios::left) - << std::setw (param.parameter_length); - break; - - case 'r': - os << std::setiosflags (std::ios::right) - << std::setw (param.parameter_length); - break; + std::string file; + std::string dir_name; - case 'c': - if (param.command == 's') - { - int front = param.first_parameter_length - - dimensions_string_req_first_space (param.dimensions); - int back = param.parameter_length - - dimensions_string_req_total_space (param.dimensions) - - front; - front = (front > 0) ? front : 0; - back = (back > 0) ? back : 0; - - os << std::setiosflags (std::ios::left) - << std::setw (front) - << "" - << std::resetiosflags (std::ios::left) - << make_dimensions_string (param.dimensions) - << std::setiosflags (std::ios::left) - << std::setw (back) - << "" - << std::resetiosflags (std::ios::left); - } - else - { - os << std::setiosflags (std::ios::left) - << std::setw (param.parameter_length); - } - break; - - default: - error ("whos_line_format: modifier `%c' unknown", - param.modifier); - - os << std::setiosflags (std::ios::right) - << std::setw (param.parameter_length); - } - - switch (param.command) - { - case 'b': - os << byte_size (); - break; - - case 'c': - os << class_name (); - break; - - case 'e': - os << capacity (); - break; - - case 'n': - os << name (); - break; - - case 'p': - { - std::stringstream ss; - std::string str; - - ss << (is_read_only () ? "r-" : "rw") - << (is_static () || is_eternal () ? "-" : "d"); - str = ss.str (); - - os << str; - } - break; - - case 's': - if (param.modifier != 'c') - os << make_dimensions_string (param.dimensions); - break; - - case 't': - os << type_name (); - break; - - default: - error ("whos_line_format: command `%c' unknown", param.command); - } + if (octave_env::absolute_pathname (nm) + && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct" + || nm.substr (nm_len-4) == ".mex")) + || (nm_len > 2 && nm.substr (nm_len-4) == ".m"))) + file = nm; + else + // FIXME -- this lookup is not right since it doesn't + // account for dispatch type. + file = octave_env::make_absolute (load_path::find_fcn (nm, dir_name), + octave_env::getcwd ()); - os << std::resetiosflags (std::ios::left) - << std::resetiosflags (std::ios::right); - i++; - } - else - { - os << param.text; - i++; - } - } -} - -void -symbol_record::print_info (std::ostream& os, const std::string& prefix) const -{ - os << prefix << "formal param: " << formal_param << "\n" - << prefix << "linked to global: " << linked_to_global << "\n" - << prefix << "tagged static: " << tagged_static << "\n" - << prefix << "can hide function: " << can_hide_function << "\n" - << prefix << "visible: " << visible << "\n"; - - if (definition) - definition->print_info (os, prefix); - else - os << prefix << "symbol " << name () << " is undefined\n"; -} - -bool -symbol_record::read_only_error (const char *action) -{ - if (is_read_only ()) - { - if (is_variable ()) - ::error ("can't %s read-only constant `%s'", action, nm.c_str ()); - else if (is_function ()) - ::error ("can't %s read-only function `%s'", action, nm.c_str ()); - else - ::error ("can't %s read-only symbol `%s'", action, nm.c_str ()); + if (file.empty ()) + { + // Can't see this function from current + // directory, so we should clear it. - return true; - } - else - return false; -} - -// A symbol table. - -symbol_table::~symbol_table (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - symbol_record *tmp = ptr; - - ptr = ptr->next (); - - delete tmp; - } - } - - delete [] table; -} - -symbol_record * -symbol_table::lookup (const std::string& nm, bool insert, bool warn) -{ - if (Vdebug_symtab_lookups) - { - std::cerr << (table_name.empty () ? std::string ("???") : table_name) - << " symtab::lookup [" - << (insert ? "I" : "-") - << (warn ? "W" : "-") - << "] \"" << nm << "\"\n"; - } - - unsigned int index = hash (nm); - - symbol_record *ptr = table[index].next (); + function = octave_value (); + } + else if (same_file (file, ff)) + { + fcn->mark_fcn_file_up_to_date (octave_time ()); - while (ptr) - { - if (ptr->name () == nm) - return ptr; - - ptr = ptr->next (); - } - - if (insert) - { - symbol_record *sr = new symbol_record (nm, table[index].next ()); - - table[index].chain (sr); - - return sr; - } - else if (warn) - warning ("lookup: symbol `%s' not found", nm.c_str ()); - - return 0; -} - -void -symbol_table::rename (const std::string& old_name, const std::string& new_name) -{ - if (Vdebug_symtab_lookups) - { - std::cerr << (table_name.empty () ? std::string ("???") : table_name) - << " symtab::rename " - << "\"" << old_name << "\"" - << " to " - << "\"" << new_name << "\"\n"; - } - - unsigned int index = hash (old_name); + if (! (Vignore_function_time_stamp == 2 + || (Vignore_function_time_stamp + && fcn->is_system_fcn_file ()))) + { + file_stat fs (ff); - symbol_record *prev = &table[index]; - symbol_record *ptr = prev->next (); - - while (ptr) - { - if (ptr->name () == old_name) - { - ptr->rename (new_name); - - if (! error_state) - { - prev->chain (ptr->next ()); - - index = hash (new_name); - ptr->chain (table[index].next ()); - table[index].chain (ptr); - - return; - } - - break; - } - - prev = ptr; - ptr = ptr->next (); - } - - error ("unable to rename `%s' to `%s'", old_name.c_str (), - new_name.c_str ()); -} - -// FIXME -- it would be nice to eliminate a lot of the -// following duplicate code. - -void -symbol_table::clear (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); + if (fs) + { + if (fs.is_newer (tp)) + { + fcn = load_fcn_from_file (ff, dir_name); - while (ptr) - { - if (ptr->is_user_function()) - { - octave_user_function *fcn = ptr->def ().user_function_value (); - std::string parent = (fcn ? fcn->parent_fcn_name () : - std::string ()); - - if (! parent.empty ()) - { - if (curr_parent_function && - parent == curr_parent_function->name ()) - { - ptr = ptr->next (); - continue; - } - - symbol_record *parent_sr = fbi_sym_tab->lookup (parent); - - if (parent_sr && (parent_sr->is_static () || - parent_sr->is_eternal ())) - { - ptr = ptr->next (); - continue; - } - } - } - - ptr->clear (); - - ptr = ptr->next (); - } - } -} - -void -symbol_table::clear_variables (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); + if (fcn) + { + retval = true; - while (ptr) - { - if (ptr->is_user_variable ()) - ptr->clear (); - - ptr = ptr->next (); - } - } -} - -// Really only clear functions that can be reloaded. - -void -symbol_table::clear_functions (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - if (ptr->is_user_function () - || ptr->is_dld_function () - || ptr->is_mex_function ()) - { - - if (ptr->is_user_function()) - { - octave_user_function *fcn = - ptr->def ().user_function_value (); - std::string parent = (fcn ? fcn->parent_fcn_name () : - std::string ()); - - if (! parent.empty ()) - { - if (curr_parent_function && - parent == curr_parent_function->name ()) - { - ptr = ptr->next (); - continue; - } - - symbol_record *parent_sr = fbi_sym_tab->lookup (parent); - - if (parent_sr && (parent_sr->is_static () || - parent_sr->is_eternal ())) - { - ptr = ptr->next (); - continue; + function = octave_value (fcn); + } + else + function = octave_value (); + } + } + else + function = octave_value (); } } } - - ptr->clear (); } - - ptr = ptr->next (); - } - } -} - -void -symbol_table::clear_mex_functions (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - if (ptr->is_mex_function ()) - ptr->clear (); - - ptr = ptr->next (); - } - } -} - -void -symbol_table::clear_globals (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - if (ptr->is_user_variable () && ptr->is_linked_to_global ()) - ptr->clear (); - - ptr = ptr->next (); - } - } -} - -bool -symbol_table::clear (const std::string& nm) -{ - unsigned int index = hash (nm); - - symbol_record *ptr = table[index].next (); - - while (ptr) - { - if (ptr->name () == nm) - { - if (ptr->is_user_function()) - { - octave_user_function *fcn = - ptr->def ().user_function_value (); - std::string parent = (fcn ? fcn->parent_fcn_name () : - std::string ()); - - if (! parent.empty ()) - { - if (curr_parent_function && - parent == curr_parent_function->name ()) - return true; - - symbol_record *parent_sr = fbi_sym_tab->lookup (parent); - - if (parent_sr && (parent_sr->is_static () || - parent_sr->is_eternal ())) - return true; - } - } - - ptr->clear (); - - return true; - } - ptr = ptr->next (); - } - - return false; -} - -bool -symbol_table::clear_variable (const std::string& nm) -{ - unsigned int index = hash (nm); - - symbol_record *ptr = table[index].next (); - - while (ptr) - { - if (ptr->name () == nm && ptr->is_user_variable ()) - { - ptr->clear (); - return true; - } - ptr = ptr->next (); - } - - return false; -} - -bool -symbol_table::clear_global (const std::string& nm) -{ - unsigned int index = hash (nm); - - symbol_record *ptr = table[index].next (); - - while (ptr) - { - if (ptr->name () == nm - && ptr->is_user_variable () - && ptr->is_linked_to_global ()) - { - ptr->clear (); - return true; - } - ptr = ptr->next (); - } - - return false; -} - -// Really only clear functions that can be reloaded. - -bool -symbol_table::clear_function (const std::string& nm) -{ - unsigned int index = hash (nm); - - symbol_record *ptr = table[index].next (); - - while (ptr) - { - if (ptr->name () == nm - && (ptr->is_user_function () - || ptr->is_dld_function () - || ptr->is_mex_function ())) - { - if (ptr->is_user_function()) - { - octave_user_function *fcn = - ptr->def ().user_function_value (); - std::string parent = (fcn ? fcn->parent_fcn_name () : - std::string ()); - - if (! parent.empty ()) - { - if (curr_parent_function && - parent == curr_parent_function->name ()) - return true; - - symbol_record *parent_sr = fbi_sym_tab->lookup (parent); - - if (parent_sr && (parent_sr->is_static () || - parent_sr->is_eternal ())) - return true; - } - } - - ptr->clear (); - return true; - } - ptr = ptr->next (); - } - - return false; -} - -bool -symbol_table::clear_variable_pattern (const std::string& pat) -{ - bool retval = false; - - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - if (ptr->is_user_variable ()) - { - glob_match pattern (pat); - - if (pattern.match (ptr->name ())) - { - ptr->clear (); - - retval = true; - } - } - - ptr = ptr->next (); } } @@ -1092,915 +193,609 @@ } bool -symbol_table::clear_global_pattern (const std::string& pat) +out_of_date_check (octave_value& function) { - bool retval = false; + return out_of_date_check_internal (function); +} - for (unsigned int i = 0; i < table_size; i++) +octave_value +symbol_table::fcn_info::fcn_info_rep::load_private_function + (const std::string& dir_name) +{ + octave_value retval; + + std::string file_name = load_path::find_private_fcn (dir_name, name); + + if (! file_name.empty ()) { - symbol_record *ptr = table[i].next (); + octave_function *fcn = load_fcn_from_file (file_name); - while (ptr) + if (fcn) { - if (ptr->is_user_variable () && ptr->is_linked_to_global ()) - { - glob_match pattern (pat); + retval = octave_value (fcn); - if (pattern.match (ptr->name ())) - { - ptr->clear (); - - retval = true; - } - } - - ptr = ptr->next (); + private_functions[dir_name] = retval; } } return retval; } -// Really only clear functions that can be reloaded. - -bool -symbol_table::clear_function_pattern (const std::string& pat) +octave_value +symbol_table::fcn_info::fcn_info_rep::load_class_constructor (void) { - bool retval = false; + octave_value retval; + + std::string dir_name; - for (unsigned int i = 0; i < table_size; i++) + std::string file_name = load_path::find_method (name, name, dir_name); + + if (! file_name.empty ()) { - symbol_record *ptr = table[i].next (); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, name); - while (ptr) + if (fcn) { - if (ptr->is_user_function () - || ptr->is_dld_function () - || ptr->is_mex_function ()) - { - glob_match pattern (pat); + retval = octave_value (fcn); + + class_constructors[name] = retval; + } + } + + return retval; +} + +octave_value +symbol_table::fcn_info::fcn_info_rep::load_class_method + (const std::string& dispatch_type) +{ + octave_value retval; - if (pattern.match (ptr->name ())) - { - ptr->clear (); + std::string dir_name; + + std::string file_name = load_path::find_method (dispatch_type, name, dir_name); - retval = true; - } - } + if (! file_name.empty ()) + { + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type); - ptr = ptr->next (); + if (fcn) + { + retval = octave_value (fcn); + + class_methods[dispatch_type] = retval; } } return retval; } -int -symbol_table::size (void) const +void +symbol_table::fcn_info::fcn_info_rep::print_dispatch (std::ostream& os) const { - int count = 0; + if (dispatch_map.empty ()) + os << "dispatch: " << name << " is not overloaded" << std::endl; + else + { + os << "Overloaded function " << name << ":\n\n"; + + for (const_dispatch_map_iterator p = dispatch_map.begin (); + p != dispatch_map.end (); p++) + os << " " << name << " (" << p->first << ", ...) -> " + << p->second << " (" << p->first << ", ...)\n"; - for (unsigned int i = 0; i < table_size; i++) + os << std::endl; + } +} + +std::string +symbol_table::fcn_info::fcn_info_rep::help_for_dispatch (void) const +{ + std::string retval; + + if (! dispatch_map.empty ()) { - symbol_record *ptr = table[i].next (); + retval = "Overloaded function:\n\n"; + + for (const_dispatch_map_iterator p = dispatch_map.begin (); + p != dispatch_map.end (); p++) + retval += " " + p->second + " (" + p->first + ", ...)\n\n"; + } + + return retval; +} + +// Find the definition of NAME according to the following precedence +// list: +// +// variable +// subfunction +// private function +// class constructor +// class method +// legacy dispatch +// command-line function +// autoload function +// function on the path +// built-in function - while (ptr) +// Notes: +// +// FIXME -- we need to evaluate the argument list to determine the +// dispatch type. The method used here works (pass in the args, pass +// out the evaluated args and a flag saying whether the evaluation was +// needed), but it seems a bit inelegant. We do need to save the +// evaluated args in some way to avoid evaluating them multiple times. +// Maybe evaluated args could be attached to the tree_argument_list +// object? Then the argument list could be evaluated outside of this +// function and we could elimnate the arg_names, evaluated_args, and +// args_evaluated arguments. We would still want to avoid computing +// the dispatch type unless it is needed, so the args should be passed +// rather than the dispatch type. But the arguments will need to be +// evaluated no matter what, so evaluating them beforehand should be +// OK. If the evaluated arguments are attached to args, then we would +// need to determine the appropriate place(s) to clear them (for +// example, before returning from tree_index_expression::rvalue). + +octave_value +symbol_table::fcn_info::fcn_info_rep::find + (tree_argument_list *args, const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope) +{ + static bool deja_vu = false; + + // Subfunction. I think it only makes sense to check for + // subfunctions if we are currently executing a function defined + // from a .m file. + + scope_val_iterator r = subfunctions.find (scope); + + if (r != subfunctions.end ()) + { + // FIXME -- out-of-date check here. + + return r->second; + } + else if (curr_parent_function) + { + scope_id pscope = curr_parent_function->scope (); + + r = subfunctions.find (pscope); + + if (r != subfunctions.end ()) { - count++; - ptr = ptr->next (); + // FIXME -- out-of-date check here. + + return r->second; } } - return count; -} + // Private function. -static bool -matches_patterns (const std::string& name, const string_vector& pats) -{ - int npats = pats.length (); + octave_function *curr_fcn = octave_call_stack::current (); - if (npats == 0) - return true; - - glob_match pattern (pats); - - return pattern.match (name); -} + if (curr_fcn) + { + std::string dir_name = curr_fcn->dir_name (); -Array -symbol_table::subsymbol_list (const string_vector& pats, - unsigned int type, unsigned int scope) const -{ - int count = 0; - - int n = size (); + if (! dir_name.empty ()) + { + str_val_iterator q = private_functions.find (dir_name); - Array subsymbols (dim_vector (n, 1)); - int pats_length = pats.length (); - - if (n == 0) - return subsymbols; - - // Look for separators like .({ - for (int j = 0; j < pats_length; j++) - { - std::string var_name = pats (j); + if (q == private_functions.end ()) + { + octave_value val = load_private_function (dir_name); - size_t pos = var_name.find_first_of (".({"); - - if ((pos != NPOS) && (pos > 0)) - { - std::string first_name = var_name.substr(0,pos); - - for (unsigned int i = 0; i < table_size; i++) + if (val.is_defined ()) + return val; + } + else { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - assert (count < n); - - unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky... + octave_value& fval = q->second; - unsigned int my_type = ptr->type (); - - std::string my_name = ptr->name (); + if (fval.is_defined ()) + out_of_date_check_internal (fval); - if ((type & my_type) && (scope & my_scope) && (first_name == my_name)) - { - symbol_record *sym_ptr = new symbol_record (); - octave_value value; - int parse_status; - - value = eval_string (var_name, true, parse_status); - - sym_ptr->define (value); - sym_ptr->rename (var_name); - subsymbols(count++) = sym_ptr; - } + if (fval.is_defined ()) + return fval; + else + { + octave_value val = load_private_function (dir_name); - ptr = ptr->next (); + if (val.is_defined ()) + return val; } } } } - subsymbols.resize (dim_vector (count, 1)); + // Class constructors. The class name and function name are the same. - return subsymbols; -} + str_val_iterator q = class_constructors.find (name); -Array -symbol_table::symbol_list (const string_vector& pats, - unsigned int type, unsigned int scope) const -{ - int count = 0; + if (q == class_constructors.end ()) + { + octave_value val = load_class_constructor (); - int n = size (); - - Array symbols (dim_vector (n, 1)); - - if (n == 0) - return symbols; - - for (unsigned int i = 0; i < table_size; i++) + if (val.is_defined ()) + return val; + } + else { - symbol_record *ptr = table[i].next (); + octave_value& fval = q->second; - while (ptr) - { - if (ptr->is_visible ()) - { - assert (count < n); - - unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky... + if (fval.is_defined ()) + out_of_date_check_internal (fval); - unsigned int my_type = ptr->type (); - - std::string my_name = ptr->name (); + if (fval.is_defined ()) + return fval; + else + { + octave_value val = load_class_constructor (); - if ((type & my_type) && (scope & my_scope) && (matches_patterns (my_name, pats))) - symbols(count++) = ptr; - } - - ptr = ptr->next (); + if (val.is_defined ()) + return val; } } - symbols.resize (dim_vector (count, 1)); + // Class methods. - return symbols; -} + if (args_evaluated || (args && args->length () > 0)) + { + if (! args_evaluated) + evaluated_args = args->convert_to_const_vector (); -string_vector -symbol_table::name_list (const string_vector& pats, bool sort, - unsigned int type, unsigned int scope) const -{ - Array symbols = symbol_list (pats, type, scope); + if (! error_state) + { + int n = evaluated_args.length (); + + if (n > 0 && ! args_evaluated) + evaluated_args.stash_name_tags (arg_names); + + args_evaluated = true; + + // FIXME -- need to handle precedence. - string_vector names; + std::string dispatch_type = evaluated_args(0).class_name (); - int n = symbols.length (); + for (int i = 1; i < n; i++) + { + octave_value arg = evaluated_args(i); - if (n > 0) - { - names.resize (n); + if (arg.is_object ()) + { + dispatch_type = arg.class_name (); + break; + } + } - for (int i = 0; i < n; i++) - names[i] = symbols(i)->name (); + octave_value fcn = find_method (dispatch_type); + + if (fcn.is_defined ()) + return fcn; + } + else + return octave_value (); } - if (sort) - names.qsort (); + // Legacy dispatch. We just check args_evaluated here because the + // actual evaluation will have happened already when searching for + // class methods. + + if (args_evaluated && ! dispatch_map.empty ()) + { + std::string dispatch_type = evaluated_args(0).type_name (); + + std::string fname; + + dispatch_map_iterator p = dispatch_map.find (dispatch_type); + + if (p == dispatch_map.end ()) + p = dispatch_map.find ("any"); - return names; -} + if (p != dispatch_map.end ()) + { + fname = p->second; + + octave_value fcn + = symbol_table::find_function (fname, evaluated_args, scope); + + if (fcn.is_defined ()) + return fcn; + } + } + + // Command-line function. + + if (cmdline_function.is_defined ()) + return cmdline_function; + + // Autoload? -static int -maybe_list_cmp_fcn (const void *a_arg, const void *b_arg) -{ - const symbol_record *a = *(static_cast (a_arg)); - const symbol_record *b = *(static_cast (b_arg)); + octave_value fcn = find_autoload (); + + if (fcn.is_defined ()) + return fcn; + + // Function on the path. + + fcn = find_user_function (); + + if (fcn.is_defined ()) + return fcn; + + // Built-in function. + + if (built_in_function.is_defined ()) + return built_in_function; - std::string a_nm = a->name (); - std::string b_nm = b->name (); + // At this point, we failed to find anything. It is possible that + // the user created a file on the fly since the last prompt or + // chdir, so try updating the load path and searching again. + + octave_value retval; - return a_nm.compare (b_nm); + if (! deja_vu) + { + load_path::update (); + + deja_vu = true; + + retval = find (args, arg_names, evaluated_args, args_evaluated, scope); + } + + deja_vu = false; + + return retval; } -void -symbol_table::print_descriptor (std::ostream& os, - std::list params) const +octave_value +symbol_table::fcn_info::fcn_info_rep::find_method (const std::string& dispatch_type) { - // This method prints a line of information on a given symbol - std::list::iterator i = params.begin (); - std::ostringstream param_buf; - - while (i != params.end ()) - { - whos_parameter param = * i; + octave_value retval; - if (param.command != '\0') - { - // Do the actual printing - switch (param.modifier) - { - case 'l': - os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); - param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); - break; + str_val_iterator q = class_methods.find (dispatch_type); - case 'r': - os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); - param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); - break; - - case 'c': - if (param.command != 's') - { - os << std::setiosflags (std::ios::left) - << std::setw (param.parameter_length); - param_buf << std::setiosflags (std::ios::left) - << std::setw (param.parameter_length); - } - break; + if (q == class_methods.end ()) + { + octave_value val = load_class_method (dispatch_type); - default: - os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); - param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); - } + if (val.is_defined ()) + return val; + } + else + { + octave_value& fval = q->second; - if (param.command == 's' && param.modifier == 'c') - { - int a, b; - - if (param.modifier == 'c') - { - a = param.first_parameter_length - param.balance; - a = (a < 0 ? 0 : a); - b = param.parameter_length - a - param.text . length (); - b = (b < 0 ? 0 : b); - os << std::setiosflags (std::ios::left) << std::setw (a) - << "" << std::resetiosflags (std::ios::left) << param.text - << std::setiosflags (std::ios::left) - << std::setw (b) << "" - << std::resetiosflags (std::ios::left); - param_buf << std::setiosflags (std::ios::left) << std::setw (a) - << "" << std::resetiosflags (std::ios::left) << param.line - << std::setiosflags (std::ios::left) - << std::setw (b) << "" - << std::resetiosflags (std::ios::left); - } - } - else - { - os << param.text; - param_buf << param.line; - } - os << std::resetiosflags (std::ios::left) - << std::resetiosflags (std::ios::right); - param_buf << std::resetiosflags (std::ios::left) - << std::resetiosflags (std::ios::right); - i++; - } + if (fval.is_defined ()) + out_of_date_check_internal (fval); + + if (fval.is_defined ()) + return fval; else { - os << param.text; - param_buf << param.line; - i++; + octave_value val = load_class_method (dispatch_type); + + if (val.is_defined ()) + return val; } } - os << param_buf.str (); + return retval; } -std::list -symbol_table::parse_whos_line_format (Array& symbols) const +octave_value +symbol_table::fcn_info::fcn_info_rep::find_autoload (void) { - // This method parses the string whos_line_format, and returns - // a parameter list, containing all information needed to print - // the given attributtes of the symbols - int idx; - size_t format_len = Vwhos_line_format.length (); - char garbage; - std::list params; - - size_t bytes1; - int elements1; + octave_value retval; - int len = symbols.length (); - - std::string param_string = "bcenpst"; - Array param_length (dim_vector (param_string.length (), 1)); - Array param_names (dim_vector (param_string.length (), 1)); - size_t pos_b, pos_c, pos_e, pos_n, pos_p, pos_s, pos_t; + // Autoloaded function. - pos_b = param_string.find ('b'); // Bytes - pos_c = param_string.find ('c'); // Class - pos_e = param_string.find ('e'); // Elements - pos_n = param_string.find ('n'); // Name - pos_p = param_string.find ('p'); // Protected - pos_s = param_string.find ('s'); // Size - pos_t = param_string.find ('t'); // Type + if (autoload_function.is_defined ()) + out_of_date_check_internal (autoload_function); - param_names(pos_b) = "Bytes"; - param_names(pos_c) = "Class"; - param_names(pos_e) = "Elements"; - param_names(pos_n) = "Name"; - param_names(pos_p) = "Prot"; - param_names(pos_s) = "Size"; - param_names(pos_t) = "Type"; + if (! autoload_function.is_defined ()) + { + std::string file_name = lookup_autoload (name); - for (size_t i = 0; i < param_string.length (); i++) - param_length(i) = param_names(i) . length (); - - // Calculating necessary spacing for name column, - // bytes column, elements column and class column - for (int i = 0; i < static_cast (len); i++) - { - std::stringstream ss1, ss2; - std::string str; + if (! file_name.empty ()) + { + size_t pos = file_name.find_last_of (file_ops::dir_sep_chars); - str = symbols(i)->name (); - param_length(pos_n) = ((str.length () - > static_cast (param_length(pos_n))) - ? str.length () : param_length(pos_n)); - - str = symbols(i)->type_name (); - param_length(pos_t) = ((str.length () - > static_cast (param_length(pos_t))) - ? str.length () : param_length(pos_t)); + std::string dir_name = file_name.substr (0, pos); - elements1 = symbols(i)->capacity (); - ss1 << elements1; - str = ss1.str (); - param_length(pos_e) = ((str.length () - > static_cast (param_length(pos_e))) - ? str.length () : param_length(pos_e)); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + "", name, true); - bytes1 = symbols(i)->byte_size (); - ss2 << bytes1; - str = ss2.str (); - param_length(pos_b) = ((str.length () - > static_cast (param_length(pos_b))) - ? str.length () : param_length (pos_b)); + if (fcn) + autoload_function = octave_value (fcn); + } } - idx = 0; - while (static_cast (idx) < format_len) - { - whos_parameter param; - param.command = '\0'; - - if (Vwhos_line_format[idx] == '%') - { - bool error_encountered = false; - param.modifier = 'r'; - param.parameter_length = 0; - param.dimensions = 8; - - int a = 0, b = -1, c = 8, balance = 1; - unsigned int items; - size_t pos; - std::string cmd; - - // Parse one command from whos_line_format - cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); - pos = cmd.find (';'); - if (pos != NPOS) - cmd = cmd.substr (0, pos+1); - else - error ("parameter without ; in whos_line_format"); - - idx += cmd.length (); - - // FIXME -- use iostream functions instead of sscanf! + return autoload_function; +} - if (cmd.find_first_of ("crl") != 1) - items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d:%d;", - &garbage, ¶m.command, &a, &b, &c, &balance); - else - items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d:%d;", - &garbage, ¶m.modifier, ¶m.command, - &a, &b, &c, &balance) - 1; - - if (items < 2) - { - error ("whos_line_format: parameter structure without command in whos_line_format"); - error_encountered = true; - } +octave_value +symbol_table::fcn_info::fcn_info_rep::find_user_function (void) +{ + // Function on the path. - // Insert data into parameter - param.first_parameter_length = 0; - pos = param_string.find (param.command); - if (pos != NPOS) - { - param.parameter_length = param_length(pos); - param.text = param_names(pos); - param.line.assign (param_names(pos).length (), '='); - - param.parameter_length = (a > param.parameter_length - ? a : param.parameter_length); - if (param.command == 's' && param.modifier == 'c' && b > 0) - param.first_parameter_length = b; - } - else - { - error ("whos_line_format: '%c' is not a command", - param.command); - error_encountered = true; - } + if (function_on_path.is_defined ()) + out_of_date_check_internal (function_on_path); - if (param.command == 's') - { - // Have to calculate space needed for printing matrix dimensions - // Space needed for Size column is hard to determine in prior, - // because it depends on dimensions to be shown. That is why it is - // recalculated for each Size-command - int j, first, rest = 0, total; - param.dimensions = c; - first = param.first_parameter_length; - total = param.parameter_length; - - for (j = 0; j < len; j++) - { - int first1 = symbols(j)->dimensions_string_req_first_space (param.dimensions); - int total1 = symbols(j)->dimensions_string_req_total_space (param.dimensions); - int rest1 = total1 - first1; - rest = (rest1 > rest ? rest1 : rest); - first = (first1 > first ? first1 : first); - total = (total1 > total ? total1 : total); - } + if (! function_on_path.is_defined ()) + { + std::string dir_name; - if (param.modifier == 'c') - { - if (first < balance) - first += balance - first; - if (rest + balance < param.parameter_length) - rest += param.parameter_length - rest - balance; + std::string file_name = load_path::find_fcn (name, dir_name); - param.parameter_length = first + rest; - param.first_parameter_length = first; - param.balance = balance; - } - else - { - param.parameter_length = total; - param.first_parameter_length = 0; - } - } - else if (param.modifier == 'c') - { - error ("whos_line_format: modifier 'c' not available for command '%c'", - param.command); - error_encountered = true; - } + if (! file_name.empty ()) + { + octave_function *fcn = load_fcn_from_file (file_name, dir_name); - // What happens if whos_line_format contains negative numbers - // at param_length positions? - param.balance = (b < 0 ? 0 : param.balance); - param.first_parameter_length = (b < 0 ? 0 : - param.first_parameter_length); - param.parameter_length = (a < 0 - ? 0 - : (param.parameter_length - < param_length(pos_s) - ? param_length(pos_s) - : param.parameter_length)); - - // Parameter will not be pushed into parameter list if ... - if (! error_encountered) - params.push_back (param); - } - else - { - // Text string, to be printed as it is ... - std::string text; - size_t pos; - text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); - pos = text.find ('%'); - if (pos != NPOS) - text = text.substr (0, pos); - - // Push parameter into list ... - idx += text.length (); - param.text=text; - param.line.assign (text.length(), ' '); - params.push_back (param); + if (fcn) + function_on_path = octave_value (fcn); } } - return params; + return function_on_path; +} + +octave_value +symbol_table::fcn_info::find (tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, + bool& args_evaluated, scope_id scope) +{ + return rep->find (args, arg_names, evaluated_args, args_evaluated, scope); +} + +octave_value +symbol_table::find (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + symbol_table::scope_id scope, bool skip_variables) +{ + symbol_table *inst = get_instance (scope); + + return inst + ? inst->do_find (name, args, arg_names, evaluated_args, + args_evaluated, scope, skip_variables) + : octave_value (); +} + +octave_value +symbol_table::find_function (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, + bool& args_evaluated, scope_id scope) +{ + return find (name, args, arg_names, evaluated_args, args_evaluated, + scope, true); } -int -symbol_table::maybe_list (const char *header, const string_vector& argv, - std::ostream& os, bool show_verbose, - unsigned type, unsigned scope) +octave_value +symbol_table::do_find (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, + bool& args_evaluated, scope_id scope, + bool skip_variables) { - // This method prints information for sets of symbols, but only one - // set at a time (like, for instance: all variables, or all - // built-in-functions). + octave_value retval; - // This method invokes print_symbol_info_line to print info on every - // symbol. + // Variable. - int status = 0; - - if (show_verbose) + if (! skip_variables) { - // FIXME Should separate argv to lists with and without dots. - Array xsymbols = symbol_list (argv, type, scope); - Array xsubsymbols = subsymbol_list (argv, type, scope); + table_iterator p = table.find (name); - int sym_len = xsymbols.length (), subsym_len = xsubsymbols.length (), - len = sym_len + subsym_len; - - Array symbols (dim_vector (len, 1)); + if (p != table.end ()) + { + symbol_record& sr = p->second; - if (len > 0) - { - size_t bytes = 0; - size_t elements = 0; - - int i; + // FIXME -- should we be using something other than varref here? - std::list params; - - // Joining symbolic tables. - for (i = 0; i < sym_len; i++) - symbols(i) = xsymbols(i); - - for (i = 0; i < subsym_len; i++) - symbols(i+sym_len) = xsubsymbols(i); - - os << "\n" << header << "\n\n"; - - symbols.qsort (maybe_list_cmp_fcn); - - params = parse_whos_line_format (symbols); - - print_descriptor (os, params); + if (sr.is_global ()) + return symbol_table::varref (name, xglobal_scope); + else + { + octave_value& val = sr.varref (); - os << "\n"; + if (val.is_defined ()) + return val; + } + } + } - for (int j = 0; j < len; j++) - { - symbols(j)->print_symbol_info_line (os, params); - elements += symbols(j)->capacity (); - bytes += symbols(j)->byte_size (); - } + fcn_table_iterator p = fcn_table.find (name); - os << "\nTotal is " - << elements << (elements == 1 ? " element" : " elements") - << " using " - << bytes << (bytes == 1 ? " byte" : " bytes") - << "\n"; + if (p != fcn_table.end ()) + { + evaluated_args = octave_value_list (); + args_evaluated = false; - status = 1; - } + return p->second.find (args, arg_names, evaluated_args, args_evaluated, + scope); } else { - string_vector symbols = name_list (argv, 1, type, scope); + fcn_info finfo (name); + + octave_value fcn = finfo.find (args, arg_names, evaluated_args, + args_evaluated, scope); - if (! symbols.empty ()) - { - os << "\n" << header << "\n\n"; + if (fcn.is_defined ()) + fcn_table[name] = finfo; - symbols.list_in_columns (os); - - status = 1; - } + return fcn; } - return status; -} - -Array -symbol_table::glob (const std::string& pat, unsigned int type, - unsigned int scope) const -{ - int count = 0; - - int n = size (); - - Array symbols (dim_vector (n, 1)); - - if (n == 0) - return symbols; - - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - assert (count < n); - - unsigned int my_scope = ptr->is_linked_to_global () + 1; // Tricky... - - unsigned int my_type = ptr->type (); - - glob_match pattern (pat); - - if ((type & my_type) && (scope & my_scope) - && pattern.match (ptr->name ())) - { - symbols(count++) = ptr; - } - - ptr = ptr->next (); - } - } - - symbols.resize (dim_vector (count, 1)); - - return symbols; + return retval; } -void -symbol_table::push_context (void) +DEFUN (ignore_function_time_stamp, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\ +Query or set the internal variable that controls whether Octave checks\n\ +the time stamp on files each time it looks up functions defined in\n\ +function files. If the internal variable is set to @code{\"system\"},\n\ +Octave will not automatically recompile function files in subdirectories of\n\ +@file{@var{octave-home}/lib/@var{version}} if they have changed since\n\ +they were last compiled, but will recompile other function files in the\n\ +search path if they change. If set to @code{\"all\"}, Octave will not\n\ +recompile any function files unless their definitions are removed with\n\ +@code{clear}. If set to \"none\", Octave will always check time stamps\n\ +on files to determine whether functions defined in function files\n\ +need to recompiled.\n\ +@end deftypefn") { - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - ptr->push_context (); - ptr = ptr->next (); - } - } -} - -void -symbol_table::pop_context (void) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - ptr->pop_context (); - ptr = ptr->next (); - } - } -} + octave_value retval; -// Create a new symbol table with the same entries. Only the symbol -// names and some attributes are copied, not values. - -symbol_table * -symbol_table::dup (void) -{ - symbol_table *new_sym_tab = new symbol_table (table_size); - - for (unsigned int i = 0; i < table_size; i++) + if (nargout > 0) { - symbol_record *ptr = table[i].next (); - - while (ptr) + switch (Vignore_function_time_stamp) { - std::string nm = ptr->name (); + case 1: + retval = "system"; + break; - symbol_record *sr = new_sym_tab->lookup (nm, true); - - if (sr) - { - if (ptr->is_formal_parameter ()) - sr->mark_as_formal_parameter (); + case 2: + retval = "all"; + break; - if (ptr->is_automatic_variable ()) - sr->mark_as_automatic_variable (); - - if (ptr->is_static ()) - sr->mark_as_static (); - } - - ptr = ptr->next (); + default: + retval = "none"; + break; } } - return new_sym_tab; -} - -void -symbol_table::inherit (symbol_table *parent_sym_tab) -{ - for (unsigned int i = 0; i < table_size; i++) - { - symbol_record *ptr = table[i].next (); - - while (ptr) - { - std::string nm = ptr->name (); - - if (! (nm == "__retval__" - || ptr->is_automatic_variable () - || ptr->is_formal_parameter ())) - { - symbol_record *sr = parent_sym_tab->lookup (nm); + int nargin = args.length (); - if (sr) - { - ptr->define (sr->variable_value ()); - - ptr->mark_as_static (); - } - } - - ptr = ptr->next (); - } - } -} - -void -symbol_table::print_info (std::ostream& os) const -{ - int count = 0; - int empty_chains = 0; - int max_chain_length = 0; - int min_chain_length = INT_MAX; - - for (unsigned int i = 0; i < table_size; i++) + if (nargin == 1) { - int num_this_chain = 0; - - symbol_record *ptr = table[i].next (); - - if (ptr) - os << "chain number " << i << ":\n"; - else - { - empty_chains++; - min_chain_length = 0; - } - - while (ptr) - { - num_this_chain++; - - os << " " << ptr->name () << "\n"; - - ptr->print_info (os, " "); - - ptr = ptr->next (); - } - - count += num_this_chain; - - if (num_this_chain > max_chain_length) - max_chain_length = num_this_chain; - - if (num_this_chain < min_chain_length) - min_chain_length = num_this_chain; - - if (num_this_chain > 0) - os << "\n"; - } - - os << "max chain length: " << max_chain_length << "\n"; - os << "min chain length: " << min_chain_length << "\n"; - os << "empty chains: " << empty_chains << "\n"; - os << "total chains: " << table_size << "\n"; - os << "total symbols: " << count << "\n"; -} - -// Chris Torek's fave hash function. + std::string sval = args(0).string_value (); -unsigned int -symbol_table::hash (const std::string& str) -{ - unsigned int h = 0; - - for (unsigned int i = 0; i < str.length (); i++) - h = h * 33 + str[i]; - - return h & (table_size - 1); -} - -DEFUN (debug_symtab_lookups, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{val} =} debug_symtab_lookups ()\n\ -@deftypefnx {Built-in Function} {@var{old_val} =} debug_symtab_lookups (@var{new_val})\n\ -Query or set the internal variable that controls whether debugging\n\ -information is printed when searching for symbols in the symbol tables.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (debug_symtab_lookups); -} + if (! error_state) + { + if (sval == "all") + Vignore_function_time_stamp = 2; + else if (sval == "system") + Vignore_function_time_stamp = 1; + else if (sval == "none") + Vignore_function_time_stamp = 0; + else + error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\""); + } + else + error ("ignore_function_time_stamp: expecting argument to be character string"); + } + else if (nargin > 1) + print_usage (); -DEFUN (whos_line_format, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\ -@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\ -Query or set the format string used by the @code{whos}.\n\ -\n\ -The following escape sequences may be used in the format:\n\ -@table @code\n\ -@item %b\n\ -Prints number of bytes occupied by variables.\n\ -@item %c\n\ -Prints class names of variables.\n\ -@item %e\n\ -Prints elements held by variables.\n\ -@item %n\n\ -Prints variable names.\n\ -@item %p\n\ -Prints protection attributes of variables.\n\ -@item %s\n\ -Prints dimensions of variables.\n\ -@item %t\n\ -Prints type names of variables.\n\ -@end table\n\ -\n\ -Every command may also have a modifier:\n\ -@table @code\n\ -@item l\n\ -Left alignment.\n\ -@item r\n\ -Right alignment (this is the default).\n\ -@item c\n\ -Centered (may only be applied to command %s).\n\ -@end table\n\ -\n\ -A command is composed like this:\n\ -\n\ -@example\n\ -%[modifier][:size_of_parameter[:center-specific[\n\ - :print_dims[:balance]]]];\n\ -@end example\n\ -\n\ -Command and modifier is already explained. Size_of_parameter\n\ -tells how many columns the parameter will need for printing.\n\ -print_dims tells how many dimensions to print. If number of\n\ -dimensions exceeds print_dims, dimensions will be printed like\n\ -x-D.\n\ -center-specific and print_dims may only be applied to command\n\ -%s. A negative value for print_dims will cause Octave to print all\n\ -dimensions whatsoever.\n\ -balance specifies the offset for printing of the dimensions string.\n\ -\n\ -The default format is \" %p:4; %ln:6; %cs:16:6:8:1; %rb:12; %lc:-1;\\n\".\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (whos_line_format); -} - -DEFUN (variables_can_hide_functions, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{val} =} variables_can_hide_functions ()\n\ -@deftypefnx {Built-in Function} {@var{old_val} =} variables_can_hide_functions (@var{new_val})\n\ -Query or set the internal variable that controls whether assignments\n\ -to variables may hide previously defined functions of the same name.\n\ -If set to a nonzero value allows hiding, zero causes Octave to\n\ -generate an error, and a negative value cause Octave to print a\n\ -warning, but allow the operation.\n\ -@end deftypefn") -{ - return SET_INTERNAL_VARIABLE (variables_can_hide_functions); + return retval; } /* diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/symtab.h --- a/src/symtab.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/symtab.h Fri Dec 28 20:56:58 2007 +0000 @@ -2,7 +2,7 @@ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 John W. Eaton - + This file is part of Octave. Octave is free software; you can redistribute it and/or modify it @@ -24,474 +24,19 @@ #if !defined (octave_symtab_h) #define octave_symtab_h 1 -#include - -#include +#include +#include +#include +#include #include -#include - -#include "oct-alloc.h" -#include "str-vec.h" - -#include "ov.h" - -class octave_lvalue; - -class string_vector; - -class symbol_record; -class symbol_table; - -struct -whos_parameter -{ - char command; - char modifier; - int parameter_length; - int first_parameter_length; - int dimensions; - int balance; - std::string text; - std::string line; -}; - -// Individual records in a symbol table. - -class -OCTINTERP_API -symbol_record -{ -public: - - // If you add or delete an entry here, you'll also need to change - // the width parameter in the declaration for symbol_type below... - - enum TYPE - { - UNKNOWN = 0, - USER_FUNCTION = 1, - USER_VARIABLE = 2, - DLD_FUNCTION = 4, - BUILTIN_FUNCTION = 8, - COMMAND = 16, - RAWCOMMAND = 32, - MAPPER_FUNCTION = 64, - MEX_FUNCTION = 128 - }; - -private: - - // Variables or functions. - - class symbol_def - { - public: - - symbol_def (const octave_value& val = octave_value (), - unsigned int sym_type = 0) - : symbol_type (sym_type), read_only (0), help_string (), - definition (val), count (1) { } - - ~symbol_def (void) { } - - bool is_variable (void) const - { return (symbol_type & symbol_record::USER_VARIABLE); } - - // It's not necessary to check for COMMAND and MAPPER_FUNCTION - // here. Those tags are just used as additional qualifiers for - // the other types of functions. - - bool is_function (void) const - { - return (symbol_type & symbol_record::USER_FUNCTION - || symbol_type & symbol_record::DLD_FUNCTION - || symbol_type & symbol_record::MEX_FUNCTION - || symbol_type & symbol_record::BUILTIN_FUNCTION); - } - - bool is_user_variable (void) const - { return (symbol_type & symbol_record::USER_VARIABLE); } - - // Don't use |= here to avoid error with AIX compiler. - void mark_as_command (void) - { symbol_type = symbol_type | symbol_record::COMMAND; } - - void unmark_command (void) - { symbol_type &= ~symbol_record::COMMAND; } - - bool is_command (void) const - { return (symbol_type & symbol_record::COMMAND); } - - void mark_as_rawcommand (void) - { symbol_type |= (symbol_record::COMMAND - | symbol_record::RAWCOMMAND); } - - void unmark_rawcommand (void) - { symbol_type &= ~symbol_record::RAWCOMMAND; } - - bool is_rawcommand (void) const - { return (symbol_type & symbol_record::RAWCOMMAND); } - - bool is_mapper_function (void) const - { return (symbol_type & symbol_record::MAPPER_FUNCTION); } - - bool is_user_function (void) const - { return (symbol_type & symbol_record::USER_FUNCTION); } - - bool is_builtin_function (void) const - { return (symbol_type & symbol_record::BUILTIN_FUNCTION); } - - bool is_dld_function (void) const - { return (symbol_type & symbol_record::DLD_FUNCTION); } - - bool is_mex_function (void) const - { return (symbol_type & symbol_record::MEX_FUNCTION); } - - // FIXME - bool is_map_element (const std::string& /* elts */) const - { return false; } - - bool is_defined (void) const - { return definition.is_defined (); } - - bool is_read_only (void) const - { return read_only; } - - bool is_matrix_type (void) const - { return definition.is_matrix_type (); } - - bool is_sparse_type (void) const - { return definition.is_sparse_type (); } - - bool is_complex_type (void) const - { return definition.is_complex_type (); } - - std::string class_name (void) const - { return definition.class_name (); } - - Matrix size (void) const - { return definition.size (); } - - size_t byte_size (void) const - { return definition.byte_size (); }; - - octave_idx_type numel (void) const - { return definition.numel (); }; - - octave_idx_type capacity (void) const - { return definition.capacity (); }; - - dim_vector dims (void) const - { return definition.dims (); } - - octave_idx_type rows (void) const { return definition.rows (); } - octave_idx_type columns (void) const { return definition.columns (); } - - std::string type_name (void) const { return definition.type_name (); } - - std::string type_as_string (void) const; - - void type (std::ostream& os, const std::string& name, bool pr_type_info, - bool quiet, bool pr_orig_txt); - - std::string which (const std::string& name); - - void which (std::ostream& os, const std::string& name); - - void define (const octave_value& val, unsigned int sym_type) - { - definition = val; - symbol_type = sym_type; - } - - void protect (void) { read_only = 1; } - - void unprotect (void) { read_only = 0; } - - octave_value& def (void) { return definition; } - - std::string help (void) const { return help_string; } - - void document (const std::string& h); - - unsigned int type (void) { return symbol_type; } - - void *operator new (size_t size) - { return allocator.alloc (size); } - - void operator delete (void *p, size_t size) - { allocator.free (p, size); } - - static octave_allocator allocator; - - // The type of this symbol (see the enum above). - unsigned int symbol_type : 9; - - // Nonzero means this variable cannot be given a new value. - unsigned int read_only : 1; - - // The doc string associated with this variable. - std::string help_string; - - // The value of this definition. See ov.h and related files. - octave_value definition; - - // Reference count. - int count; - - void print_info (std::ostream& os, - const std::string& prefix = std::string ()) const; - - // No copying! - - symbol_def (const symbol_def& sd); - - symbol_def& operator = (const symbol_def& sd); - }; - -public: - - typedef int (*change_function) (void); +#include - symbol_record (void) - : formal_param (false), automatic_variable (false), - linked_to_global (false), tagged_static (false), - can_hide_function (true), visible (true), eternal (false), - nm (), chg_fcn (0), definition (new symbol_def ()), next_elem (0) { } - - // FIXME -- kluge alert! We obviously need a better way of - // handling allow_shadow! - - symbol_record (const std::string& n, symbol_record *nxt) - : formal_param (false), automatic_variable (false), - linked_to_global (false), tagged_static (false), - can_hide_function (n != "__end__"), visible (true), - eternal (false), nm (n), chg_fcn (0), - definition (new symbol_def ()), next_elem (nxt) { } - - ~symbol_record (void) - { - if (--definition->count <= 0) - delete definition; - } - - std::string name (void) const { return nm; } - - std::string help (void) const { return definition->help (); } - - octave_value& def (void) { return definition->def (); } - - void rename (const std::string& new_name); - - bool is_function (void) const - { return definition->is_function (); } - - void mark_as_command (void) - { definition->mark_as_command (); } - - void unmark_command (void) - { definition->unmark_command (); } - - bool is_command (void) const - { return definition->is_command (); } - - void mark_as_rawcommand (void) - { definition->mark_as_rawcommand (); } - - void unmark_rawcommand (void) - { definition->unmark_rawcommand (); } - - bool is_rawcommand (void) const - { return definition->is_rawcommand (); } - - bool is_mapper_function (void) const - { return definition->is_mapper_function (); } - - bool is_user_function (void) const - { return definition->is_user_function (); } - - bool is_builtin_function (void) const - { return definition->is_builtin_function (); } - - bool is_dld_function (void) const - { return definition->is_dld_function (); } - - bool is_mex_function (void) const - { return definition->is_mex_function (); } - - bool is_variable (void) const - { return definition->is_variable (); } - - bool is_user_variable (void) const - { return definition->is_user_variable (); } - - bool is_map_element (const std::string& elts) const - { return definition->is_map_element (elts); } - - unsigned int type (void) const { return definition->type (); } - - bool is_defined (void) const { return definition->is_defined (); } - - bool is_read_only (void) const { return definition->is_read_only (); } - - bool is_eternal (void) const { return eternal; } - - void protect (void) { definition->protect (); } - - void unprotect (void) { definition->unprotect (); } - - void make_eternal (void) { eternal = 1; } - - void hide (void) { visible = false; } - void show (void) { visible = true; } - bool is_visible (void) const { return visible; } - - void set_change_function (change_function f) { chg_fcn = f; } - - void define (const octave_value& v, unsigned int sym_type = USER_VARIABLE); - - bool define (octave_function *f, unsigned int sym_type); - - void document (const std::string& h) { definition->document (h); } - - void clear (void); - - void alias (symbol_record *s, bool mark_to_clear = false); - - void mark_as_formal_parameter (void); - bool is_formal_parameter (void) const { return formal_param; } - - void mark_as_automatic_variable (void); - bool is_automatic_variable (void) const { return automatic_variable; } - - void mark_as_linked_to_global (void); - bool is_linked_to_global (void) const { return linked_to_global; } - - void mark_as_static (void); - bool is_static (void) const { return tagged_static; } - void unmark_static (void) { tagged_static = false; } +#include "glob-match.h" - bool is_matrix_type (void) const - { return definition->is_matrix_type (); } - - bool is_sparse_type (void) const - { return definition->is_sparse_type (); } - - bool is_complex_type (void) const - { return definition->is_complex_type (); } - - std::string class_name (void) const - { return definition->class_name (); } - - Matrix size (void) const - { return definition->size (); } - - size_t byte_size (void) const - { return definition->byte_size (); }; - - octave_idx_type numel (void) const - { return definition->numel (); }; - - octave_idx_type capacity (void) const - { return definition->capacity (); }; - - dim_vector dims (void) const { return definition->dims (); } - - int dimensions_string_req_first_space (int print_dims) const; - - int dimensions_string_req_total_space (int print_dims) const; - - std::string make_dimensions_string (int print_dims) const; - - octave_idx_type rows (void) const { return definition->rows (); } - octave_idx_type columns (void) const { return definition->columns (); } - - std::string type_name (void) const { return definition->type_name (); } - - std::string type_as_string (void) const - { return definition->type_as_string (); } - - void type (std::ostream& os, bool pr_type_info, bool quiet, bool pr_orig_txt) - { definition->type (os, name (), pr_type_info, quiet, pr_orig_txt); } - - std::string which (void) { return definition->which (name ()); } - - void which (std::ostream& os) { definition->which (os, name ()); } - - octave_value& variable_value (void); - octave_lvalue variable_reference (void); - - symbol_record *next (void) const { return next_elem; } - - void chain (symbol_record *s) { next_elem = s; } - - void push_context (void); - - void pop_context (void); - - void print_symbol_info_line (std::ostream& os, - std::list& params) const; +class tree_argument_list; - void print_info (std::ostream& os, - const std::string& prefix = std::string ()) const; - -private: - - unsigned int formal_param : 1; - unsigned int automatic_variable : 1; - unsigned int linked_to_global : 1; - unsigned int tagged_static : 1; - unsigned int can_hide_function : 1; - unsigned int visible : 1; - unsigned int eternal : 1; - - std::string nm; - change_function chg_fcn; - symbol_def *definition; - symbol_record *next_elem; - - // This should maybe be one stack with a structure containing all the - // items we need to save for recursive calls... - std::stack context; - std::stack global_link_context; - - std::stack aliases_to_clear; - - void push_alias_to_clear (symbol_record *s) - { aliases_to_clear.push (s); } - - bool read_only_error (const char *action); - - void maybe_delete_def (void) - { - if (--definition->count <= 0) - delete definition; - } - - // No copying! - - symbol_record (const symbol_record& s); - - symbol_record& operator = (const symbol_record& s); -}; - -// A symbol table. - -#define SYMTAB_LOCAL_SCOPE 1 -#define SYMTAB_GLOBAL_SCOPE 2 - -#define SYMTAB_ALL_SCOPES (SYMTAB_LOCAL_SCOPE | SYMTAB_GLOBAL_SCOPE) - -#define SYMTAB_ALL_TYPES (symbol_record::USER_FUNCTION \ - | symbol_record::USER_VARIABLE \ - | symbol_record::DLD_FUNCTION \ - | symbol_record::BUILTIN_FUNCTION \ - | symbol_record::COMMAND \ - | symbol_record::RAWCOMMAND \ - | symbol_record::MAPPER_FUNCTION \ - | symbol_record::MEX_FUNCTION) - -#define SYMTAB_VARIABLES (symbol_record::USER_VARIABLE) +#include "oct-obj.h" +#include "ov.h" class OCTINTERP_API @@ -499,135 +44,1737 @@ { public: - symbol_table (unsigned int tab_size = 64, - const std::string& nm = std::string ()) - : table_size (tab_size), table (new symbol_record [table_size]), - table_name (nm) + typedef int scope_id; + + class + symbol_record + { + public: + + // generic variable + static const unsigned int local = 1; + + // varargin, argn, .nargin., .nargout. + // (FIXME -- is this really used now?) + static const unsigned int automatic = 2; + + // formal parameter + static const unsigned int formal = 4; + + // not listed or cleared (.nargin., .nargout.) + static const unsigned int hidden = 8; + + // inherited from parent scope; not cleared at function exit + static const unsigned int inherited = 16; + + // global (redirects to global scope) + static const unsigned int global = 32; + + // not cleared at function exit + static const unsigned int persistent = 64; + + private: + + class + symbol_record_rep { - assert ((tab_size % 2) == 0); + public: + + symbol_record_rep (const std::string& nm, const octave_value& v, + unsigned int sc) + : name (nm), value_stack (), storage_class (sc), count (1) + { + value_stack.push (v); + } + + octave_value& varref (void) { return value_stack.top (); } + + octave_value varval (void) const { return value_stack.top (); } + + void push_context (void) { value_stack.push (octave_value ()); } + + void pop_context (void) { value_stack.pop (); } + + void clear (void) + { + if (! (is_hidden () || is_inherited ())) + { + if (is_global ()) + unmark_global (); + + if (is_persistent ()) + { + symbol_table::persistent_varref (name) = varval (); + unmark_persistent (); + } + + varref () = octave_value (); + } + } + + bool is_defined (void) const { return varval ().is_defined (); } + + bool is_variable (void) const + { + return (storage_class != local || is_defined ()); + } + + bool is_local (void) const { return storage_class & local; } + bool is_automatic (void) const { return storage_class & automatic; } + bool is_formal (void) const { return storage_class & formal; } + bool is_hidden (void) const { return storage_class & hidden; } + bool is_inherited (void) const { return storage_class & inherited; } + bool is_global (void) const { return storage_class & global; } + bool is_persistent (void) const { return storage_class & persistent; } + + void mark_local (void) { storage_class |= local; } + void mark_automatic (void) { storage_class |= automatic; } + void mark_formal (void) { storage_class |= formal; } + void mark_hidden (void) { storage_class |= hidden; } + void mark_inherited (void) { storage_class |= inherited; } + void mark_global (void) + { + if (is_persistent ()) + error ("can't make persistent variable %s global", name.c_str ()); + else + storage_class |= global; + } + void mark_persistent (void) + { + if (is_global ()) + error ("can't make global variable %s persistent", name.c_str ()); + else + storage_class |= persistent; + } + + void unmark_local (void) { storage_class &= ~local; } + void unmark_automatic (void) { storage_class &= ~automatic; } + void unmark_formal (void) { storage_class &= ~formal; } + void unmark_hidden (void) { storage_class &= ~hidden; } + void unmark_inherited (void) { storage_class &= ~inherited; } + void unmark_global (void) { storage_class &= ~global; } + void unmark_persistent (void) { storage_class &= ~persistent; } + + void init_persistent (void) + { + if (! is_defined ()) + { + mark_persistent (); + + varref () = symbol_table::persistent_varval (name); + } + // FIXME -- this causes trouble with recursive calls. + // else + // error ("unable to declare existing variable persistent"); + } + + void erase_persistent (void) + { + unmark_persistent (); + symbol_table::erase_persistent (name); + } + + symbol_record_rep *dup (void) + { + return new symbol_record_rep (name, varval (), storage_class); + } + + std::string name; + + std::stack value_stack; + + unsigned int storage_class; + + size_t count; + + private: + + // No copying! + + symbol_record_rep (const symbol_record_rep& ov); + + symbol_record_rep& operator = (const symbol_record_rep&); + }; + + public: + + symbol_record (const std::string& nm = std::string (), + const octave_value& v = octave_value (), + unsigned int sc = local) + : rep (new symbol_record_rep (nm, v, sc)) { } + + symbol_record (const symbol_record& sr) + : rep (sr.rep) + { + rep->count++; + } + + symbol_record& operator = (const symbol_record& sr) + { + if (this != &sr) + { + rep = sr.rep; + rep->count++; + } + + return *this; + } + + ~symbol_record (void) + { + if (--rep->count == 0) + delete rep; + } + + symbol_record dup (void) const { return symbol_record (rep->dup ()); } + + std::string name (void) const { return rep->name; } + + octave_value + find (tree_argument_list *args, const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated) const; + + octave_value& varref (void) + { + return is_global () + ? symbol_table::varref (name (), symbol_table::global_scope ()) + : rep->varref (); + } + + octave_value varval (void) const + { + return is_global () + ? symbol_table::varval (name (), symbol_table::global_scope ()) + : rep->varval (); + } + + void push_context (void) + { + if (! (is_persistent () || is_global ())) + rep->push_context (); + } + + void pop_context (void) + { + if (! (is_persistent () || is_global ())) + rep->pop_context (); + } + + void clear (void) { rep->clear (); } + + bool is_defined (void) const { return rep->is_defined (); } + bool is_variable (void) const { return rep->is_variable (); } + + bool is_local (void) const { return rep->is_local (); } + bool is_automatic (void) const { return rep->is_automatic (); } + bool is_formal (void) const { return rep->is_formal (); } + bool is_global (void) const { return rep->is_global (); } + bool is_hidden (void) const { return rep->is_hidden (); } + bool is_inherited (void) const { return rep->is_inherited (); } + bool is_persistent (void) const { return rep->is_persistent (); } + + void mark_local (void) { rep->mark_local (); } + void mark_automatic (void) { rep->mark_automatic (); } + void mark_formal (void) { rep->mark_formal (); } + void mark_hidden (void) { rep->mark_hidden (); } + void mark_inherited (void) { rep->mark_inherited (); } + void mark_global (void) { rep->mark_global (); } + void mark_persistent (void) { rep->mark_persistent (); } + + void unmark_local (void) { rep->unmark_local (); } + void unmark_automatic (void) { rep->unmark_automatic (); } + void unmark_formal (void) { rep->unmark_formal (); } + void unmark_hidden (void) { rep->unmark_hidden (); } + void unmark_inherited (void) { rep->unmark_inherited (); } + void unmark_global (void) { rep->unmark_global (); } + void unmark_persistent (void) { rep->unmark_persistent (); } + + void init_persistent (void) { rep->init_persistent (); } + + void erase_persistent (void) { rep->erase_persistent (); } + + unsigned int xstorage_class (void) const { return rep->storage_class; } + + private: + + symbol_record_rep *rep; + + symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { } + }; + + class + fcn_info + { + public: + + typedef std::map dispatch_map_type; + + typedef std::map::const_iterator const_scope_val_iterator; + typedef std::map::iterator scope_val_iterator; - if (table_name.empty ()) + typedef std::map::const_iterator const_str_val_iterator; + typedef std::map::iterator str_val_iterator; + + typedef dispatch_map_type::const_iterator const_dispatch_map_iterator; + typedef dispatch_map_type::iterator dispatch_map_iterator; + + private: + + class + fcn_info_rep + { + public: + + fcn_info_rep (const std::string& nm) + : name (nm), subfunctions (), private_functions (), + class_constructors (), class_methods (), cmdline_function (), + autoload_function (), function_on_path (), built_in_function (), + count (1) { } + + octave_value load_private_function (const std::string& dir_name); + + octave_value load_class_constructor (void); + + octave_value load_class_method (const std::string& dispatch_type); + + octave_value + find (tree_argument_list *args, const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope); + + octave_value find_method (const std::string& dispatch_type); + + octave_value find_autoload (void); + + octave_value find_user_function (void); + + bool is_user_function_defined (void) const + { + return function_on_path.is_defined (); + } + + octave_value find_function (scope_id scope) + { + octave_value_list args; + + return find_function (args, scope); + } + + octave_value find_function (const octave_value_list& args, + scope_id scope) + { + string_vector arg_names; + octave_value_list evaluated_args = args; + bool args_evaluated; + + return find (0, arg_names, evaluated_args, args_evaluated, scope); + } + + void install_cmdline_function (const octave_value& f) + { + cmdline_function = f; + } + + void install_subfunction (const octave_value& f, scope_id scope) + { + subfunctions[scope] = f; + } + + void install_user_function (const octave_value& f) + { + function_on_path = f; + } + + void install_built_in_function (const octave_value& f) + { + built_in_function = f; + } + + void clear (void) + { + subfunctions.clear (); + private_functions.clear (); + class_constructors.clear (); + class_methods.clear (); + cmdline_function = octave_value (); + autoload_function = octave_value (); + function_on_path = octave_value (); + } + + // FIXME -- should this also clear the cmdline and other "user + // defined" functions? + void clear_user_function (void) + { + function_on_path = octave_value (); + } + + void clear_mex_function (void) + { + if (function_on_path.is_mex_function ()) + function_on_path = octave_value (); + } + + void add_dispatch (const std::string& type, const std::string& fname) + { + dispatch_map[type] = fname; + } + + void clear_dispatch (const std::string& type) + { + dispatch_map_iterator p = dispatch_map.find (type); + + if (p != dispatch_map.end ()) + dispatch_map.erase (p); + } + + void print_dispatch (std::ostream& os) const; + + std::string help_for_dispatch (void) const; + + dispatch_map_type get_dispatch (void) const { return dispatch_map; } + + std::string name; + + // Scope id to function object. + std::map subfunctions; + + // Directory name to function object. + std::map private_functions; + + // Class name to function object. + std::map class_constructors; + + // Dispatch type to function object. + std::map class_methods; + + // Legacy dispatch map (dispatch type name to function name). + dispatch_map_type dispatch_map; + + octave_value cmdline_function; + + octave_value autoload_function; + + octave_value function_on_path; + + octave_value built_in_function; + + size_t count; + + private: + + // No copying! + + fcn_info_rep (const fcn_info_rep&); + + fcn_info_rep& operator = (const fcn_info_rep&); + }; + + public: + + fcn_info (const std::string& nm = std::string ()) + : rep (new fcn_info_rep (nm)) { } + + fcn_info (const fcn_info& ov) : rep (ov.rep) + { + rep->count++; + } + + fcn_info& operator = (const fcn_info& ov) + { + if (this != &ov) { - std::ostringstream buf; - buf << symtab_count++; - table_name = buf.str (); + rep = ov.rep; + rep->count++; } + + return *this; + } + + ~fcn_info (void) + { + if (--rep->count == 0) + delete rep; + } + + octave_value + find (tree_argument_list *args, const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope); + + octave_value find_method (const std::string& dispatch_type) const + { + return rep->find_method (dispatch_type); + } + + octave_value find_built_in_function (void) const + { + return rep->built_in_function; + } + + octave_value find_autoload (void) + { + return rep->find_autoload (); + } + + octave_value find_user_function (void) + { + return rep->find_user_function (); + } + + bool is_user_function_defined (void) const + { + return rep->is_user_function_defined (); + } + + octave_value find_function (scope_id scope) + { + return rep->find_function (scope); + } + + octave_value find_function (const octave_value_list& args, + scope_id scope) + { + return rep->find_function (args, scope); + } + + void install_cmdline_function (const octave_value& f) + { + rep->install_cmdline_function (f); + } + + void install_subfunction (const octave_value& f, scope_id scope) + { + rep->install_subfunction (f, scope); + } + + void install_user_function (const octave_value& f) + { + rep->install_user_function (f); + } + + void install_built_in_function (const octave_value& f) + { + rep->install_built_in_function (f); + } + + void clear (void) { rep->clear (); } + + void clear_user_function (void) { rep->clear_user_function (); } + + void clear_mex_function (void) { rep->clear_mex_function (); } + + void add_dispatch (const std::string& type, const std::string& fname) + { + rep->add_dispatch (type, fname); + } + + void clear_dispatch (const std::string& type) + { + rep->clear_dispatch (type); + } + + void print_dispatch (std::ostream& os) const + { + rep->print_dispatch (os); + } + + std::string help_for_dispatch (void) const { return rep->help_for_dispatch (); } + + dispatch_map_type get_dispatch (void) const + { + return rep->get_dispatch (); } - ~symbol_table (void); + private: + + fcn_info_rep *rep; + }; + + static scope_id global_scope (void) { return xglobal_scope; } + static scope_id top_scope (void) { return xtop_scope; } + + static scope_id current_scope (void) { return xcurrent_scope; } + static scope_id current_caller_scope (void) { return xcurrent_caller_scope; } + + // We use parent_scope to handle parsing subfunctions. + static scope_id parent_scope (void) { return xparent_scope; } + + static scope_id alloc_scope (void) + { + scope_id retval; + + scope_ids_free_list_iterator p = scope_ids_free_list.begin (); + + if (p != scope_ids_free_list.end ()) + { + retval = *p; + scope_ids_free_list.erase (p); + } + else + retval = next_available_scope++; + + scope_ids_in_use.insert (retval); + + return retval; + } + + static void set_scope (scope_id scope) + { + if (scope == xglobal_scope) + error ("can't set scope to global"); + else if (scope != xcurrent_scope) + { + all_instances_iterator p = all_instances.find (scope); + + if (p == all_instances.end ()) + { + instance = new symbol_table (); - symbol_record *lookup (const std::string& nm, bool insert = false, - bool warn = false); + all_instances[scope] = instance; + } + else + instance = p->second; + + xcurrent_scope = scope; + } + } + + static void push_scope (scope_id scope) + { + if (scope_stack.empty ()) + scope_stack.push_front (xtop_scope); + + xcurrent_caller_scope = xcurrent_scope; + + set_scope (scope); + + scope_stack.push_front (scope); + } + + static void pop_scope (void) + { + scope_stack.pop_front (); - void rename (const std::string& old_name, const std::string& new_name); + set_scope (scope_stack[0]); + + xcurrent_caller_scope = scope_stack[1]; + } + + static void pop_scope (void *) { pop_scope (); } + + static void reset_scope (void) + { + scope_stack.clear (); + + scope_stack.push_front (xtop_scope); - void clear (void); + set_scope (xtop_scope); + + xcurrent_caller_scope = -1; + } + + static void set_parent_scope (scope_id scope) + { + xparent_scope = scope; + } + + static void reset_parent_scope (void) + { + set_parent_scope (-1); + } - void clear_variables (void); - void clear_functions (void); - void clear_mex_functions (void); - void clear_globals (void); + static void erase_scope (scope_id scope = xcurrent_scope) + { + all_instances_iterator p = all_instances.find (scope); + + if (p != all_instances.end ()) + all_instances.erase (p); + + // free_scope (scope); + } + + static scope_id dup_scope (scope_id scope = xcurrent_scope) + { + scope_id retval = -1; + + symbol_table *inst = get_instance (scope); + + if (inst) + { + scope_id new_scope = alloc_scope (); + + symbol_table *new_symbol_table = new symbol_table (); + + if (new_symbol_table) + { + all_instances[new_scope] = new_symbol_table; + + inst->do_dup_scope (*new_symbol_table); + + retval = new_scope; + } + } + + return retval; + } + +#if 0 + static void print_scope (const std::string& tag, scope_id scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + { + std::cerr << "printing " << tag << ", scope: " << scope + << ", inst: " << inst << std::endl; + + inst->do_print_scope (std::cerr); + } + } - bool clear (const std::string& nm); + void do_print_scope (std::ostream& os) const + { + for (const_table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record sr = p->second; + + octave_value val = sr.varval (); + + if (val.is_defined ()) + sr.varval ().print_with_name (os, sr.name ()); + else + os << sr.name () << " is not defined" << std::endl; + } + } +#endif + + static symbol_record find_symbol (const std::string& name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_find_symbol (name) : symbol_record (); + } - bool clear_variable (const std::string& nm); - bool clear_function (const std::string& nm); - bool clear_global (const std::string& nm); + static void inherit (scope_id scope, scope_id donor_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_inherit (donor_scope); + } + + static bool at_top_level (void) { return xcurrent_scope == xtop_scope; } + + // Find a value corresponding to the given name in the table. + static octave_value + find (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope = xcurrent_scope, bool skip_variables = false); + + // Insert a new name in the table. + static symbol_record& + insert (const std::string& name, scope_id scope = xcurrent_scope) + { + static symbol_record foobar; + + symbol_table *inst = get_instance (scope); - bool clear_variable_pattern (const std::string& pat); - bool clear_function_pattern (const std::string& pat); - bool clear_global_pattern (const std::string& pat); + return inst ? inst->do_insert (name) : foobar; + } + + static octave_value& + varref (const std::string& name, scope_id scope = xcurrent_scope) + { + static octave_value foobar; + + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_varref (name) : foobar; + } + + static octave_value + varval (const std::string& name, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_varval (name) : octave_value (); + } + + static octave_value& + persistent_varref (const std::string& name, scope_id scope = xcurrent_scope) + { + static octave_value foobar; + + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_persistent_varref (name) : foobar; + } + + static octave_value + persistent_varval (const std::string& name, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_persistent_varval (name) : octave_value (); + } + + static void + erase_persistent (const std::string& name, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_erase_persistent (name); + } - int size (void) const; + static bool + is_variable (const std::string& name, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_is_variable (name) : false; + } + + static bool + is_built_in_function_name (const std::string& name) + { + octave_value val = find_built_in_function (name); + + return val.is_defined (); + } + + static octave_value + find_method (const std::string& name, const std::string& dispatch_type) + { + const_fcn_table_iterator p = fcn_table.find (name); - Array - subsymbol_list (const string_vector& pats = string_vector (), - unsigned int type = SYMTAB_ALL_TYPES, - unsigned int scope = SYMTAB_ALL_SCOPES) const; + if (p != fcn_table.end ()) + return p->second.find_method (dispatch_type); + else + { + fcn_info finfo (name); + + octave_value fcn = finfo.find_method (dispatch_type); + + if (fcn.is_defined ()) + fcn_table[name] = finfo; + + return fcn; + } + } + + static octave_value + find_built_in_function (const std::string& name) + { + const_fcn_table_iterator p = fcn_table.find (name); + + return (p != fcn_table.end ()) + ? p->second.find_built_in_function () : octave_value (); + } + + static octave_value + find_autoload (const std::string& name) + { + fcn_table_iterator p = fcn_table.find (name); - Array - symbol_list (const string_vector& pats = string_vector (), - unsigned int type = SYMTAB_ALL_TYPES, - unsigned int scope = SYMTAB_ALL_SCOPES) const; + return (p != fcn_table.end ()) + ? p->second.find_autoload () : octave_value (); + } + + static octave_value + find_function (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope = xcurrent_scope); + + static octave_value + find_user_function (const std::string& name) + { + fcn_table_iterator p = fcn_table.find (name); + + return (p != fcn_table.end ()) + ? p->second.find_user_function () : octave_value (); + } + + static octave_value + find_function (const std::string& name, scope_id scope = xcurrent_scope) + { + octave_value_list evaluated_args; + + return find_function (name, evaluated_args, scope); + } + + static octave_value + find_function (const std::string& name, const octave_value_list& args, + scope_id scope = xcurrent_scope) + { + string_vector arg_names; + octave_value_list evaluated_args = args; + bool args_evaluated = ! args.empty (); + + return find_function (name, 0, arg_names, evaluated_args, + args_evaluated, scope); + } + + static void install_cmdline_function (const std::string& name, + const octave_value& fcn) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + finfo.install_cmdline_function (fcn); + } + else + { + fcn_info finfo (name); - string_vector - name_list (const string_vector& pats = string_vector (), - bool sort = false, unsigned int type = SYMTAB_ALL_TYPES, - unsigned int scope = SYMTAB_ALL_SCOPES) const; + finfo.install_cmdline_function (fcn); + + fcn_table[name] = finfo; + } + } + + static void install_subfunction (const std::string& name, + const octave_value& fcn, + scope_id scope = xparent_scope) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.install_subfunction (fcn, scope); + } + else + { + fcn_info finfo (name); + + finfo.install_subfunction (fcn, scope); + + fcn_table[name] = finfo; + } + } + + static void install_user_function (const std::string& name, + const octave_value& fcn) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.install_user_function (fcn); + } + else + { + fcn_info finfo (name); + + finfo.install_user_function (fcn); + + fcn_table[name] = finfo; + } + } - string_vector - user_function_name_list (void) const - { - return name_list - (string_vector (), false, - symbol_record::USER_FUNCTION|symbol_record::DLD_FUNCTION|symbol_record::MEX_FUNCTION, - SYMTAB_ALL_SCOPES); - } + static void install_built_in_function (const std::string& name, + const octave_value& fcn) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.install_built_in_function (fcn); + } + else + { + fcn_info finfo (name); + + finfo.install_built_in_function (fcn); + + fcn_table[name] = finfo; + } + } + + static void clear (const std::string& name, scope_id scope = xcurrent_scope) + { + clear_variable (name, scope); + } + + static void clear_all (void) + { + clear_variables (); + + clear_functions (); + } + + static void clear_variables (scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_variables (); + } + + // For unwind_protect. + static void clear_variables (void *) { clear_variables (); } + + static void clear_functions (void) + { + for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) + p->second.clear (); + } + + static void clear_function (const std::string& name) + { + clear_user_function (name); + } + + static void clear_global (const std::string& name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_global (name); + } + + static void clear_variable (const std::string& name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_variable (name); + } + + static void clear_symbol (const std::string& name) + { + // FIXME -- are we supposed to do both here? + + clear_variable (name); + clear_function (name); + } + + static void clear_function_pattern (const std::string& pat) + { + glob_match pattern (pat); + + for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) + { + if (pattern.match (p->first)) + p->second.clear_user_function (); + } + } + + static void clear_global_pattern (const std::string& pat, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); - string_vector - global_variable_name_list (void) const - { - return name_list - (string_vector (), false, SYMTAB_VARIABLES, SYMTAB_GLOBAL_SCOPE); - } + if (inst) + inst->do_clear_global_pattern (pat); + } + + static void clear_variable_pattern (const std::string& pat, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_variable_pattern (pat); + } + + static void clear_symbol_pattern (const std::string& pat) + { + // FIXME -- are we supposed to do both here? + + clear_variable_pattern (pat); + clear_function_pattern (pat); + } + + static void clear_user_function (const std::string& name) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.clear_user_function (); + } + // FIXME -- is this necessary, or even useful? + // else + // error ("clear: no such function `%s'", name.c_str ()); + } + + static void clear_mex_functions (void) + { + for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) + { + fcn_info& finfo = p->second; + + finfo.clear_mex_function (); + } + } + + static void alias_built_in_function (const std::string& alias, + const std::string& name) + { + octave_value fcn = find_built_in_function (name); + + if (fcn.is_defined ()) + { + fcn_info finfo (alias); + + finfo.install_built_in_function (fcn); + + fcn_table[alias] = finfo; + } + else + panic ("alias: `%s' is undefined", name.c_str ()); + } + + static void add_dispatch (const std::string& name, const std::string& type, + const std::string& fname) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.add_dispatch (type, fname); + } + else + { + fcn_info finfo (name); + + finfo.add_dispatch (type, fname); + + fcn_table[name] = finfo; + } + } + + static void clear_dispatch (const std::string& name, const std::string& type) + { + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.clear_dispatch (type); + } + } + + static void print_dispatch (std::ostream& os, const std::string& name) + { + fcn_table_iterator p = fcn_table.find (name); - string_vector - variable_name_list (void) const - { - return name_list - (string_vector (), false, SYMTAB_VARIABLES, SYMTAB_LOCAL_SCOPE); - } + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + finfo.print_dispatch (os); + } + } + + static fcn_info::dispatch_map_type get_dispatch (const std::string& name) + { + fcn_info::dispatch_map_type retval; + + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + retval = finfo.get_dispatch (); + } + + return retval; + } + + static std::string help_for_dispatch (const std::string& name) + { + std::string retval; + + fcn_table_iterator p = fcn_table.find (name); + + if (p != fcn_table.end ()) + { + fcn_info& finfo = p->second; + + retval = finfo.help_for_dispatch (); + } + + return retval; + } + + static void push_context (scope_id scope = xcurrent_scope) + { + if (scope == xglobal_scope || scope == xtop_scope) + error ("invalid call to xymtab::push_context"); + else + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_push_context (); + } + } + + static void pop_context (scope_id scope = xcurrent_scope) + { + if (scope == xglobal_scope || scope == xtop_scope) + error ("invalid call to xymtab::push_context"); + else + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_pop_context (); + } + } + + // For unwind_protect. + static void pop_context (void *) { pop_context (); } + + static void mark_hidden (const std::string& name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_mark_hidden (name); + } + + static void mark_global (const std::string& name, + scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_mark_global (name); + } + + static std::list + all_variables (scope_id scope = xcurrent_scope, bool defined_only = true) + { + symbol_table *inst = get_instance (scope); + + return inst + ? inst->do_all_variables (defined_only) : std::list (); + } - int maybe_list (const char *header, const string_vector& argv, - std::ostream& os, bool show_verbose, - unsigned type, unsigned scope); - - Array glob (const std::string& pat = std::string ("*"), - unsigned int type = SYMTAB_ALL_TYPES, - unsigned int scope = SYMTAB_ALL_SCOPES) const; + static std::list + glob (const std::string& pattern, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_glob (pattern) : std::list (); + } + + static std::list + glob_variables (const std::string& pattern, scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_glob (pattern, true) : std::list (); + } + + static std::list + glob_variables (const string_vector& patterns, + scope_id scope = xcurrent_scope) + { + std::list retval; + + size_t len = patterns.length (); - void push_context (void); + for (size_t i = 0; i < len; i++) + { + std::list tmp = glob_variables (patterns[i], scope); + + retval.insert (retval.begin (), tmp.begin (), tmp.end ()); + } + + return retval; + } + + static std::list user_function_names (void) + { + std::list retval; + + for (fcn_table_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + if (p->second.is_user_function_defined ()) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); + + return retval; + } - void pop_context (void); + static std::list + variable_names (scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_variable_names () : std::list (); + } + + static std::list built_in_function_names (void) + { + std::list retval; + + for (const_fcn_table_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + octave_value fcn = p->second.find_built_in_function (); + + if (fcn.is_defined ()) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); - // Create a new symbol table with the same entries. Only the symbol - // names and some attributes are copied, not values. - symbol_table *dup (void); + return retval; + } + + static bool is_local_variable (const std::string& name, + scope_id scope = xcurrent_scope) + { + if (scope == xglobal_scope) + return false; + else + { + symbol_table *inst = get_instance (scope); - // Inherit some values from the parent_sym_tab. - void inherit (symbol_table *parent_sym_tab); + return inst ? inst->do_is_local_variable (name) : false; + } + } - void print_info (std::ostream& os) const; + static bool is_global (const std::string& name, + scope_id scope = xcurrent_scope) + { + if (scope == xglobal_scope) + return true; + else + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_is_global (name) : false; + } + } private: - unsigned int table_size; + typedef std::map::const_iterator const_table_iterator; + typedef std::map::iterator table_iterator; + + typedef std::map::const_iterator const_persistent_table_iterator; + typedef std::map::iterator persistent_table_iterator; + + typedef std::map::const_iterator all_instances_const_iterator; + typedef std::map::iterator all_instances_iterator; + + typedef std::map::const_iterator const_fcn_table_iterator; + typedef std::map::iterator fcn_table_iterator; + + typedef std::set::const_iterator scope_ids_free_list_const_iterator; + typedef std::set::iterator scope_ids_free_list_iterator; + + typedef std::set::const_iterator scope_ids_in_use_const_iterator; + typedef std::set::iterator scope_ids_in_use_iterator; + + // Map from symbol names to symbol info. + std::map table; + + // Map from names of persistent variables to values. + std::map persistent_table; + + // Pointer to symbol table for current scope (variables only). + static symbol_table *instance; - symbol_record *table; + // Map from scope id to symbol table instances. + static std::map all_instances; + + // Map from function names to function info (subfunctions, private + // functions, class constructors, class methods, etc.) + static std::map fcn_table; + + static const scope_id xglobal_scope; + static const scope_id xtop_scope; + + static scope_id xcurrent_scope; + static scope_id xcurrent_caller_scope; + + // We use parent_scope to handle parsing subfunctions. + static scope_id xparent_scope; + + static std::deque scope_stack; + + // The next available scope ID. + static scope_id next_available_scope; + + // The set of scope IDs that are currently allocated. + static std::set scope_ids_in_use; + + // The set of scope IDs that are currently available. + static std::set scope_ids_free_list; + + symbol_table (void) : table () { } + + ~symbol_table (void) { } - std::string table_name; + static void free_scope (scope_id scope) + { + if (scope == xglobal_scope || scope == xtop_scope) + error ("can't free global or top-level scopes!"); + else + { + scope_ids_in_use_iterator p = scope_ids_in_use.find (scope); + + if (p != scope_ids_in_use.end ()) + { + scope_ids_in_use.erase (p); + scope_ids_free_list.insert (*p); + } + else + error ("scope id = %ld not found!", scope); + } + } + + static symbol_table *get_instance (scope_id scope) + { + symbol_table *retval = 0; + + if (scope == xcurrent_scope) + { + if (! instance) + { + instance = new symbol_table (); - static unsigned long int symtab_count; + all_instances[scope] = instance; + } + + if (! instance) + error ("unable to create symbol_table object!"); + + retval = instance; + } + else + { + all_instances_iterator p = all_instances.find (scope); + + if (p == all_instances.end ()) + { + retval = new symbol_table (); + + all_instances[scope] = retval; + } + else + retval = p->second; + } + + return retval; + } + + void insert_symbol_record (const symbol_record& sr) + { + table[sr.name ()] = sr; + } void - print_descriptor (std::ostream& os, - std::list params) const; + do_dup_scope (symbol_table& new_symbol_table) const + { + for (const_table_iterator p = table.begin (); p != table.end (); p++) + new_symbol_table.insert_symbol_record (p->second.dup ()); + } + + symbol_record do_find_symbol (const std::string& name) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + return do_insert (name); + else + return p->second; + } + + void do_inherit (scope_id donor_scope) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record& sr = p->second; + + std::string nm = sr.name (); + + if (! (sr.is_automatic () || sr.is_formal () || nm == "__retval__")) + { + octave_value val = symbol_table::varval (nm, donor_scope); + + if (val.is_defined ()) + { + sr.varref () = val; + + sr.mark_inherited (); + } + } + } + } + + octave_value + do_find (const std::string& name, tree_argument_list *args, + const string_vector& arg_names, + octave_value_list& evaluated_args, bool& args_evaluated, + scope_id scope, bool skip_variables); + + symbol_record& do_insert (const std::string& name) + { + table_iterator p = table.find (name); + + return p == table.end () + ? (table[name] = symbol_record (name)) : p->second; + } + + octave_value& do_varref (const std::string& name) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + { + symbol_record& sr = do_insert (name); + + return sr.varref (); + } + else + return p->second.varref (); + } - std::list - parse_whos_line_format (Array& symbols) const; + octave_value do_varval (const std::string& name) const + { + const_table_iterator p = table.find (name); + + return (p != table.end ()) ? p->second.varval () : octave_value (); + } + + octave_value& do_persistent_varref (const std::string& name) + { + persistent_table_iterator p = persistent_table.find (name); + + return (p == persistent_table.end ()) + ? persistent_table[name] : p->second; + } + + octave_value do_persistent_varval (const std::string& name) + { + const_persistent_table_iterator p = persistent_table.find (name); + + return (p != persistent_table.end ()) ? p->second : octave_value (); + } + + void do_erase_persistent (const std::string& name) + { + persistent_table_iterator p = persistent_table.find (name); + + if (p != persistent_table.end ()) + persistent_table.erase (p); + } + + bool do_is_variable (const std::string& name) const + { + bool retval = false; + + const_table_iterator p = table.find (name); + + if (p != table.end ()) + { + const symbol_record& sr = p->second; + + retval = sr.is_variable (); + } + + return retval; + } + + void do_push_context (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + p->second.push_context (); + } + + void do_pop_context (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + p->second.pop_context (); + } + + void do_clear_variables (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + p->second.clear (); + } + + void do_clear_global (const std::string& name) + { + table_iterator p = table.find (name); - unsigned int hash (const std::string& s); + if (p != table.end ()) + { + symbol_record& sr = p->second; + + if (sr.is_global ()) + { + symbol_table::clear_variable (p->first, xglobal_scope); + + sr.unmark_global (); + } + } + } + + void do_clear_variable (const std::string& name) + { + table_iterator p = table.find (name); + + if (p != table.end ()) + p->second.clear (); + } + + void do_clear_global_pattern (const std::string& pat) + { + glob_match pattern (pat); + + for (table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record& sr = p->second; - // No copying! + if (sr.is_global ()) + { + if (pattern.match (sr.name ())) + { + symbol_table::clear_variable (p->first, xglobal_scope); + + sr.unmark_global (); + } + } + } + } + + void do_clear_variable_pattern (const std::string& pat) + { + glob_match pattern (pat); + + for (table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record& sr = p->second; + + if (sr.is_defined () || sr.is_global ()) + { + if (pattern.match (sr.name ())) + sr.clear (); + } + } + } + + void do_mark_hidden (const std::string& name) + { + table_iterator p = table.find (name); + + if (p != table.end ()) + p->second.mark_hidden (); + } + + void do_mark_global (const std::string& name) + { + table_iterator p = table.find (name); - symbol_table (const symbol_table&); + if (p != table.end ()) + p->second.mark_global (); + } + + std::list do_all_variables (bool defined_only) const + { + std::list retval; + + for (const_table_iterator p = table.begin (); p != table.end (); p++) + { + const symbol_record& sr = p->second; + + if (defined_only && ! sr.is_defined ()) + continue; + + retval.push_back (sr); + } + + return retval; + } + + std::list do_glob (const std::string& pattern, + bool vars_only = false) const + { + std::list retval; + + glob_match pat (pattern); + + for (const_table_iterator p = table.begin (); p != table.end (); p++) + { + if (pat.match (p->first)) + { + const symbol_record& sr = p->second; - symbol_table& operator = (const symbol_table&); + if (vars_only && ! sr.is_variable ()) + continue; + + retval.push_back (sr); + } + } + + return retval; + } + + std::list do_variable_names (void) + { + std::list retval; + + for (const_table_iterator p = table.begin (); p != table.end (); p++) + retval.push_back (p->first); + + retval.sort (); + + return retval; + } + + bool do_is_local_variable (const std::string& name) const + { + const_table_iterator p = table.find (name); + + return (p != table.end () + && ! p->second.is_global () + && p->second.is_defined ()); + } + + bool do_is_global (const std::string& name) const + { + const_table_iterator p = table.find (name); + + return p != table.end () && p->second.is_global (); + } }; -// Defines layout for the whos/who -long command. -extern std::string Vwhos_line_format; +extern bool out_of_date_check (octave_value& function); #endif diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/token.cc --- a/src/token.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/token.cc Fri Dec 28 20:56:58 2007 +0000 @@ -73,7 +73,7 @@ pt = t; } -token::token (symbol_record *s, int l, int c) +token::token (symbol_table::symbol_record *s, int l, int c) { line_num = l; column_num = c; @@ -115,7 +115,7 @@ return pt; } -symbol_record * +symbol_table::symbol_record * token::sym_rec (void) { assert (type_tag == sym_rec_token); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/token.h --- a/src/token.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/token.h Fri Dec 28 20:56:58 2007 +0000 @@ -26,7 +26,7 @@ #include -class symbol_record; +class symbol_table::symbol_record; class token @@ -68,7 +68,7 @@ int l = -1, int c = -1); token (end_tok_type t, int l = -1, int c = -1); token (plot_tok_type t, int l = -1, int c = -1); - token (symbol_record *s, int l = -1, int c = -1); + token (symbol_table::symbol_record *s, int l = -1, int c = -1); ~token (void); @@ -79,7 +79,7 @@ double number (void); end_tok_type ettype (void); plot_tok_type pttype (void); - symbol_record *sym_rec (void); + symbol_table::symbol_record *sym_rec (void); std::string text_rep (void); @@ -100,7 +100,7 @@ double num; end_tok_type et; plot_tok_type pt; - symbol_record *sr; + symbol_table::symbol_record *sr; }; std::string orig_text; }; diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/toplev.cc --- a/src/toplev.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/toplev.cc Fri Dec 28 20:56:58 2007 +0000 @@ -209,7 +209,7 @@ { try { - curr_sym_tab = top_level_sym_tab; + symbol_table::reset_scope (); reset_error_handler (); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/unwind-prot.h --- a/src/unwind-prot.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/unwind-prot.h Fri Dec 28 20:56:58 2007 +0000 @@ -81,7 +81,7 @@ { public: - static void add (unwind_elem::cleanup_func fptr, void *ptr); + static void add (unwind_elem::cleanup_func fptr, void *ptr = 0); static void run (void); diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/variables.cc --- a/src/variables.cc Fri Feb 01 23:56:51 2008 -0500 +++ b/src/variables.cc Fri Dec 28 20:56:58 2007 +0000 @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -63,51 +64,32 @@ // since they were last compiled? static int Vignore_function_time_stamp = 1; -// Symbol table for symbols at the top level. -symbol_table *top_level_sym_tab = 0; - -// Symbol table for the current scope. -symbol_table *curr_sym_tab = 0; - -// Symbol table for the current caller scope. -symbol_table *curr_caller_sym_tab = 0; - -// Symbol table for global symbols. -symbol_table *global_sym_tab = 0; - -// Symbol table for functions and built-in symbols. -symbol_table *fbi_sym_tab = 0; - -bool -at_top_level (void) -{ - return (curr_sym_tab == top_level_sym_tab); -} - -// Initialization. - -// Create the initial symbol tables and set the current scope at the -// top level. - -void -initialize_symbol_tables (void) -{ - if (! fbi_sym_tab) - fbi_sym_tab = new symbol_table (2048, "FBI"); - - if (! global_sym_tab) - global_sym_tab = new symbol_table (2048, "GLOBAL"); - - if (! top_level_sym_tab) - top_level_sym_tab = new symbol_table (4096, "TOP"); - - curr_caller_sym_tab = curr_sym_tab = top_level_sym_tab; -} +// Defines layout for the whos/who -long command +static std::string Vwhos_line_format + = " %a:4; %ln:6; %cs:16:6:8:1; %rb:12; %lc:-1;\n"; void clear_mex_functions (void) { - fbi_sym_tab->clear_mex_functions (); + symbol_table::clear_mex_functions (); +} + +void +clear_function (const std::string& nm) +{ + symbol_table::clear_function (nm); +} + +void +clear_variable (const std::string& nm) +{ + symbol_table::clear_variable (nm); +} + +void +clear_symbol (const std::string& nm) +{ + symbol_table::clear_symbol (nm); } // Attributes of variables and functions. @@ -116,13 +98,7 @@ static std::set command_set; -static inline bool -is_marked_as_command (const std::string& s) -{ - return command_set.find (s) != command_set.end (); -} - -static inline void +void mark_as_command (const std::string& s) { command_set.insert (s); @@ -132,11 +108,6 @@ unmark_command (const std::string& s) { command_set.erase (s); - - symbol_record *sr = fbi_sym_tab->lookup (s); - - if (sr) - sr->unmark_command (); } DEFCMD (mark_as_command, args, , @@ -148,7 +119,7 @@ { octave_value_list retval; - if (at_top_level ()) + if (symbol_table::at_top_level ()) { int nargin = args.length (); @@ -182,7 +153,7 @@ { octave_value_list retval; - if (at_top_level ()) + if (symbol_table::at_top_level ()) { int nargin = args.length (); @@ -210,26 +181,10 @@ bool is_command_name (const std::string& s) { - bool retval = false; - - symbol_record *sr = fbi_sym_tab->lookup (s); - - if (sr) - { - if (sr->is_command ()) - retval = true; - else if (is_marked_as_command (s)) - { - sr->mark_as_command (); - retval = true; - } - } - else - retval = is_marked_as_command (s); - - return retval; + return command_set.find (s) != command_set.end (); } + DEFCMD (iscommand, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} iscommand (@var{name})\n\ @@ -274,12 +229,6 @@ static std::set rawcommand_set; -bool -is_marked_as_rawcommand (const std::string& s) -{ - return rawcommand_set.find (s) != rawcommand_set.end (); -} - void mark_as_rawcommand (const std::string& s) { @@ -291,11 +240,6 @@ unmark_rawcommand (const std::string& s) { rawcommand_set.erase (s); - - symbol_record *sr = fbi_sym_tab->lookup (s); - - if (sr) - sr->unmark_rawcommand (); } DEFCMD (mark_as_rawcommand, args, , @@ -314,7 +258,7 @@ { octave_value_list retval; - if (at_top_level ()) + if (symbol_table::at_top_level ()) { int nargin = args.length (); @@ -350,7 +294,7 @@ { octave_value_list retval; - if (at_top_level ()) + if (symbol_table::at_top_level ()) { int nargin = args.length (); @@ -378,24 +322,7 @@ bool is_rawcommand_name (const std::string& s) { - bool retval = false; - - symbol_record *sr = fbi_sym_tab->lookup (s); - - if (sr) - { - if (sr->is_rawcommand ()) - retval = true; - else if (is_marked_as_rawcommand (s)) - { - sr->mark_as_rawcommand (); - retval = true; - } - } - else - retval = is_marked_as_rawcommand (s); - - return retval; + return rawcommand_set.find (s) != rawcommand_set.end (); } DEFCMD (israwcommand, args, , @@ -439,33 +366,6 @@ return retval; } -// Is this a built-in function? - -bool -is_builtin_function_name (const std::string& s) -{ - symbol_record *sr = fbi_sym_tab->lookup (s); - return (sr && sr->is_builtin_function ()); -} - -// Is this a mapper function? - -bool -is_mapper_function_name (const std::string& s) -{ - symbol_record *sr = fbi_sym_tab->lookup (s); - return (sr && sr->is_mapper_function ()); -} - -// Is this function globally in this scope? - -bool -is_globally_visible (const std::string& name) -{ - symbol_record *sr = curr_sym_tab->lookup (name); - return (sr && sr->is_linked_to_global ()); -} - // Is this octave_value a valid function? octave_function * @@ -474,28 +374,17 @@ { octave_function *ans = 0; - symbol_record *sr = 0; - if (! fcn_name.empty ()) { - sr = fbi_sym_tab->lookup (fcn_name, true); - - lookup (sr, false); + octave_value val = symbol_table::find_function (fcn_name); + + if (val.is_defined ()) + ans = val.function_value (true); } - if (sr) - { - octave_value tmp = sr->def (); - ans = tmp.function_value (true); - } - - if (! sr || ! ans || ! sr->is_function ()) - { - if (warn) - error ("%s: the symbol `%s' is not valid as a function", - warn_for.c_str (), fcn_name.c_str ()); - ans = 0; - } + if (! ans && warn) + error ("%s: the symbol `%s' is not valid as a function", + warn_for.c_str (), fcn_name.c_str ()); return ans; } @@ -613,12 +502,9 @@ if (! name.empty ()) { - symbol_record *sr = curr_sym_tab->lookup (name); - - if (! sr) - sr = fbi_sym_tab->lookup (name); - - retval = (sr && sr->is_variable ()); + octave_value val = symbol_table::varval (name); + + retval = val.is_defined (); } return retval; @@ -733,11 +619,7 @@ return retval; } - symbol_record *sr = curr_sym_tab->lookup (name); - - retval = (sr && sr->is_linked_to_global ()); - - return retval; + return symbol_table::is_global (name); } DEFUN (isglobal, args, , @@ -787,20 +669,21 @@ // name that is visible in the current scope will be in the local // symbol table. - symbol_record *sr = curr_sym_tab->lookup (symbol_name); - - if (! (sr && sr->is_defined ())) - sr = fbi_sym_tab->lookup (symbol_name); - - if (sr && sr->is_defined ()) + octave_value_list evaluated_args; + bool args_evaluated; + + octave_value val = symbol_table::find (symbol_name, 0, string_vector (), + evaluated_args, args_evaluated); + + if (val.is_defined ()) { bool not_a_struct = struct_elts.empty (); - bool var_ok = not_a_struct || sr->is_map_element (struct_elts); + bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */; if (! retval && var_ok && (type == "any" || type == "var") - && sr->is_user_variable ()) + && val.is_constant ()) { retval = 1; } @@ -808,7 +691,7 @@ if (! retval && (type == "any" || type == "builtin")) { - if (not_a_struct && sr->is_builtin_function ()) + if (not_a_struct && val.is_builtin_function ()) { retval = 5; } @@ -817,13 +700,12 @@ if (! retval && not_a_struct && (type == "any" || type == "file") - && (sr->is_user_function () || sr->is_dld_function ())) + && (val.is_user_function () || val.is_dld_function ())) { - octave_value t = sr->def (); - octave_function *f = t.function_value (true); + octave_function *f = val.function_value (true); std::string s = f ? f->fcn_file_name () : std::string (); - retval = s.empty () ? 103 : (sr->is_user_function () ? 2 : 3); + retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3); } } @@ -962,289 +844,29 @@ return retval; } -bool -fcn_out_of_date (octave_function *fcn, const std::string& ff, time_t tp) -{ - bool retval = false; - - fcn->mark_fcn_file_up_to_date (octave_time ()); - - if (! (Vignore_function_time_stamp == 2 - || (Vignore_function_time_stamp && fcn->is_system_fcn_file ()))) - { - file_stat fs (ff); - - if (fs && fs.is_newer (tp)) - retval = true; - } - - return retval; -} - -// Is there a corresponding function file that is newer than the -// symbol definition? - -static bool -symbol_out_of_date (symbol_record *sr) -{ - bool retval = false; - - if (sr) - { - octave_value ans = sr->def (); - - octave_function *fcn = ans.function_value (true); - - if (fcn) - { - std::string ff = fcn->fcn_file_name (); - - if (! ff.empty ()) - { - octave_time tc = fcn->time_checked (); - - bool relative = fcn->is_relative (); - - if (tc < Vlast_prompt_time - || (relative && tc < Vlast_chdir_time)) - { - octave_time ottp = fcn->time_parsed (); - time_t tp = ottp.unix_time (); - - std::string nm = fcn->is_nested_function () - ? fcn->parent_fcn_name () : fcn->name (); - - // FIXME -- the following code is repeated - // in load_fcn_from_file in parse.y. - - int nm_len = nm.length (); - - std::string file; - - if (octave_env::absolute_pathname (nm) - && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct" - || nm.substr (nm_len-4) == ".mex")) - || (nm_len > 2 && nm.substr (nm_len-4) == ".m"))) - { - file = nm; - } - else - { - file = lookup_autoload (nm); - - if (file.empty ()) - file = load_path::find_fcn (nm); - - file = octave_env::make_absolute (file, octave_env::getcwd ()); - } - - if (file.empty ()) - { - // Can't see this function now, so we should - // clear it. - - sr->clear (); - - retval = true; - } - else if (same_file (file, ff)) - { - retval = fcn_out_of_date (fcn, ff, tp); - } - else - { - // Check the full function name. Maybe we already - // parsed it. - - symbol_record *full_sr = fbi_sym_tab->lookup (file); - - if (full_sr) - { - octave_value v = full_sr->def (); - - if (v.is_function ()) - { - // OK, swap the aliases around. - - // FIXME -- this is a bit - // tricky, so maybe some refactoring is - // in order here too... - - symbol_record *short_sr = fbi_sym_tab->lookup (nm); - - if (short_sr) - short_sr->alias (full_sr); - - // Make local symbol table entry point - // to correct global function too. - - sr->alias (full_sr); - - fcn = v.function_value (); - - retval = fcn_out_of_date (fcn, file, tp); - } - else - retval = true; - } - else - retval = true; - } - } - } - } - } - - return retval; -} - -bool -lookup (symbol_record *sym_rec, bool exec_script) -{ - bool script_executed = false; - - if (! sym_rec->is_linked_to_global ()) - { - if (sym_rec->is_defined ()) - { - if (sym_rec->is_function () && symbol_out_of_date (sym_rec)) - script_executed = load_fcn_from_file (sym_rec, exec_script); - } - else if (! sym_rec->is_formal_parameter ()) - { - link_to_builtin_or_function (sym_rec); - - if (! sym_rec->is_defined ()) - script_executed = load_fcn_from_file (sym_rec, exec_script); - else if (sym_rec->is_function () && symbol_out_of_date (sym_rec)) - script_executed = load_fcn_from_file (sym_rec, exec_script); - } - } - - return script_executed; -} - -// Get the symbol record for the given name that is visible in the -// current scope. Reread any function definitions that appear to be -// out of date. If a function is available in a file but is not -// currently loaded, this will load it and insert the name in the -// current symbol table. - -symbol_record * -lookup_by_name (const std::string& nm, bool exec_script) -{ - symbol_record *sym_rec = curr_sym_tab->lookup (nm, true); - - lookup (sym_rec, exec_script); - - return sym_rec; -} - -octave_value -lookup_function (const std::string& nm, const std::string& parent) -{ - octave_value retval; - - symbol_record *sr = 0; - - if (! parent.empty ()) - sr = fbi_sym_tab->lookup (parent + ":" + nm); - - if (! sr || ! sr->is_function ()) - { - if (curr_parent_function) - sr = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm); - - if (! sr || ! sr->is_function ()) - sr = fbi_sym_tab->lookup (nm, true); - - if (sr && ! sr->is_function ()) - load_fcn_from_file (sr, false); - } - - if (sr) - { - octave_value v = sr->def (); - - if (v.is_function ()) - retval = v; - } - - return retval; -} - -octave_value -lookup_user_function (const std::string& nm) -{ - octave_value retval; - - symbol_record *sr = 0; - - if (curr_parent_function) - { - std::string parent = curr_parent_function->name (); - - sr = fbi_sym_tab->lookup (parent + ":" + nm); - } - - if (! sr || ! sr->is_user_function ()) - { - sr = fbi_sym_tab->lookup (nm, true); - - if (sr && ! sr->is_user_function ()) - load_fcn_from_file (sr, false); - } - - if (sr) - retval = sr->def (); - - return retval; -} - octave_value lookup_function_handle (const std::string& nm) { - octave_value retval; - - symbol_record *sr = curr_sym_tab->lookup (nm, true); - - if (sr && sr->def ().is_function_handle ()) - retval = sr->def (); - - return retval; + octave_value val = symbol_table::varval (nm); + + return val.is_function_handle () ? val : octave_value (); } octave_value get_global_value (const std::string& nm, bool silent) { - octave_value retval; - - symbol_record *sr = global_sym_tab->lookup (nm); - - if (sr) - { - octave_value sr_def = sr->def (); - - if (sr_def.is_defined ()) - retval = sr_def; - else if (! silent) - error ("get_global_by_name: undefined symbol `%s'", nm.c_str ()); - } - else if (! silent) - error ("get_global_by_name: unknown symbol `%s'", nm.c_str ()); - - return retval; + octave_value val = symbol_table::varval (nm, symbol_table::global_scope ()); + + if (val.is_undefined () && ! silent) + error ("get_global_by_name: undefined symbol `%s'", nm.c_str ()); + + return val; } void set_global_value (const std::string& nm, const octave_value& val) { - symbol_record *sr = global_sym_tab->lookup (nm, true); - - if (sr) - sr->define (val); - else - panic_impossible (); + symbol_table::varref (nm, symbol_table::global_scope ()) = val; } // Variable values. @@ -1415,174 +1037,609 @@ return retval; } -// Global stuff and links to builtin variables and functions. - -// Make the definition of the symbol record sr be the same as the -// definition of the global variable of the same name, creating it if -// it doesn't already exist. - -void -link_to_global_variable (symbol_record *sr) +struct +symbol_record_name_compare +{ + bool operator () (const symbol_table::symbol_record& a, + const symbol_table::symbol_record& b) + { + std::string a_nm = a.name (); + std::string b_nm = b.name (); + + return a_nm.compare (b_nm); + } +}; + +struct +whos_parameter { - if (! sr->is_linked_to_global ()) + char command; + char modifier; + int parameter_length; + int first_parameter_length; + int dimensions; + int balance; + std::string text; + std::string line; +}; + +static void +print_descriptor (std::ostream& os, std::list params) +{ + // This method prints a line of information on a given symbol + std::list::iterator i = params.begin (); + std::ostringstream param_buf; + + while (i != params.end ()) { - sr->mark_as_linked_to_global (); - - if (! error_state) + whos_parameter param = *i; + + if (param.command != '\0') + { + // Do the actual printing + switch (param.modifier) + { + case 'l': + os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + break; + + case 'r': + os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); + break; + + case 'c': + if (param.command != 's') + { + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + } + break; + + default: + os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + } + + if (param.command == 's' && param.modifier == 'c') + { + int a, b; + + if (param.modifier == 'c') + { + a = param.first_parameter_length - param.balance; + a = (a < 0 ? 0 : a); + b = param.parameter_length - a - param.text . length (); + b = (b < 0 ? 0 : b); + os << std::setiosflags (std::ios::left) << std::setw (a) + << "" << std::resetiosflags (std::ios::left) << param.text + << std::setiosflags (std::ios::left) + << std::setw (b) << "" + << std::resetiosflags (std::ios::left); + param_buf << std::setiosflags (std::ios::left) << std::setw (a) + << "" << std::resetiosflags (std::ios::left) << param.line + << std::setiosflags (std::ios::left) + << std::setw (b) << "" + << std::resetiosflags (std::ios::left); + } + } + else + { + os << param.text; + param_buf << param.line; + } + os << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + param_buf << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + i++; + } + else { - std::string nm = sr->name (); - - symbol_record *gsr = global_sym_tab->lookup (nm, true); - - // Make sure this symbol is a variable. - - if (! gsr->is_user_variable ()) - gsr->define (octave_value ()); - - sr->alias (gsr); + os << param.text; + param_buf << param.line; + i++; } } + + os << param_buf.str (); } -// Make the definition of the symbol record sr be the same as the -// definition of the builtin variable of the same name. - -// Make the definition of the symbol record sr be the same as the -// definition of the builtin function, or user function of the same -// name, provided that the name has not been used as a formal parameter. - -void -link_to_builtin_or_function (symbol_record *sr) -{ - std::string nm = sr->name (); - - symbol_record *tmp_sym = 0; - - octave_function *fcn = octave_call_stack::current (); - - std::string parent = fcn ? fcn->parent_fcn_name () : std::string (); - - if (! parent.empty ()) - tmp_sym = fbi_sym_tab->lookup (parent + ":" + nm); - - if (! tmp_sym && curr_parent_function) - tmp_sym = fbi_sym_tab->lookup (curr_parent_function->name () + ":" + nm); - - if (! tmp_sym) - tmp_sym = fbi_sym_tab->lookup (nm); - - if (tmp_sym - && tmp_sym->is_function () - && ! tmp_sym->is_formal_parameter ()) - sr->alias (tmp_sym); -} - -// Force a link to a function in the current symbol table. This is -// used just after defining a function to avoid different behavior -// depending on whether or not the function has been evaluated after -// being defined. +// Calculate how much space needs to be reserved for the first part of +// the dimensions string. For example, // -// Return without doing anything if there isn't a function with the -// given name defined in the global symbol table. - -void -force_link_to_function (const std::string& id_name) -{ - symbol_record *fsr = fbi_sym_tab->lookup (id_name, true); - if (fsr->is_function ()) - { - curr_sym_tab->clear (id_name); - symbol_record *csr = curr_sym_tab->lookup (id_name, true); - csr->alias (fsr); - } -} - -DEFUN (document, args, , - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {} document (@var{symbol}, @var{text})\n\ -Set the documentation string for @var{symbol} to @var{text}.\n\ -@end deftypefn") +// mat is a 12x3 matrix +// ^^ => 2 columns + +static int +dimensions_string_req_first_space (const dim_vector& dims, int print_dims) { - octave_value retval; - - int nargin = args.length (); - - if (nargin == 2) + int first_param_space = 0; + + // Calculating dimensions. + + std::string dim_str = ""; + std::stringstream ss; + long dim = dims.length (); + + first_param_space = (first_param_space >= 1 ? first_param_space : 1); + + // Preparing dimension string. + + if ((dim <= print_dims || print_dims < 0) && print_dims != 0) + { + // Dimensions string must be printed like this: 2x3x4x2. + + if (dim == 0 || dim == 1) + first_param_space = 1; // First parameter is 1. + else + { + ss << dims (0); + + dim_str = ss.str (); + first_param_space = dim_str.length (); + } + } + else { - std::string name = args(0).string_value (); - - if (! error_state) - { - std::string help = args(1).string_value (); - - if (! error_state) + // Printing dimension string as: a-D. + + ss << dim; + + dim_str = ss.str (); + first_param_space = dim_str.length (); + } + + return first_param_space; +} + +// Make the dimensions-string. For example: mat is a 2x3 matrix. +// ^^^ +// +// FIXME -- why not just use the dim_vector::str () method? + +std::string +make_dimensions_string (const dim_vector& dims, int print_dims) +{ + // Calculating dimensions. + + std::string dim_str = ""; + std::stringstream ss; + long dim = dims.length (); + + // Preparing dimension string. + + if ((dim <= print_dims || print_dims < 0) && print_dims != 0) + { + // Only printing the dimension string as: axbxc... + + if (dim == 0) + ss << "1x1"; + else + { + for (int i = 0; i < dim; i++) { - if (is_command_name (name) - || is_mapper_function_name (name) - || is_builtin_function_name (name)) - error ("document: can't redefine help for built-in functions"); - else + if (i == 0) { - symbol_record *sym_rec = curr_sym_tab->lookup (name); - - if (sym_rec) - sym_rec->document (help); + if (dim == 1) + { + // Looks like this is not going to happen in + // Octave, but ... + + ss << "1x" << dims (i); + } else - error ("document: no such symbol `%s'", name.c_str ()); + ss << dims (i); } + else if (i < dim && dim != 1) + ss << "x" << dims (i); } } } else - print_usage (); - - return retval; + { + // Printing dimension string as: a-D. + + ss << dim << "-D"; + } + + dim_str = ss.str (); + + return dim_str; } -// FIXME -- this function is duplicated in symtab.cc with the -// name maybe_list_cmp_fcn. +// Calculate how much space needs to be reserved for the +// dimensions string. For example, +// +// mat is a 12x3 matrix +// ^^^^ => 4 columns +// +// FIXME -- why not just use the dim_vector::str () method? static int -symbol_record_name_compare (const void *a_arg, const void *b_arg) +dimensions_string_req_total_space (const dim_vector& dims, int print_dims) +{ + std::string dim_str = ""; + std::stringstream ss; + + ss << make_dimensions_string (dims, print_dims); + dim_str = ss.str (); + + return dim_str.length (); +} + +static std::list +parse_whos_line_format (const std::list& symbols) { - const symbol_record *a = *(static_cast (a_arg)); - const symbol_record *b = *(static_cast (b_arg)); - - std::string a_nm = a->name (); - std::string b_nm = b->name (); - - return a_nm.compare (b_nm); + // This method parses the string whos_line_format, and returns + // a parameter list, containing all information needed to print + // the given attributtes of the symbols + int idx; + size_t format_len = Vwhos_line_format.length (); + char garbage; + std::list params; + + size_t bytes1; + int elements1; + + std::string param_string = "abcenst"; + Array param_length (dim_vector (param_string.length (), 1)); + Array param_names (dim_vector (param_string.length (), 1)); + size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t; + + pos_a = param_string.find ('a'); // Attributes + pos_b = param_string.find ('b'); // Bytes + pos_c = param_string.find ('c'); // Class + pos_e = param_string.find ('e'); // Elements + pos_n = param_string.find ('n'); // Name + pos_s = param_string.find ('s'); // Size + pos_t = param_string.find ('t'); // Type + + param_names(pos_a) = "Attr"; + param_names(pos_b) = "Bytes"; + param_names(pos_c) = "Class"; + param_names(pos_e) = "Elements"; + param_names(pos_n) = "Name"; + param_names(pos_s) = "Size"; + param_names(pos_t) = "Type"; + + for (size_t i = 0; i < param_string.length (); i++) + param_length(i) = param_names(i) . length (); + + // Calculating necessary spacing for name column, + // bytes column, elements column and class column + + for (std::list::const_iterator p = symbols.begin (); + p != symbols.end (); p++) + { + std::stringstream ss1, ss2; + std::string str; + + str = p->name (); + param_length(pos_n) = ((str.length () + > static_cast (param_length(pos_n))) + ? str.length () : param_length(pos_n)); + + octave_value val = p->varval (); + + str = val.type_name (); + param_length(pos_t) = ((str.length () + > static_cast (param_length(pos_t))) + ? str.length () : param_length(pos_t)); + + elements1 = val.capacity (); + ss1 << elements1; + str = ss1.str (); + param_length(pos_e) = ((str.length () + > static_cast (param_length(pos_e))) + ? str.length () : param_length(pos_e)); + + bytes1 = val.byte_size (); + ss2 << bytes1; + str = ss2.str (); + param_length(pos_b) = ((str.length () + > static_cast (param_length(pos_b))) + ? str.length () : param_length (pos_b)); + } + + idx = 0; + while (static_cast (idx) < format_len) + { + whos_parameter param; + param.command = '\0'; + + if (Vwhos_line_format[idx] == '%') + { + bool error_encountered = false; + param.modifier = 'r'; + param.parameter_length = 0; + param.dimensions = 8; + + int a = 0, b = -1, c = 8, balance = 1; + unsigned int items; + size_t pos; + std::string cmd; + + // Parse one command from whos_line_format + cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); + pos = cmd.find (';'); + if (pos != NPOS) + cmd = cmd.substr (0, pos+1); + else + error ("parameter without ; in whos_line_format"); + + idx += cmd.length (); + + // FIXME -- use iostream functions instead of sscanf! + + if (cmd.find_first_of ("crl") != 1) + items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d:%d;", + &garbage, ¶m.command, &a, &b, &c, &balance); + else + items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d:%d;", + &garbage, ¶m.modifier, ¶m.command, + &a, &b, &c, &balance) - 1; + + if (items < 2) + { + error ("whos_line_format: parameter structure without command in whos_line_format"); + error_encountered = true; + } + + // Insert data into parameter + param.first_parameter_length = 0; + pos = param_string.find (param.command); + if (pos != NPOS) + { + param.parameter_length = param_length(pos); + param.text = param_names(pos); + param.line.assign (param_names(pos).length (), '='); + + param.parameter_length = (a > param.parameter_length + ? a : param.parameter_length); + if (param.command == 's' && param.modifier == 'c' && b > 0) + param.first_parameter_length = b; + } + else + { + error ("whos_line_format: '%c' is not a command", + param.command); + error_encountered = true; + } + + if (param.command == 's') + { + // Have to calculate space needed for printing matrix dimensions + // Space needed for Size column is hard to determine in prior, + // because it depends on dimensions to be shown. That is why it is + // recalculated for each Size-command + int first, rest = 0, total; + param.dimensions = c; + first = param.first_parameter_length; + total = param.parameter_length; + + for (std::list::const_iterator p = symbols.begin (); + p != symbols.end (); p++) + { + octave_value val = p->varval (); + dim_vector dims = val.dims (); + int first1 = dimensions_string_req_first_space (dims, param.dimensions); + int total1 = dimensions_string_req_total_space (dims, param.dimensions); + int rest1 = total1 - first1; + rest = (rest1 > rest ? rest1 : rest); + first = (first1 > first ? first1 : first); + total = (total1 > total ? total1 : total); + } + + if (param.modifier == 'c') + { + if (first < balance) + first += balance - first; + if (rest + balance < param.parameter_length) + rest += param.parameter_length - rest - balance; + + param.parameter_length = first + rest; + param.first_parameter_length = first; + param.balance = balance; + } + else + { + param.parameter_length = total; + param.first_parameter_length = 0; + } + } + else if (param.modifier == 'c') + { + error ("whos_line_format: modifier 'c' not available for command '%c'", + param.command); + error_encountered = true; + } + + // What happens if whos_line_format contains negative numbers + // at param_length positions? + param.balance = (b < 0 ? 0 : param.balance); + param.first_parameter_length = (b < 0 ? 0 : + param.first_parameter_length); + param.parameter_length = (a < 0 + ? 0 + : (param.parameter_length + < param_length(pos_s) + ? param_length(pos_s) + : param.parameter_length)); + + // Parameter will not be pushed into parameter list if ... + if (! error_encountered) + params.push_back (param); + } + else + { + // Text string, to be printed as it is ... + std::string text; + size_t pos; + text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); + pos = text.find ('%'); + if (pos != NPOS) + text = text.substr (0, pos); + + // Push parameter into list ... + idx += text.length (); + param.text=text; + param.line.assign (text.length(), ' '); + params.push_back (param); + } + } + + return params; +} + +void +print_symbol_info_line (std::ostream& os, + const symbol_table::symbol_record& sr, + std::list& params) +{ + octave_value val = sr.varval (); + dim_vector dims = val.dims (); + + std::list::iterator i = params.begin (); + + while (i != params.end ()) + { + whos_parameter param = *i; + + if (param.command != '\0') + { + // Do the actual printing. + + switch (param.modifier) + { + case 'l': + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + break; + + case 'r': + os << std::setiosflags (std::ios::right) + << std::setw (param.parameter_length); + break; + + case 'c': + if (param.command == 's') + { + int front = param.first_parameter_length + - dimensions_string_req_first_space (dims, param.dimensions); + int back = param.parameter_length + - dimensions_string_req_total_space (dims, param.dimensions) + - front; + front = (front > 0) ? front : 0; + back = (back > 0) ? back : 0; + + os << std::setiosflags (std::ios::left) + << std::setw (front) + << "" + << std::resetiosflags (std::ios::left) + << make_dimensions_string (dims, param.dimensions) + << std::setiosflags (std::ios::left) + << std::setw (back) + << "" + << std::resetiosflags (std::ios::left); + } + else + { + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + } + break; + + default: + error ("whos_line_format: modifier `%c' unknown", + param.modifier); + + os << std::setiosflags (std::ios::right) + << std::setw (param.parameter_length); + } + + switch (param.command) + { + case 'a': + { + char tmp[5]; + + tmp[0] = (sr.is_automatic () ? 'a' : ' '); + tmp[1] = (sr.is_formal () ? 'f' : ' '); + tmp[2] = (sr.is_global () ? 'g' : ' '); + tmp[3] = (sr.is_persistent () ? 'p' : ' '); + tmp[4] = 0; + + os << tmp; + } + break; + + case 'b': + os << val.byte_size (); + break; + + case 'c': + os << val.class_name (); + break; + + case 'e': + os << val.capacity (); + break; + + case 'n': + os << sr.name (); + break; + + case 's': + if (param.modifier != 'c') + os << make_dimensions_string (dims, param.dimensions); + break; + + case 't': + os << val.type_name (); + break; + + default: + error ("whos_line_format: command `%c' unknown", param.command); + } + + os << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + i++; + } + else + { + os << param.text; + i++; + } + } } static octave_value -do_who (int argc, const string_vector& argv, int return_list) +do_who (int argc, const string_vector& argv, bool return_list, + bool verbose = false) { octave_value retval; - bool show_builtins = false; - bool show_functions = false; - bool show_variables = false; - bool show_verbose = false; - std::string my_name = argv[0]; + bool global_only = false; + int i; for (i = 1; i < argc; i++) { - if (argv[i] == "-all" || argv[i] == "-a") + if (argv[i] == "-regexp" || argv[i] == "-file") { - show_builtins = true; - show_functions = true; - show_variables = true; + error ("%s: `%s' option not implemented", my_name.c_str (), + argv[i].c_str ()); + + return retval; } - else if (argv[i] == "-builtins" || argv[i] == "-b") - show_builtins = true; - else if (argv[i] == "-functions" || argv[i] == "-f") - show_functions = true; - else if (argv[i] == "-long" || argv[i] == "-l") - show_verbose = true; - else if (argv[i] == "-variables" || argv[i] == "-v") - show_variables = true; + else if (argv[i] == "global") + global_only = true; else if (argv[i][0] == '-') warning ("%s: unrecognized option `%s'", my_name.c_str (), argv[i].c_str ()); @@ -1590,99 +1647,27 @@ break; } - // If no options were specified to select the type of symbol to - // display, then set defaults. - - if (! (show_builtins || show_functions || show_variables)) + int npats = argc - i; + string_vector pats (npats > 0 ? npats : 1); + if (npats > 0) { - show_functions = at_top_level (); - show_variables = true; + for (int j = 0; j < npats; j++) + pats[j] = argv[i+j]; } - - int npats = argc - i; - string_vector pats (npats); - for (int j = 0; j < npats; j++) - pats[j] = argv[i+j]; - - // If the user specified -l and nothing else, show variables. If - // evaluating this at the top level, also show functions. - - if (show_verbose && ! (show_builtins || show_functions || show_variables)) - { - show_functions = at_top_level (); - show_variables = 1; - } + else + pats[0] = "*"; + + symbol_table::scope_id scope = global_only + ? symbol_table::global_scope () : symbol_table::current_scope (); + + std::list symbols + = symbol_table::glob_variables (pats, scope); + + size_t symbols_len = symbols.size (); if (return_list) { - // FIXME -- maybe symbol_list should return a std::list - // object instead of an Array. - - dim_vector dv (0, 0); - - Array s3 (dv); - Array s4 (dv); - Array s5 (dv); - Array s6 (dv); - Array s7 (dv); - Array s8 (dv); - - if (show_builtins) - { - s3 = fbi_sym_tab->symbol_list (pats, symbol_record::BUILTIN_FUNCTION, - SYMTAB_ALL_SCOPES); - } - - if (show_functions) - { - s4 = fbi_sym_tab->symbol_list (pats, symbol_record::DLD_FUNCTION, - SYMTAB_ALL_SCOPES); - - s5 = fbi_sym_tab->symbol_list (pats, symbol_record::USER_FUNCTION, - SYMTAB_ALL_SCOPES); - - s6 = fbi_sym_tab->symbol_list (pats, symbol_record::MEX_FUNCTION, - SYMTAB_ALL_SCOPES); - } - - if (show_variables) - { - s7 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE, - SYMTAB_LOCAL_SCOPE); - - s8 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE, - SYMTAB_GLOBAL_SCOPE); - } - - octave_idx_type s3_len = s3.length (); - octave_idx_type s4_len = s4.length (); - octave_idx_type s5_len = s5.length (); - octave_idx_type s6_len = s6.length (); - octave_idx_type s7_len = s7.length (); - octave_idx_type s8_len = s8.length (); - - octave_idx_type symbols_len - = s3_len + s4_len + s5_len + s6_len + s7_len + s8_len; - - Array symbols (dim_vector (symbols_len, 1)); - - octave_idx_type k = 0; - - symbols.insert (s3, k, 0); - k += s3_len; - symbols.insert (s4, k, 0); - k += s4_len; - symbols.insert (s5, k, 0); - k += s5_len; - symbols.insert (s6, k, 0); - k += s6_len; - symbols.insert (s7, k, 0); - k += s7_len; - symbols.insert (s8, k, 0); - - symbols.qsort (symbol_record_name_compare); - - if (show_verbose) + if (verbose) { Array name_info (symbols_len, 1); Array size_info (symbols_len, 1); @@ -1693,9 +1678,12 @@ Array complex_info (symbols_len, 1); Array nesting_info (symbols_len, 1); - for (octave_idx_type j = 0; j < symbols_len; j++) + std::list::const_iterator p + = symbols.begin (); + + for (size_t j = 0; j < symbols_len; j++) { - symbol_record *sr = symbols(j); + const symbol_table::symbol_record& sr = *p++; Octave_map ni; @@ -1708,13 +1696,16 @@ ni.assign ("function", caller_function_name); ni.assign ("level", 1); - name_info(j) = sr->name (); - size_info(j) = sr->size (); - bytes_info(j) = sr->byte_size (); - class_info(j) = sr->class_name (); - global_info(j) = sr->is_linked_to_global (); - sparse_info(j) = sr->is_sparse_type (); - complex_info(j) = sr->is_complex_type (); + name_info(j) = sr.name (); + global_info(j) = sr.is_global (); + + octave_value val = sr.varval (); + + size_info(j) = val.size (); + bytes_info(j) = val.byte_size (); + class_info(j) = val.class_name (); + sparse_info(j) = val.is_sparse_type (); + complex_info(j) = val.is_complex_type (); nesting_info(j) = ni; } @@ -1739,56 +1730,70 @@ { names.resize (symbols_len); - for (octave_idx_type j = 0; j < symbols_len; j++) - names[j] = symbols(j)->name (); + std::list::const_iterator p + = symbols.begin (); + + for (size_t j = 0; j < symbols_len; j++) + { + names[j] = p->name (); + p++; + } } retval = Cell (names); } } - else + else if (symbols_len > 0) { - int pad_after = 0; - - if (show_builtins) - { - pad_after += fbi_sym_tab->maybe_list - ("*** built-in functions:", pats, octave_stdout, - show_verbose, symbol_record::BUILTIN_FUNCTION, SYMTAB_ALL_SCOPES); - } - - if (show_functions) + if (global_only) + octave_stdout << "Global variables:\n\n"; + else + octave_stdout << "Variables in the current scope:\n\n"; + + if (verbose) { - pad_after += fbi_sym_tab->maybe_list - ("*** dynamically linked functions:", pats, - octave_stdout, show_verbose, symbol_record::DLD_FUNCTION, - SYMTAB_ALL_SCOPES); - - pad_after += fbi_sym_tab->maybe_list - ("*** currently compiled functions:", pats, - octave_stdout, show_verbose, symbol_record::USER_FUNCTION, - SYMTAB_ALL_SCOPES); - - pad_after += fbi_sym_tab->maybe_list - ("*** mex functions:", pats, - octave_stdout, show_verbose, symbol_record::MEX_FUNCTION, - SYMTAB_ALL_SCOPES); + size_t bytes = 0; + size_t elements = 0; + + std::list params; + + params = parse_whos_line_format (symbols); + + print_descriptor (octave_stdout, params); + + octave_stdout << "\n"; + + for (std::list::const_iterator p = symbols.begin (); + p != symbols.end (); p++) + { + print_symbol_info_line (octave_stdout, *p, params); + octave_value val = p->varval (); + elements += val.capacity (); + bytes += val.byte_size (); + } + + octave_stdout << "\nTotal is " << elements + << (elements == 1 ? " element" : " elements") + << " using " << bytes + << (bytes == 1 ? " byte" : " bytes") << "\n"; } - - if (show_variables) + else { - pad_after += curr_sym_tab->maybe_list - ("*** local user variables:", pats, octave_stdout, - show_verbose, symbol_record::USER_VARIABLE, SYMTAB_LOCAL_SCOPE); - - pad_after += curr_sym_tab->maybe_list - ("*** globally visible user variables:", pats, - octave_stdout, show_verbose, symbol_record::USER_VARIABLE, - SYMTAB_GLOBAL_SCOPE); + string_vector names (symbols_len); + + std::list::const_iterator p + = symbols.begin (); + + for (size_t j = 0; j < symbols_len; j++) + { + names[j] = p->name (); + p++; + } + + names.list_in_columns (octave_stdout); } - if (pad_after) - octave_stdout << "\n"; + octave_stdout << "\n"; } return retval; @@ -1840,10 +1845,8 @@ string_vector argv = args.make_argv ("who"); - if (error_state) - return retval; - - retval = do_who (argc, argv, nargout == 1); + if (! error_state) + retval = do_who (argc, argv, nargout == 1); } else print_usage (); @@ -1861,23 +1864,12 @@ if (nargout < 2) { - int nargin = args.length (); - - octave_value_list tmp_args; - - for (int i = nargin; i > 0; i--) - tmp_args(i) = args(i-1); - - tmp_args(0) = "-long"; - - int argc = tmp_args.length () + 1; - - string_vector argv = tmp_args.make_argv ("whos"); - - if (error_state) - return retval; - - retval = do_who (argc, argv, nargout == 1); + int argc = args.length () + 1; + + string_vector argv = args.make_argv ("whos"); + + if (! error_state) + retval = do_who (argc, argv, nargout == 1, true); } else print_usage (); @@ -1890,14 +1882,14 @@ void bind_ans (const octave_value& val, bool print) { - symbol_record *sr = curr_sym_tab->lookup ("ans", true); + static std::string ans = "ans"; if (val.is_defined ()) { - sr->define (val); + symbol_table::varref (ans) = val; if (print) - val.print_with_name (octave_stdout, "ans"); + val.print_with_name (octave_stdout, ans); } } @@ -1912,61 +1904,59 @@ } void -mlock (const std::string& nm) +mlock (void) { - symbol_record *sr = fbi_sym_tab->lookup (nm, true); - - if (sr) - sr->mark_as_static (); + octave_function *fcn = octave_call_stack::caller (); + + if (fcn) + fcn->lock (); + else + error ("mlock: invalid use outside a function"); } void munlock (const std::string& nm) { - symbol_record *sr = fbi_sym_tab->lookup (nm); - - if (sr && sr->is_static ()) - sr->unmark_static (); - else - error ("munlock: %s is not locked", nm.c_str ()); + octave_value val = symbol_table::find_function (nm); + + if (val.is_defined ()) + { + octave_function *fcn = val.function_value (); + + if (fcn) + fcn->unlock (); + } } bool mislocked (const std::string& nm) { - symbol_record *sr = fbi_sym_tab->lookup (nm); - - return (sr && sr->is_static ()); + bool retval = false; + + octave_value val = symbol_table::find_function (nm); + + if (val.is_defined ()) + { + octave_function *fcn = val.function_value (); + + if (fcn) + retval = fcn->islocked (); + } + + return retval; } DEFCMD (mlock, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} mlock (@var{name})\n\ -Lock the named function into memory. If no function is named\n\ -then lock in the current function.\n\ +Lock the current function into memory so that it can't be cleared.\n\ @seealso{munlock, mislocked, persistent}\n\ @end deftypefn") { octave_value_list retval; - if (args.length () == 1) - { - std::string name = args(0).string_value (); - - if (! error_state) - mlock (name); - else - error ("mlock: expecting argument to be a function name"); - } - else if (args.length () == 0) - { - octave_user_function *fcn = octave_call_stack::caller_user_function (); - - if (fcn) - mlock (fcn->name ()); - else - error ("mlock: invalid use outside a function"); - } + if (args.length () == 0) + mlock (); else print_usage (); @@ -1994,10 +1984,10 @@ } else if (args.length () == 0) { - octave_user_function *fcn = octave_call_stack::caller_user_function (); + octave_function *fcn = octave_call_stack::caller (); if (fcn) - munlock (fcn->name ()); + fcn->unlock (); else error ("munlock: invalid use outside a function"); } @@ -2029,10 +2019,10 @@ } else if (args.length () == 0) { - octave_user_function *fcn = octave_call_stack::caller_user_function (); + octave_function *fcn = octave_call_stack::caller (); if (fcn) - retval = mislocked (fcn->name ()); + retval = fcn->islocked (); else error ("mislocked: invalid use outside a function"); } @@ -2069,14 +2059,6 @@ return retval; } -static inline bool -is_local_variable (const std::string& nm) -{ - symbol_record *sr = curr_sym_tab->lookup (nm); - - return (sr && sr->is_variable ()); -} - static inline void maybe_warn_exclusive (bool exclusive) { @@ -2084,136 +2066,17 @@ warning ("clear: ignoring --exclusive option"); } -static inline void -do_clear_all (void) -{ - curr_sym_tab->clear (); - fbi_sym_tab->clear_functions (); - global_sym_tab->clear (); -} - -static inline void -do_clear_functions (void) -{ - curr_sym_tab->clear_functions (); - fbi_sym_tab->clear_functions (); -} - -static inline void -do_clear_globals (void) -{ - curr_sym_tab->clear_globals (); - global_sym_tab->clear (); -} - -static inline void -do_clear_variables (void) -{ - curr_sym_tab->clear (); -} - -static inline bool -do_clear_function (const std::string& nm) -{ - bool b1 = curr_sym_tab->clear_function (nm); - - bool b2 = fbi_sym_tab->clear_function (nm); - - return b1 || b2; -} - -static inline bool -do_clear_global (const std::string& nm) -{ - bool b1 = curr_sym_tab->clear_global (nm); - - bool b2 = global_sym_tab->clear_variable (nm); - - return b1 || b2; -} - -static inline bool -do_clear_variable (const std::string& nm) -{ - return curr_sym_tab->clear_variable (nm); -} - -static inline bool -do_clear_symbol (const std::string& nm) -{ - bool cleared = curr_sym_tab->clear_variable (nm); - - if (! cleared) - cleared = do_clear_function (nm); - - return cleared; -} - -static inline bool -do_clear_function_pattern (const std::string& pat) -{ - bool b1 = curr_sym_tab->clear_function_pattern (pat); - - bool b2 = fbi_sym_tab->clear_function_pattern (pat); - - return b1 || b2; -} - -static inline bool -do_clear_global_pattern (const std::string& pat) -{ - bool b1 = curr_sym_tab->clear_global_pattern (pat); - - bool b2 = global_sym_tab->clear_variable_pattern (pat); - - return b1 || b2; -} - -static inline bool -do_clear_variable_pattern (const std::string& pat) -{ - return curr_sym_tab->clear_variable_pattern (pat); -} - -static inline bool -do_clear_symbol_pattern (const std::string& pat) -{ - // FIXME -- if we have a variable v1 and a function v2 and - // someone says clear v*, we will clear the variable but not the - // function. Is that really what should happen? (I think it is - // what Matlab does.) - - bool cleared = curr_sym_tab->clear_variable_pattern (pat); - - if (! cleared) - cleared = do_clear_function_pattern (pat); - - return cleared; -} - -static inline void +static void do_clear_functions (const string_vector& argv, int argc, int idx, bool exclusive = false) { if (idx == argc) - do_clear_functions (); + symbol_table::clear_functions (); else { if (exclusive) { - string_vector lfcns = curr_sym_tab->user_function_name_list (); - - int lcount = lfcns.length (); - - for (int i = 0; i < lcount; i++) - { - std::string nm = lfcns[i]; - - if (! name_matches_any_pattern (nm, argv, argc, idx)) - do_clear_function (nm); - } - - string_vector fcns = fbi_sym_tab->user_function_name_list (); + string_vector fcns = symbol_table::user_function_names (); int fcount = fcns.length (); @@ -2222,40 +2085,29 @@ std::string nm = fcns[i]; if (! name_matches_any_pattern (nm, argv, argc, idx)) - do_clear_function (nm); + symbol_table::clear_function (nm); } } else { while (idx < argc) - do_clear_function_pattern (argv[idx++]); + symbol_table::clear_function_pattern (argv[idx++]); } } } -static inline void +static void do_clear_globals (const string_vector& argv, int argc, int idx, bool exclusive = false) { if (idx == argc) - do_clear_globals (); + symbol_table::clear_variables(symbol_table::global_scope ()); else { if (exclusive) { - string_vector lvars = curr_sym_tab->global_variable_name_list (); - - int lcount = lvars.length (); - - for (int i = 0; i < lcount; i++) - { - std::string nm = lvars[i]; - - if (! name_matches_any_pattern (nm, argv, argc, idx)) - do_clear_global (nm); - } - - string_vector gvars = global_sym_tab->global_variable_name_list (); + string_vector gvars + = symbol_table::variable_names (symbol_table::global_scope ()); int gcount = gvars.length (); @@ -2264,28 +2116,28 @@ std::string nm = gvars[i]; if (! name_matches_any_pattern (nm, argv, argc, idx)) - do_clear_global (nm); + symbol_table::clear_global (nm); } } else { while (idx < argc) - do_clear_global_pattern (argv[idx++]); + symbol_table::clear_global_pattern (argv[idx++]); } } } -static inline void +static void do_clear_variables (const string_vector& argv, int argc, int idx, bool exclusive = false) { if (idx == argc) - do_clear_variables (); + symbol_table::clear_variables (); else { if (exclusive) { - string_vector lvars = curr_sym_tab->variable_name_list (); + string_vector lvars = symbol_table::variable_names (); int lcount = lvars.length (); @@ -2294,23 +2146,23 @@ std::string nm = lvars[i]; if (! name_matches_any_pattern (nm, argv, argc, idx)) - do_clear_variable (nm); + symbol_table::clear_variable (nm); } } else { while (idx < argc) - do_clear_variable_pattern (argv[idx++]); + symbol_table::clear_variable_pattern (argv[idx++]); } } } -static inline void +static void do_clear_symbols (const string_vector& argv, int argc, int idx, bool exclusive = false) { if (idx == argc) - do_clear_variables (); + symbol_table::clear_variables (); else { if (exclusive) @@ -2326,7 +2178,7 @@ else { while (idx < argc) - do_clear_symbol_pattern (argv[idx++]); + symbol_table::clear_symbol_pattern (argv[idx++]); } } } @@ -2338,25 +2190,29 @@ for (; idx < argc; idx++) { - if (argv[idx] == "all" && ! is_local_variable ("all")) + if (argv[idx] == "all" + && ! symbol_table::is_local_variable ("all")) { - do_clear_all (); + symbol_table::clear_all (); } - else if (argv[idx] == "functions" && ! is_local_variable ("functions")) + else if (argv[idx] == "functions" + && ! symbol_table::is_local_variable ("functions")) { do_clear_functions (argv, argc, ++idx); } - else if (argv[idx] == "global" && ! is_local_variable ("global")) + else if (argv[idx] == "global" + && ! symbol_table::is_local_variable ("global")) { do_clear_globals (argv, argc, ++idx); } - else if (argv[idx] == "variables" && ! is_local_variable ("variables")) + else if (argv[idx] == "variables" + && ! symbol_table::is_local_variable ("variables")) { - do_clear_variables (); + symbol_table::clear_variables (); } else { - do_clear_symbol_pattern (argv[idx]); + symbol_table::clear_symbol_pattern (argv[idx]); } } } @@ -2372,24 +2228,6 @@ } \ while (0) -bool -clear_function (const std::string& nm) -{ - return do_clear_function (nm); -} - -bool -clear_variable (const std::string& nm) -{ - return do_clear_variable (nm); -} - -bool -clear_symbol (const std::string& nm) -{ - return do_clear_symbol (nm); -} - DEFCMD (clear, args, , "-*- texinfo -*-\n\ @deffn {Command} clear [-x] pattern @dots{}\n\ @@ -2443,7 +2281,7 @@ { if (argc == 1) { - do_clear_variables (); + symbol_table::clear_variables (); } else { @@ -2511,9 +2349,7 @@ warning ("clear: ignoring extra arguments after -all"); - curr_sym_tab->clear (); - fbi_sym_tab->clear_functions (); - global_sym_tab->clear (); + symbol_table::clear_all (); } else if (clear_functions) { @@ -2547,40 +2383,9 @@ { octave_value_list retval; - int nargin = args.length (); - - if (nargin == 1) - { - std::string arg = args(0).string_value (); - - if (arg == "fbi") - fbi_sym_tab->print_info (octave_stdout); - else if (arg == "global") - global_sym_tab->print_info (octave_stdout); - else if (arg == "top-level") - top_level_sym_tab->print_info (octave_stdout); - else - { - symbol_record *fsr = fbi_sym_tab->lookup (arg, true); - - if (fsr && fsr->is_user_function ()) - { - octave_value tmp = fsr->def (); - const octave_base_value& rep = tmp.get_rep (); - - const octave_user_function& fcn - = dynamic_cast (rep); - - fcn.print_symtab_info (octave_stdout); - } - else - error ("no user-defined function named %s", arg.c_str ()); - } - } - else if (nargin == 0) - curr_sym_tab->print_info (octave_stdout); - else - print_usage (); + // FIXME -- what should this function do now? Print a summary for + // each scope? Print the entire symbol table? Accept a scope + // argument? return retval; } @@ -2593,92 +2398,67 @@ { octave_value_list retval; - int nargin = args.length (); - - if (nargin == 1) - { - std::string symbol_name = args(0).string_value (); - - if (! error_state) - { - symbol_record *sr = curr_sym_tab->lookup (symbol_name); - - if (sr) - sr->print_info (octave_stdout); - else - error ("__print_symbol_info__: symbol %s not found", - symbol_name.c_str ()); - } - else - print_usage (); - } - else - print_usage (); + // FIXME -- what should this function do now? return retval; } -DEFUN (ignore_function_time_stamp, args, nargout, - "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\ -@deftypefnx {Built-in Function} {@var{old_val} =} ignore_function_time_stamp (@var{new_val})\n\ -Query or set the internal variable that controls whether Octave checks\n\ -the time stamp on files each time it looks up functions defined in\n\ -function files. If the internal variable is set to @code{\"system\"},\n\ -Octave will not automatically recompile function files in subdirectories of\n\ -@file{@var{octave-home}/lib/@var{version}} if they have changed since\n\ -they were last compiled, but will recompile other function files in the\n\ -search path if they change. If set to @code{\"all\"}, Octave will not\n\ -recompile any function files unless their definitions are removed with\n\ -@code{clear}. If set to \"none\", Octave will always check time stamps\n\ -on files to determine whether functions defined in function files\n\ -need to be recompiled.\n\ +DEFUN (whos_line_format, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\ +Query or set the format string used by the @code{whos}.\n\ +\n\ +The following escape sequences may be used in the format:\n\ +@table @code\n\ +@item %a\n\ +Prints attributes of variables (g=global, p=persistent,\n\ +f=formal parameter, a=automatic variable).\n\ +@item %b\n\ +Prints number of bytes occupied by variables.\n\ +@item %c\n\ +Prints class names of variables.\n\ +@item %e\n\ +Prints elements held by variables.\n\ +@item %n\n\ +Prints variable names.\n\ +@item %s\n\ +Prints dimensions of variables.\n\ +@item %t\n\ +Prints type names of variables.\n\ +@end table\n\ +\n\ +Every command may also have a modifier:\n\ +@table @code\n\ +@item l\n\ +Left alignment.\n\ +@item r\n\ +Right alignment (this is the default).\n\ +@item c\n\ +Centered (may only be applied to command %s).\n\ +@end table\n\ +\n\ +A command is composed like this:\n\ +\n\ +@example\n\ +%[modifier][:size_of_parameter[:center-specific[\n\ + :print_dims[:balance]]]];\n\ +@end example\n\ +\n\ +Command and modifier is already explained. Size_of_parameter\n\ +tells how many columns the parameter will need for printing.\n\ +print_dims tells how many dimensions to print. If number of\n\ +dimensions exceeds print_dims, dimensions will be printed like\n\ +x-D.\n\ +center-specific and print_dims may only be applied to command\n\ +%s. A negative value for print_dims will cause Octave to print all\n\ +dimensions whatsoever.\n\ +balance specifies the offset for printing of the dimensions string.\n\ +\n\ +The default format is \" %a:4; %ln:6; %cs:16:6:8:1; %rb:12; %lc:-1;\\n\".\n\ @end deftypefn") { - octave_value retval; - - if (nargout > 0) - { - switch (Vignore_function_time_stamp) - { - case 1: - retval = "system"; - break; - - case 2: - retval = "all"; - break; - - default: - retval = "none"; - break; - } - } - - int nargin = args.length (); - - if (nargin == 1) - { - std::string sval = args(0).string_value (); - - if (! error_state) - { - if (sval == "all") - Vignore_function_time_stamp = 2; - else if (sval == "system") - Vignore_function_time_stamp = 1; - else if (sval == "none") - Vignore_function_time_stamp = 0; - else - error ("ignore_function_time_stamp: expecting argument to be \"all\", \"system\", or \"none\""); - } - else - error ("ignore_function_time_stamp: expecting argument to be character string"); - } - else if (nargin > 1) - print_usage (); - - return retval; + return SET_INTERNAL_VARIABLE (whos_line_format); } /* diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/variables.h --- a/src/variables.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/variables.h Fri Dec 28 20:56:58 2007 +0000 @@ -26,8 +26,6 @@ class octave_function; class octave_user_function; -class symbol_record; -class symbol_table; class tree_identifier; class octave_value; @@ -45,11 +43,9 @@ #include "ov-builtin.h" #include "symtab.h" -extern OCTINTERP_API bool at_top_level (void); - -extern OCTINTERP_API void initialize_symbol_tables (void); extern OCTINTERP_API void clear_mex_functions (void); +extern OCTINTERP_API void mark_as_command (const std::string&); extern OCTINTERP_API bool is_command_name (const std::string&); // The next three are here temporarily... @@ -58,9 +54,6 @@ extern OCTINTERP_API void unmark_rawcommand (const std::string& s); extern OCTINTERP_API bool is_rawcommand_name (const std::string&); -extern OCTINTERP_API bool is_mapper_function_name (const std::string&); -extern OCTINTERP_API bool is_builtin_function_name (const std::string&); -extern OCTINTERP_API bool is_globally_visible (const std::string&); extern OCTINTERP_API octave_function * is_valid_function (const octave_value&, const std::string& = std::string (), @@ -91,20 +84,6 @@ extern OCTINTERP_API std::string unique_symbol_name (const std::string& basename); -extern OCTINTERP_API bool -fcn_out_of_date (octave_function *fcn, const std::string& ff, time_t tp); - -extern OCTINTERP_API bool lookup (symbol_record *s, bool exec_script = true); - -extern OCTINTERP_API symbol_record * -lookup_by_name (const std::string& nm, bool exec_script = true); - -extern OCTINTERP_API octave_value -lookup_function (const std::string& nm, - const std::string& parent = std::string ()); - -extern OCTINTERP_API octave_value lookup_user_function (const std::string& nm); - extern OCTINTERP_API octave_value lookup_function_handle (const std::string& nm); extern OCTINTERP_API octave_value @@ -147,38 +126,18 @@ extern OCTINTERP_API int builtin_real_scalar_variable (const std::string&, double&); extern OCTINTERP_API octave_value builtin_any_variable (const std::string&); -extern OCTINTERP_API void link_to_global_variable (symbol_record *sr); -extern OCTINTERP_API void link_to_builtin_or_function (symbol_record *sr); - -extern OCTINTERP_API void force_link_to_function (const std::string&); - extern OCTINTERP_API void bind_ans (const octave_value& val, bool print); extern OCTINTERP_API void bind_internal_variable (const std::string& fname, const octave_value& val); -extern OCTINTERP_API void mlock (const std::string&); +extern OCTINTERP_API void mlock (void); extern OCTINTERP_API void munlock (const std::string&); extern OCTINTERP_API bool mislocked (const std::string&); -extern OCTINTERP_API bool clear_function (const std::string& nm); -extern OCTINTERP_API bool clear_variable (const std::string& nm); -extern OCTINTERP_API bool clear_symbol (const std::string& nm); - -// Symbol table for symbols at the top level. -extern OCTINTERP_API symbol_table *top_level_sym_tab; - -// Symbol table for the current scope. -extern OCTINTERP_API symbol_table *curr_sym_tab; - -// Symbol table for the current caller scope. -extern OCTINTERP_API symbol_table *curr_caller_sym_tab; - -// Symbol table for global symbols. -extern OCTINTERP_API symbol_table *global_sym_tab; - -// Symbol table for functions and built-in symbols. -extern OCTINTERP_API symbol_table *fbi_sym_tab; +extern OCTINTERP_API void clear_function (const std::string& nm); +extern OCTINTERP_API void clear_variable (const std::string& nm); +extern OCTINTERP_API void clear_symbol (const std::string& nm); #endif diff -r 58f5fab3ebe5 -r 745a8299c2b5 src/version.h --- a/src/version.h Fri Feb 01 23:56:51 2008 -0500 +++ b/src/version.h Fri Dec 28 20:56:58 2007 +0000 @@ -24,9 +24,9 @@ #if !defined (octave_version_h) #define octave_version_h 1 -#define OCTAVE_VERSION "3.0.0" +#define OCTAVE_VERSION "3.0.0+" -#define OCTAVE_API_VERSION "api-v32" +#define OCTAVE_API_VERSION "api-v32+" #define OCTAVE_RELEASE_DATE "2007-12-21"