Mercurial > octave-nkf
diff src/interpfcn/symtab.h @ 15093:a132d206a36a gui
maint: periodic merge of default to gui
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 03 Aug 2012 14:59:40 -0400 |
parents | src/symtab.h@fabc0e37ead1 src/symtab.h@60ff2cef569d |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interpfcn/symtab.h Fri Aug 03 14:59:40 2012 -0400 @@ -0,0 +1,2660 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2009 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if !defined (octave_symtab_h) +#define octave_symtab_h 1 + +#include <deque> +#include <list> +#include <map> +#include <set> +#include <string> + +#include "glob-match.h" +#include "regexp.h" + +class tree_argument_list; +class octave_user_function; + +#include "oct-obj.h" +#include "oct-refcount.h" +#include "ov.h" + +class +OCTINTERP_API +symbol_table +{ +public: + + typedef int scope_id; + typedef size_t context_id; + + class + scope_id_cache + { + protected: + + typedef std::set<scope_id>::iterator set_iterator; + typedef std::set<scope_id>::const_iterator set_const_iterator; + + // We start with 2 because we allocate 0 for the global symbols + // and 1 for the top-level workspace. + + scope_id_cache (void) : next_available (2), in_use (), free_list () { } + + public: + + ~scope_id_cache (void) { } + + static scope_id alloc (void) + { + return instance_ok () ? instance->do_alloc () : -1; + } + + static void free (scope_id scope) + { + if (instance_ok ()) + return instance->do_free (scope); + } + + static std::list<scope_id> scopes (void) + { + return instance_ok () ? instance->do_scopes () : std::list<scope_id> (); + } + + static void create_instance (void); + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + create_instance (); + + if (! instance) + { + ::error ("unable to create scope_id_cache object!"); + + retval = false; + } + + return retval; + } + + private: + + // No copying! + + scope_id_cache (const scope_id_cache&); + + scope_id_cache& operator = (const scope_id_cache&); + + static scope_id_cache *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + // The next available scope not in the free list. + scope_id next_available; + + // The set of scope IDs that are currently allocated. + std::set<scope_id> in_use; + + // The set of scope IDs that are currently available. + std::set<scope_id> free_list; + + scope_id do_alloc (void) + { + scope_id retval; + + set_iterator p = free_list.begin (); + + if (p != free_list.end ()) + { + retval = *p; + free_list.erase (p); + } + else + retval = next_available++; + + in_use.insert (retval); + + return retval; + } + + void do_free (scope_id scope) + { + set_iterator p = in_use.find (scope); + + if (p != in_use.end ()) + { + in_use.erase (p); + free_list.insert (scope); + } + else + error ("free_scope: scope %d not found!", scope); + } + + std::list<scope_id> do_scopes (void) const + { + std::list<scope_id> retval; + + for (set_const_iterator p = in_use.begin (); p != in_use.end (); p++) + retval.push_back (*p); + + retval.sort (); + + return retval; + } + }; + + class fcn_info; + + 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; + + // temporary variables forced into symbol table for parsing + static const unsigned int forced = 128; + + private: + + class + symbol_record_rep + { + public: + + symbol_record_rep (scope_id s, const std::string& nm, + const octave_value& v, unsigned int sc) + : decl_scope (s), curr_fcn (0), name (nm), value_stack (), + storage_class (sc), finfo (), valid (true), count (1) + { + value_stack.push_back (v); + } + + void force_variable (context_id context = xdefault_context) + { + if (context == xdefault_context) + context = active_context (); + + octave_value& val = varref (context); + + if (! val.is_defined ()) + mark_forced (); + } + + octave_value& varref (context_id context = xdefault_context) + { + if (is_global ()) + return symbol_table::global_varref (name); + else if (is_persistent ()) + return symbol_table::persistent_varref (name); + else + { + if (context == xdefault_context) + context = active_context (); + + context_id n = value_stack.size (); + while (n++ <= context) + value_stack.push_back (octave_value ()); + + return value_stack[context]; + } + } + + octave_value varval (context_id context = xdefault_context) const + { + if (is_global ()) + return symbol_table::global_varval (name); + else if (is_persistent ()) + return symbol_table::persistent_varval (name); + else + { + if (context == xdefault_context) + context = active_context (); + + if (context < value_stack.size ()) + return value_stack[context]; + else + return octave_value (); + } + } + + void push_context (scope_id s) + { + if (! (is_persistent () || is_global ()) + && s == scope ()) + value_stack.push_back (octave_value ()); + } + + // If pop_context returns 0, we are out of values and this element + // of the symbol table should be deleted. This can happen for + // functions like + // + // function foo (n) + // if (n > 0) + // foo (n-1); + // else + // eval ("x = 1"); + // endif + // endfunction + // + // Here, X should only exist in the final stack frame. + + size_t pop_context (scope_id s) + { + size_t retval = 1; + + if (! (is_persistent () || is_global ()) + && s == scope ()) + { + value_stack.pop_back (); + retval = value_stack.size (); + } + + return retval; + } + + void clear (void) { clear (scope ()); } + + void clear (scope_id s) + { + if (! (is_hidden () || is_inherited ()) + && s == scope ()) + { + if (is_global ()) + unmark_global (); + + if (is_persistent ()) + { + symbol_table::persistent_varref (name) + = varval (); + + unmark_persistent (); + } + + varref () = octave_value (); + } + } + + bool is_defined (context_id context = xdefault_context) const + { + if (context == xdefault_context) + context = active_context (); + + return varval (context).is_defined (); + } + + bool is_valid (void) const + { + return valid; + } + + bool is_variable (context_id context) const + { + if (context == xdefault_context) + context = active_context (); + + return (! is_local () || is_defined (context) || is_forced ()); + } + + 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; } + bool is_forced (void) const { return storage_class & forced; } + + 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 mark_forced (void) { storage_class |= forced; } + + 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 unmark_forced (void) { storage_class &= ~forced; } + + 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 invalidate (void) + { + valid = false; + } + + void erase_persistent (void) + { + unmark_persistent (); + symbol_table::erase_persistent (name); + } + + context_id active_context (void) const; + + scope_id scope (void) const { return decl_scope; } + + void set_curr_fcn (octave_user_function *fcn) + { + curr_fcn = fcn; + } + + symbol_record_rep *dup (scope_id new_scope) const + { + return new symbol_record_rep (new_scope, name, varval (), + storage_class); + } + + void dump (std::ostream& os, const std::string& prefix) const; + + scope_id decl_scope; + + octave_user_function* curr_fcn; + + std::string name; + + std::deque<octave_value> value_stack; + + unsigned int storage_class; + + fcn_info *finfo; + + bool valid; + + octave_refcount<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 (scope_id s = xcurrent_scope, + const std::string& nm = std::string (), + const octave_value& v = octave_value (), + unsigned int sc = local) + : rep (new symbol_record_rep (s, nm, v, sc)) { } + + symbol_record (const symbol_record& sr) + : rep (sr.rep) + { + rep->count++; + } + + symbol_record& operator = (const symbol_record& sr) + { + if (this != &sr) + { + if (--rep->count == 0) + delete rep; + + rep = sr.rep; + rep->count++; + } + + return *this; + } + + ~symbol_record (void) + { + if (--rep->count == 0) + delete rep; + } + + symbol_record dup (scope_id new_scope) const + { + return symbol_record (rep->dup (new_scope)); + } + + const std::string& name (void) const { return rep->name; } + + octave_value + find (const octave_value_list& args = octave_value_list ()) const; + + void force_variable (context_id context = xdefault_context) + { + rep->force_variable (context); + } + + octave_value& varref (context_id context = xdefault_context) + { + return rep->varref (context); + } + + octave_value varval (context_id context = xdefault_context) const + { + return rep->varval (context); + } + + void push_context (scope_id s) { rep->push_context (s); } + + size_t pop_context (scope_id s) { return rep->pop_context (s); } + + void clear (void) { rep->clear (); } + + void clear (scope_id s) { rep->clear (s); } + + bool is_defined (context_id context = xdefault_context) const + { + return rep->is_defined (context); + } + + bool is_valid (void) const + { + return rep->is_valid (); + } + + bool is_variable (context_id context = xdefault_context) const + { + return rep->is_variable (context); + } + + 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 (); } + bool is_forced (void) const { return rep->is_forced (); } + + 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 mark_forced (void) { rep->mark_forced (); } + + 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 unmark_forced (void) { rep->unmark_forced (); } + + void init_persistent (void) { rep->init_persistent (); } + + void erase_persistent (void) { rep->erase_persistent (); } + + void invalidate (void) { rep->invalidate (); } + + context_id active_context (void) const { return rep->active_context (); } + + scope_id scope (void) const { return rep->scope (); } + + unsigned int xstorage_class (void) const { return rep->storage_class; } + + void set_curr_fcn (octave_user_function *fcn) { rep->set_curr_fcn (fcn); } + + void + dump (std::ostream& os, const std::string& prefix = std::string ()) const + { + rep->dump (os, prefix); + } + + private: + + symbol_record_rep *rep; + + symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { } + }; + + // Always access a symbol from the current scope. + // Useful for scripts, as they may be executed in more than one scope. + class + symbol_reference + { + public: + symbol_reference (void) : scope (-1) {} + + symbol_reference (symbol_record record, + scope_id curr_scope = symbol_table::current_scope ()) + : scope (curr_scope), sym (record) + {} + + symbol_reference& operator = (const symbol_reference& ref) + { + scope = ref.scope; + sym = ref.sym; + return *this; + } + + // The name is the same regardless of scope. + const std::string& name (void) const { return sym.name (); } + + symbol_record *operator-> (void) + { + update (); + return &sym; + } + + symbol_record *operator-> (void) const + { + update (); + return &sym; + } + + // can be used to place symbol_reference in maps, we don't overload < as + // it doesn't make any sense for symbol_reference + struct comparator + { + bool operator ()(const symbol_reference& lhs, + const symbol_reference& rhs) const + { + return lhs.name () < rhs.name (); + } + }; + private: + void update (void) const + { + scope_id curr_scope = symbol_table::current_scope (); + if (scope != curr_scope || ! sym.is_valid ()) + { + scope = curr_scope; + sym = symbol_table::insert (sym.name ()); + } + } + + mutable scope_id scope; + mutable symbol_record sym; + }; + + class + fcn_info + { + public: + + typedef std::map<std::string, std::string> dispatch_map_type; + + typedef std::map<scope_id, octave_value>::const_iterator scope_val_const_iterator; + typedef std::map<scope_id, octave_value>::iterator scope_val_iterator; + + typedef std::map<std::string, octave_value>::const_iterator str_val_const_iterator; + typedef std::map<std::string, octave_value>::iterator str_val_iterator; + + typedef dispatch_map_type::const_iterator dispatch_map_const_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 (), dispatch_map (), + 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 (const octave_value_list& args, bool local_funcs); + + octave_value builtin_find (void); + + 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 (const octave_value_list& args, bool local_funcs) + { + return find (args, local_funcs); + } + + void lock_subfunction (scope_id scope) + { + scope_val_iterator p = subfunctions.find (scope); + + if (p != subfunctions.end ()) + p->second.lock (); + } + + void unlock_subfunction (scope_id scope) + { + scope_val_iterator p = subfunctions.find (scope); + + if (p != subfunctions.end ()) + p->second.unlock (); + } + + std::pair<std::string, octave_value> + subfunction_defined_in_scope (scope_id scope) const + { + scope_val_const_iterator p = subfunctions.find (scope); + + return p == subfunctions.end () + ? std::pair<std::string, octave_value> () + : std::pair<std::string, octave_value> (name, p->second); + } + + void erase_subfunction (scope_id scope) + { + scope_val_iterator p = subfunctions.find (scope); + + if (p != subfunctions.end ()) + subfunctions.erase (p); + } + + void mark_subfunction_in_scope_as_private (scope_id scope, + const std::string& class_name); + + 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; + } + + template <class T> + void + clear_unlocked (std::map<T, octave_value>& map) + { + typename std::map<T, octave_value>::iterator p = map.begin (); + + while (p != map.end ()) + { + if (p->second.islocked ()) + p++; + else + map.erase (p++); + } + } + + void clear_autoload_function (void) + { + if (! autoload_function.islocked ()) + autoload_function = octave_value (); + } + + // We also clear command line functions here, as these are both + // "user defined" + void clear_user_function (void) + { + if (! function_on_path.islocked ()) + { + function_on_path.erase_subfunctions (); + + function_on_path = octave_value (); + } + + if (! cmdline_function.islocked ()) + cmdline_function = octave_value (); + } + + void clear_mex_function (void) + { + if (function_on_path.is_mex_function ()) + clear_user_function (); + } + + void clear (void) + { + clear_unlocked (subfunctions); + clear_unlocked (private_functions); + clear_unlocked (class_constructors); + clear_unlocked (class_methods); + clear_autoload_function (); + clear_user_function (); + } + + 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; } + + void dump (std::ostream& os, const std::string& prefix) const; + + std::string name; + + // Scope id to function object. + std::map<scope_id, octave_value> subfunctions; + + // Directory name to function object. + std::map<std::string, octave_value> private_functions; + + // Class name to function object. + std::map<std::string, octave_value> class_constructors; + + // Dispatch type to function object. + std::map<std::string, octave_value> 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; + + octave_refcount<size_t> count; + + private: + + octave_value xfind (const octave_value_list& args, bool local_funcs); + + octave_value x_builtin_find (void); + + // 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& fi) : rep (fi.rep) + { + rep->count++; + } + + fcn_info& operator = (const fcn_info& fi) + { + if (this != &fi) + { + if (--rep->count == 0) + delete rep; + + rep = fi.rep; + rep->count++; + } + + return *this; + } + + ~fcn_info (void) + { + if (--rep->count == 0) + delete rep; + } + + octave_value find (const octave_value_list& args = octave_value_list (), + bool local_funcs = true) + { + return rep->find (args, local_funcs); + } + + octave_value builtin_find (void) + { + return rep->builtin_find (); + } + + 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_cmdline_function (void) const + { + return rep->cmdline_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 (const octave_value_list& args = octave_value_list (), + bool local_funcs = true) + { + return rep->find_function (args, local_funcs); + } + + void lock_subfunction (scope_id scope) + { + rep->lock_subfunction (scope); + } + + void unlock_subfunction (scope_id scope) + { + rep->unlock_subfunction (scope); + } + + std::pair<std::string, octave_value> + subfunction_defined_in_scope (scope_id scope = xcurrent_scope) const + { + return rep->subfunction_defined_in_scope (scope); + } + + void erase_subfunction (scope_id scope) + { + rep->erase_subfunction (scope); + } + + void mark_subfunction_in_scope_as_private (scope_id scope, + const std::string& class_name) + { + rep->mark_subfunction_in_scope_as_private (scope, class_name); + } + + 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_autoload_function (void) { rep->clear_autoload_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 (); + } + + void + dump (std::ostream& os, const std::string& prefix = std::string ()) const + { + rep->dump (os, prefix); + } + + 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 context_id current_context (void) { return xcurrent_context; } + + static scope_id alloc_scope (void) { return scope_id_cache::alloc (); } + + 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 ()) + { + symbol_table *inst = new symbol_table (scope); + + if (inst) + all_instances[scope] = instance = inst; + } + else + instance = p->second; + + xcurrent_scope = scope; + xcurrent_context = 0; + } + } + + static void set_scope_and_context (scope_id scope, context_id context) + { + 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 ()) + error ("scope not found!"); + else + { + instance = p->second; + + xcurrent_scope = scope; + + xcurrent_context = context; + } + } + else + xcurrent_context = context; + } + } + + static void erase_scope (scope_id scope) + { + assert (scope != xglobal_scope); + + all_instances_iterator p = all_instances.find (scope); + + if (p != all_instances.end ()) + { + delete p->second; + + all_instances.erase (p); + + free_scope (scope); + } + } + + static void erase_subfunctions_in_scope (scope_id scope) + { + for (fcn_table_iterator q = fcn_table.begin (); + q != fcn_table.end (); q++) + q->second.erase_subfunction (scope); + } + + static void + mark_subfunctions_in_scope_as_private (scope_id scope, + const std::string& class_name) + { + for (fcn_table_iterator q = fcn_table.begin (); + q != fcn_table.end (); q++) + q->second.mark_subfunction_in_scope_as_private (scope, class_name); + } + + static scope_id dup_scope (scope_id 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 (scope); + + if (new_symbol_table) + { + all_instances[new_scope] = new_symbol_table; + + inst->do_dup_scope (*new_symbol_table); + + retval = new_scope; + } + } + + return retval; + } + + static std::list<scope_id> scopes (void) + { + return scope_id_cache::scopes (); + } + + 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 (scope); + } + + static void + inherit (scope_id scope, scope_id donor_scope, context_id donor_context) + { + symbol_table *inst = get_instance (scope); + + if (inst) + { + symbol_table *donor_symbol_table = get_instance (donor_scope); + + if (donor_symbol_table) + inst->do_inherit (*donor_symbol_table, donor_context); + } + } + + 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, + const octave_value_list& args = octave_value_list (), + bool skip_variables = false, + bool local_funcs = true); + + static octave_value builtin_find (const std::string& name); + + // Insert a new name in the table. + static symbol_record& insert (const std::string& name) + { + static symbol_record foobar; + + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_insert (name) : foobar; + } + + static void force_variable (const std::string& name, + scope_id scope = xcurrent_scope, + context_id context = xdefault_context) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_force_variable (name, context); + } + + static octave_value& varref (const std::string& name, + scope_id scope = xcurrent_scope, + context_id context = xdefault_context) + { + static octave_value foobar; + + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_varref (name, context) : foobar; + } + + static octave_value varval (const std::string& name, + scope_id scope = xcurrent_scope, + context_id context = xdefault_context) + { + symbol_table *inst = get_instance (scope); + + return inst ? inst->do_varval (name, context) : octave_value (); + } + + static octave_value& + global_varref (const std::string& name) + { + global_table_iterator p = global_table.find (name); + + return (p == global_table.end ()) ? global_table[name] : p->second; + } + + static octave_value + global_varval (const std::string& name) + { + global_table_const_iterator p = global_table.find (name); + + return (p != global_table.end ()) ? p->second : octave_value (); + } + + static octave_value& + top_level_varref (const std::string& name) + { + return varref (name, top_scope (), 0); + } + + static octave_value + top_level_varval (const std::string& name) + { + return varval (name, top_scope (), 0); + } + + static octave_value& persistent_varref (const std::string& name) + { + static octave_value foobar; + + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_persistent_varref (name) : foobar; + } + + static octave_value persistent_varval (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_persistent_varval (name) : octave_value (); + } + + static void erase_persistent (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_erase_persistent (name); + } + + static bool is_variable (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_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) + { + fcn_table_const_iterator p = fcn_table.find (name); + + 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) + { + fcn_table_const_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); + + return (p != fcn_table.end ()) + ? p->second.find_autoload () : octave_value (); + } + + static octave_value + find_function (const std::string& name, + const octave_value_list& args = octave_value_list (), + bool local_funcs = true); + + 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 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); + + finfo.install_cmdline_function (fcn); + + fcn_table[name] = finfo; + } + } + + static void install_subfunction (const std::string& name, + const octave_value& fcn, + scope_id 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_nestfunction (const std::string& name, + const octave_value& fcn, + scope_id parent_scope); + + static void update_nest (scope_id scope) + { + symbol_table *inst = get_instance (scope); + if (inst) + inst->do_update_nest (); + } + + 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; + } + } + + 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) + { + clear_variable (name); + } + + static void clear_all (void) + { + clear_variables (); + + clear_global_pattern ("*"); + + clear_functions (); + } + + static void clear_variables (scope_id scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_variables (); + } + + // This is split for unwind_protect. + static void clear_variables (void) + { + clear_variables (xcurrent_scope); + } + + static void clear_objects (scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_clear_objects (); + } + + static void unmark_forced_variables (scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + + if (inst) + inst->do_unmark_forced_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) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_clear_global (name); + } + + static void clear_variable (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_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) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_clear_global_pattern (pat); + } + + static void clear_variable_pattern (const std::string& pat) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_clear_variable_pattern (pat); + } + + static void clear_variable_regexp (const std::string& pat) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_clear_variable_regexp (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 ()); + } + + // This clears oct and mex files, incl. autoloads. + static void clear_dld_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_autoload_function (); + finfo.clear_user_function (); + } + } + + 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 bool set_class_relationship (const std::string& sup_class, + const std::string& inf_class); + + static bool is_superiorto (const std::string& a, const std::string& b); + + 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); + + 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 (void) + { + if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) + error ("invalid call to xymtab::push_context"); + else + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_push_context (); + } + } + + static void pop_context (void) + { + if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) + error ("invalid call to xymtab::pop_context"); + else + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_pop_context (); + } + } + + // For unwind_protect. + static void pop_context (void *) { pop_context (); } + + static void mark_automatic (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_mark_automatic (name); + } + + static void mark_hidden (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_mark_hidden (name); + } + + static void mark_global (const std::string& name) + { + symbol_table *inst = get_instance (xcurrent_scope); + + if (inst) + inst->do_mark_global (name); + } + + static std::list<symbol_record> + all_variables (scope_id scope = xcurrent_scope, + context_id context = xdefault_context, + bool defined_only = true) + { + symbol_table *inst = get_instance (scope); + + return inst + ? inst->do_all_variables (context, defined_only) : std::list<symbol_record> (); + } + + static std::list<symbol_record> glob (const std::string& pattern) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_glob (pattern) : std::list<symbol_record> (); + } + + static std::list<symbol_record> regexp (const std::string& pattern) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_regexp (pattern) : std::list<symbol_record> (); + } + + static std::list<symbol_record> glob_variables (const std::string& pattern) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> (); + } + + static std::list<symbol_record> regexp_variables (const std::string& pattern) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_regexp (pattern, true) : std::list<symbol_record> (); + } + + static std::list<symbol_record> + glob_global_variables (const std::string& pattern) + { + std::list<symbol_record> retval; + + glob_match pat (pattern); + + for (global_table_const_iterator p = global_table.begin (); + p != global_table.end (); p++) + { + // We generate a list of symbol_record objects so that + // the results from glob_variables and glob_global_variables + // may be handled the same way. + + if (pat.match (p->first)) + retval.push_back (symbol_record (xglobal_scope, + p->first, p->second, + symbol_record::global)); + } + + return retval; + } + + static std::list<symbol_record> + regexp_global_variables (const std::string& pattern) + { + std::list<symbol_record> retval; + + ::regexp pat (pattern); + + for (global_table_const_iterator p = global_table.begin (); + p != global_table.end (); p++) + { + // We generate a list of symbol_record objects so that + // the results from regexp_variables and regexp_global_variables + // may be handled the same way. + + if (pat.is_match (p->first)) + retval.push_back (symbol_record (xglobal_scope, + p->first, p->second, + symbol_record::global)); + } + + return retval; + } + + static std::list<symbol_record> glob_variables (const string_vector& patterns) + { + std::list<symbol_record> retval; + + size_t len = patterns.length (); + + for (size_t i = 0; i < len; i++) + { + std::list<symbol_record> tmp = glob_variables (patterns[i]); + + retval.insert (retval.begin (), tmp.begin (), tmp.end ()); + } + + return retval; + } + + static std::list<symbol_record> regexp_variables + (const string_vector& patterns) + { + std::list<symbol_record> retval; + + size_t len = patterns.length (); + + for (size_t i = 0; i < len; i++) + { + std::list<symbol_record> tmp = regexp_variables (patterns[i]); + + retval.insert (retval.begin (), tmp.begin (), tmp.end ()); + } + + return retval; + } + + static std::list<std::string> user_function_names (void) + { + std::list<std::string> 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; + } + + static std::list<std::string> global_variable_names (void) + { + std::list<std::string> retval; + + for (global_table_const_iterator p = global_table.begin (); + p != global_table.end (); p++) + retval.push_back (p->first); + + retval.sort (); + + return retval; + } + + static std::list<std::string> top_level_variable_names (void) + { + symbol_table *inst = get_instance (xtop_scope); + + return inst ? inst->do_variable_names () : std::list<std::string> (); + } + + static std::list<std::string> variable_names (void) + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_variable_names () : std::list<std::string> (); + } + + static std::list<std::string> built_in_function_names (void) + { + std::list<std::string> retval; + + for (fcn_table_const_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 (); + + return retval; + } + + static std::list<std::string> cmdline_function_names (void) + { + std::list<std::string> retval; + + for (fcn_table_const_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + octave_value fcn = p->second.find_cmdline_function (); + + if (fcn.is_defined ()) + retval.push_back (p->first); + } + + if (! retval.empty ()) + retval.sort (); + + return retval; + } + + static bool is_local_variable (const std::string& name) + { + if (xcurrent_scope == xglobal_scope) + return false; + else + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_is_local_variable (name) : false; + } + } + + static bool is_global (const std::string& name) + { + if (xcurrent_scope == xglobal_scope) + return true; + else + { + symbol_table *inst = get_instance (xcurrent_scope); + + return inst ? inst->do_is_global (name) : false; + } + } + + static void dump (std::ostream& os, scope_id scope = xcurrent_scope); + + static void dump_global (std::ostream& os); + + static void dump_functions (std::ostream& os); + + static void cache_name (scope_id scope, const std::string& name) + { + symbol_table *inst = get_instance (scope, false); + + if (inst) + inst->do_cache_name (name); + } + + static void lock_subfunctions (scope_id scope = xcurrent_scope) + { + for (fcn_table_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + p->second.lock_subfunction (scope); + } + + static void unlock_subfunctions (scope_id scope = xcurrent_scope) + { + for (fcn_table_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + p->second.unlock_subfunction (scope); + } + + static void free_scope (scope_id scope) + { + if (scope == xglobal_scope || scope == xtop_scope) + error ("can't free global or top-level scopes!"); + else + symbol_table::scope_id_cache::free (scope); + } + + static void stash_dir_name_for_subfunctions (scope_id scope, + const std::string& dir_name); + + static void add_to_parent_map (const std::string& classname, + const std::list<std::string>& parent_list) + { + parent_map[classname] = parent_list; + } + + static std::list<std::string> + parent_classes (const std::string& dispatch_type) + { + std::list<std::string> retval; + + const_parent_map_iterator it = parent_map.find (dispatch_type); + + if (it != parent_map.end ()) + retval = it->second; + + for (std::list<std::string>::const_iterator lit = retval.begin (); + lit != retval.end (); lit++) + { + // Search for parents of parents and append them to the list. + + // FIXME -- should we worry about a circular inheritance graph? + + std::list<std::string> parents = parent_classes (*lit); + + if (! parents.empty ()) + retval.insert (retval.end (), parents.begin (), parents.end ()); + } + + return retval; + } + + static octave_user_function *get_curr_fcn (scope_id scope = xcurrent_scope) + { + symbol_table *inst = get_instance (scope); + return inst->curr_fcn; + } + + static void set_curr_fcn (octave_user_function *curr_fcn, + scope_id scope = xcurrent_scope) + { + assert (scope != xtop_scope && scope != xglobal_scope); + symbol_table *inst = get_instance (scope); + // FIXME: normally, functions should not usurp each other's scope. + // If for any incredible reason this is needed, call + // set_user_function (0, scope) first. This may cause problems with + // nested functions, as the curr_fcn of symbol_records must be updated. + assert (inst->curr_fcn == 0 || curr_fcn == 0); + inst->curr_fcn = curr_fcn; + } + + static void cleanup (void); + +private: + + // No copying! + + symbol_table (const symbol_table&); + + symbol_table& operator = (const symbol_table&); + + typedef std::map<std::string, symbol_record>::const_iterator table_const_iterator; + typedef std::map<std::string, symbol_record>::iterator table_iterator; + + typedef std::map<std::string, octave_value>::const_iterator global_table_const_iterator; + typedef std::map<std::string, octave_value>::iterator global_table_iterator; + + typedef std::map<std::string, octave_value>::const_iterator persistent_table_const_iterator; + typedef std::map<std::string, octave_value>::iterator persistent_table_iterator; + + typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator; + typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator; + + typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator; + typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator; + + // The scope of this symbol table. + scope_id my_scope; + + // Name for this table (usually the file name of the function + // corresponding to the scope); + std::string table_name; + + // Map from symbol names to symbol info. + std::map<std::string, symbol_record> table; + + // Child nested functions. + std::vector<symbol_table*> nest_children; + + // Parent nested function (may be null). + symbol_table *nest_parent; + + // The associated user code (may be null). + octave_user_function *curr_fcn; + + // Map from names of global variables to values. + static std::map<std::string, octave_value> global_table; + + // Map from names of persistent variables to values. + std::map<std::string, octave_value> persistent_table; + + // Pointer to symbol table for current scope (variables only). + static symbol_table *instance; + + // Map from scope id to symbol table instances. + static std::map<scope_id, symbol_table*> all_instances; + + // Map from function names to function info (subfunctions, private + // functions, class constructors, class methods, etc.) + static std::map<std::string, fcn_info> fcn_table; + + // Mape from class names to set of classes that have lower + // precedence. + static std::map<std::string, std::set<std::string> > class_precedence_table; + + typedef std::map<std::string, std::set<std::string> >::const_iterator class_precedence_table_const_iterator; + typedef std::map<std::string, std::set<std::string> >::iterator class_precedence_table_iterator; + + // Map from class names to parent class names. + static std::map<std::string, std::list<std::string> > parent_map; + + typedef std::map<std::string, std::list<std::string> >::const_iterator const_parent_map_iterator; + typedef std::map<std::string, std::list<std::string> >::iterator parent_map_iterator; + + static const scope_id xglobal_scope; + static const scope_id xtop_scope; + + static scope_id xcurrent_scope; + + static context_id xcurrent_context; + + static const context_id xdefault_context = static_cast<context_id> (-1); + + symbol_table (scope_id scope) + : my_scope (scope), table_name (), table (), nest_children (), nest_parent (0), + curr_fcn (0), persistent_table () { } + + ~symbol_table (void) { } + + static symbol_table *get_instance (scope_id scope, bool create = true) + { + symbol_table *retval = 0; + + bool ok = true; + + if (scope != xglobal_scope) + { + if (scope == xcurrent_scope) + { + if (! instance && create) + { + symbol_table *inst = new symbol_table (scope); + + if (inst) + { + all_instances[scope] = instance = inst; + + if (scope == xtop_scope) + instance->do_cache_name ("top-level"); + } + } + + if (! instance) + ok = false; + + retval = instance; + } + else + { + all_instances_iterator p = all_instances.find (scope); + + if (p == all_instances.end ()) + { + if (create) + { + retval = new symbol_table (scope); + + if (retval) + all_instances[scope] = retval; + else + ok = false; + } + else + ok = false; + } + else + retval = p->second; + } + } + + if (! ok) + error ("unable to %s symbol_table object for scope %d!", + create ? "create" : "find", scope); + + return retval; + } + + void add_nest_child (symbol_table& st) + { + assert (!st.nest_parent); + nest_children.push_back (&st); + st.nest_parent = this; + } + + void insert_symbol_record (const symbol_record& sr) + { + table[sr.name ()] = sr; + } + + void + do_dup_scope (symbol_table& new_symbol_table) const + { + for (table_const_iterator p = table.begin (); p != table.end (); p++) + new_symbol_table.insert_symbol_record (p->second.dup (new_symbol_table.my_scope)); + } + + 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 (symbol_table& donor_table, context_id donor_context) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record& sr = p->second; + + if (! (sr.is_automatic () || sr.is_formal ())) + { + std::string nm = sr.name (); + + if (nm != "__retval__") + { + octave_value val = donor_table.do_varval (nm, donor_context); + + if (val.is_defined ()) + { + sr.varref (0) = val; + + sr.mark_inherited (); + } + } + } + } + } + + static fcn_info *get_fcn_info (const std::string& name) + { + fcn_table_iterator p = fcn_table.find (name); + return p != fcn_table.end () ? &p->second : 0; + } + + octave_value + do_find (const std::string& name, const octave_value_list& args, + bool skip_variables, bool local_funcs); + + octave_value do_builtin_find (const std::string& name); + + symbol_record& do_insert (const std::string& name) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + { + symbol_record parent_symbol; + + if (nest_parent && nest_parent->look_nonlocal (name, parent_symbol)) + return table[name] = parent_symbol; + else + return table[name] = symbol_record (my_scope, name, octave_value ()); + } + else + return p->second; + } + + void do_force_variable (const std::string& name, context_id context) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + { + symbol_record& sr = do_insert (name); + + sr.force_variable (context); + } + else + p->second.force_variable (context); + } + + octave_value& do_varref (const std::string& name, context_id context) + { + table_iterator p = table.find (name); + + if (p == table.end ()) + { + symbol_record& sr = do_insert (name); + + return sr.varref (context); + } + else + return p->second.varref (context); + } + + octave_value do_varval (const std::string& name, context_id context) const + { + table_const_iterator p = table.find (name); + + return (p != table.end ()) ? p->second.varval (context) : 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) + { + persistent_table_const_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; + + table_const_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 (my_scope); + } + + void do_pop_context (void) + { + for (table_iterator p = table.begin (); p != table.end (); ) + { + if (p->second.pop_context (my_scope) == 0) + table.erase (p++); + else + p++; + } + } + + void do_clear_variables (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + p->second.clear (my_scope); + } + + void do_clear_objects (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + { + symbol_record& sr = p->second; + octave_value& val = sr.varref (); + if (val.is_object ()) + p->second.clear (my_scope); + } + } + + void do_unmark_forced_variables (void) + { + for (table_iterator p = table.begin (); p != table.end (); p++) + p->second.unmark_forced (); + } + + void do_clear_global (const std::string& name) + { + table_iterator p = table.find (name); + + if (p != table.end ()) + { + symbol_record& sr = p->second; + + if (sr.is_global ()) + sr.unmark_global (); + } + + global_table_iterator q = global_table.find (name); + + if (q != global_table.end ()) + global_table.erase (q); + + } + + void do_clear_variable (const std::string& name) + { + table_iterator p = table.find (name); + + if (p != table.end ()) + p->second.clear (my_scope); + } + + 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; + + if (sr.is_global () && pattern.match (sr.name ())) + sr.unmark_global (); + } + + + for (global_table_iterator q = global_table.begin (); + q != global_table.end ();) + { + if (pattern.match (q->first)) + global_table.erase (q++); //Gotta be careful to not + //invalidate iterators + else + q++; + } + + + } + + 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 (my_scope); + } + } + } + + void do_clear_variable_regexp (const std::string& pat) + { + ::regexp 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.is_match (sr.name ())) + sr.clear (my_scope); + } + } + } + + void do_mark_automatic (const std::string& name) + { + do_insert (name).mark_automatic (); + } + + void do_mark_hidden (const std::string& name) + { + do_insert (name).mark_hidden (); + } + + void do_mark_global (const std::string& name) + { + do_insert (name).mark_global (); + } + + std::list<symbol_record> + do_all_variables (context_id context, bool defined_only) const + { + std::list<symbol_record> retval; + + for (table_const_iterator p = table.begin (); p != table.end (); p++) + { + const symbol_record& sr = p->second; + + if (defined_only && ! sr.is_defined (context)) + continue; + + retval.push_back (sr); + } + + return retval; + } + + std::list<symbol_record> do_glob (const std::string& pattern, + bool vars_only = false) const + { + std::list<symbol_record> retval; + + glob_match pat (pattern); + + for (table_const_iterator p = table.begin (); p != table.end (); p++) + { + if (pat.match (p->first)) + { + const symbol_record& sr = p->second; + + if (vars_only && ! sr.is_variable ()) + continue; + + retval.push_back (sr); + } + } + + return retval; + } + + std::list<symbol_record> do_regexp (const std::string& pattern, + bool vars_only = false) const + { + std::list<symbol_record> retval; + + ::regexp pat (pattern); + + for (table_const_iterator p = table.begin (); p != table.end (); p++) + { + if (pat.is_match (p->first)) + { + const symbol_record& sr = p->second; + + if (vars_only && ! sr.is_variable ()) + continue; + + retval.push_back (sr); + } + } + + return retval; + } + + std::list<std::string> do_variable_names (void) + { + std::list<std::string> retval; + + for (table_const_iterator p = table.begin (); p != table.end (); p++) + { + if (p->second.is_variable ()) + retval.push_back (p->first); + } + + retval.sort (); + + return retval; + } + + static std::map<std::string, octave_value> + subfunctions_defined_in_scope (scope_id scope = xcurrent_scope) + { + std::map<std::string, octave_value> retval; + + for (fcn_table_const_iterator p = fcn_table.begin (); + p != fcn_table.end (); p++) + { + std::pair<std::string, octave_value> tmp + = p->second.subfunction_defined_in_scope (scope); + + std::string nm = tmp.first; + + if (! nm.empty ()) + retval[nm] = tmp.second; + } + + return retval; + } + + bool do_is_local_variable (const std::string& name) const + { + table_const_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 + { + table_const_iterator p = table.find (name); + + return p != table.end () && p->second.is_global (); + } + + void do_dump (std::ostream& os); + + void do_cache_name (const std::string& name) { table_name = name; } + + void do_update_nest (void); + + bool look_nonlocal (const std::string& name, symbol_record& result) + { + table_iterator p = table.find (name); + if (p == table.end ()) + { + if (nest_parent) + return nest_parent->look_nonlocal (name, result); + } + else if (! p->second.is_automatic ()) + { + result = p->second; + return true; + } + + return false; + } +}; + +extern bool out_of_date_check (octave_value& function, + const std::string& dispatch_type = std::string (), + bool check_relative = true); + +extern OCTINTERP_API std::string +get_dispatch_type (const octave_value_list& args); +extern OCTINTERP_API std::string +get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type); + +#endif