Mercurial > hg > octave-lyh
diff src/symtab.h @ 14544:be18c9e359bf
Nested function support (bug #35772)
* src/oct-parse.yy (push_fcn_symtab, recover_from_parsing_function)
(eval_string): Keep track of a stack of nested functions.
(parse_fcn_file): Keep track of a stack of nested functions and remove
warning that nested functions are not supported.
(frob_function): Call symbol_table::install_nestfunction for nested functions.
(finish_function): Call symbol_table::update_nest on top level functions.
* src/ov-fcn-handle.cc (octave_fcn_handle::octave_fcn_handle):
Error when creating a handle to a nested function.
* src/ov-usr-fcn.cc (octave_user_function::octave_user_function):
Initialize new members.
(octave_user_function::do_multi_index_op): Use active_context to
determine execution context.
* src/ov-usr-fcn.h (octave_user_function::active_context,
octave_user_function::is_nested_function,
octave_user_function::mark_as_nested_function): New functions.
* src/pt-id.h (symbol_table::xsym): Check symbol validity.
* src/symtab.cc (symbol_table::symbol_record::symbol_record_rep::active_context,
symbol_table::install_nestfunction, symbol_table::do_update_nest):
New functions.
(symbol_table::symbol_record::symbol_record_rep::dump): Use varval ()
instead of varval (current_context).
(symbol_table::fcn_info::fcn_info_rep::xfind,
symbol_table::fcn_info::fcn_info_rep::x_builtin_find): Allow for
parents of parents in subfunction search.
* src/symtab.h (symbol_table::symbol_record::symbol_record_rep::symbol_record_rep,
symbol_table::symbol_record::symbol_record): New parameter,
decl_scope.
(symbol_table::symbol_record::symbol_record_rep::force_variable,
symbol_table::symbol_record::force_variable,
symbol_table::symbol_record::symbol_record_rep::varref,
symbol_table::symbol_record::varref,
symbol_table::symbol_record::symbol_record_rep::varval,
symbol_table::symbol_record::varval,
symbol_table::symbol_record::symbol_record_rep::is_defined,
symbol_table::symbol_record::is_defined,
symbol_table::symbol_record::symbol_record_rep::is_variable,
symbol_table::symbol_record::is_variable,
symbol_table::symbol_record::varval,
symbol_table::symbol_record::symbol_record_rep::varval): Use xdefault_context.
symbol_table::symbol_record::symbol_record_rep::push_context,
symbol_table::symbol_record::push_context,
symbol_table::symbol_record::symbol_record_rep::pop_context,
symbol_table::symbol_record::pop_context,
symbol_table::symbol_record::symbol_record_rep::clear,
symbol_table::symbol_record::clear): Only work when the decl_scope of
the symbol is the active scope.
(symbol_table::symbol_record::symbol_record_rep::is_valid,
symbol_table::symbol_record::is_valid,
symbol_table::symbol_record::symbol_record_rep::invalidate,
symbol_table::symbol_record::invalidate,
symbol_table::symbol_record::symbol_record_rep::set_curr_fcn,
symbol_table::symbol_record::set_curr_fcn,
symbol_table::symbol_record::symbol_record_rep::scope,
symbol_table::symbol_record::scope,
symbol_table::symbol_record::active_context,
symbol_table::update_nest, symbol_table::symbol_table,
symbol_table::add_nest_child, symbol_table::look_nonlocal): New functions.
(symbol_table::symbol_record::symbol_record_rep::init_persistent):
Init to xdefault_context instead of xcurrent_context.
(symbol_table::symbol_record::symbol_record_rep::dup,
symbol_table::symbol_record::dup): New parameter, scope.
(symbol_table::set_scope, symbol_table::dup_scope,
symbol_table:;get_instance): Pass scope_id to symbol_table constructor.
(symbol_table::find_symbol, symbol_table::glob_global_variables,
symbol_table::regexp_global_variables): Specify scope when creating
symbol_record.
(symbol_table::force_variable, symbol_table::varref,
symbol_table::varval, symbol_table::all_variables): Default to
xdefault_context instead of xcurrent_context.
(symbol_table::do_dup_scope): Pass scope of new symbol table to symbol
dup.
(symbol_table::do_insert): Check nest_parent for nonlocals.
(symbol_table::do_push_context, symbol_table::do_pop_context,
symbol_table::do_clear_variables, symbol_table::do_clear_objects,
symbol_table::do_clear_variable, symbol_table::do_clear_variable_pattern,
symbol_table::do_clear_variable_regexp): Pass my_scope to symbol.
* test/Makefile.am: Include nest/module.mk.
* test/nest/arg_nest.m: New file.
* test/nest/arg_ret.m: New file.
* test/nest/module.mk: New file.
* test/nest/no_closure.m: New file.
* test/nest/persistent_nest.m: New file.
* test/nest/recursive_nest.m: New file.
* test/nest/recursive_nest2.m: New file.
* test/nest/recursive_nest3.m: New file.
* test/nest/scope0.m: New file.
* test/nest/scope1.m: New file.
* test/nest/scope2.m: New file.
* test/nest/scope3.m: New file.
* test/nest/script_nest.m: New file.
* test/nest/script_nest_script.m: New file.
* test/nest/test_nest.m: New file.
* test/nest/varg_nest.m: New file.
* test/nest/varg_nest2.m: New file.
author | Max Brister <max@2bass.com> |
---|---|
date | Tue, 10 Apr 2012 20:42:22 -0400 |
parents | 72c96de7a403 |
children | e4d380c01dcf 460a3c6d8bf1 f25d2224fa02 |
line wrap: on
line diff
--- a/src/symtab.h +++ b/src/symtab.h @@ -206,22 +206,26 @@ { public: - symbol_record_rep (const std::string& nm, const octave_value& v, - unsigned int sc) - : name (nm), value_stack (), storage_class (sc), finfo (), count (1) + 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) + 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) + octave_value& varref (context_id context = xdefault_context) { if (is_global ()) return symbol_table::global_varref (name); @@ -229,6 +233,9 @@ 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 ()); @@ -237,7 +244,7 @@ } } - octave_value varval (context_id context) const + octave_value varval (context_id context = xdefault_context) const { if (is_global ()) return symbol_table::global_varval (name); @@ -245,6 +252,9 @@ return symbol_table::persistent_varval (name); else { + if (context == xdefault_context) + context = active_context (); + if (context < value_stack.size ()) return value_stack[context]; else @@ -252,9 +262,10 @@ } } - void push_context (void) + void push_context (scope_id s) { - if (! (is_persistent () || is_global ())) + if (! (is_persistent () || is_global ()) + && s == scope ()) value_stack.push_back (octave_value ()); } @@ -272,11 +283,12 @@ // // Here, X should only exist in the final stack frame. - size_t pop_context (void) + size_t pop_context (scope_id s) { size_t retval = 1; - if (! (is_persistent () || is_global ())) + if (! (is_persistent () || is_global ()) + && s == scope ()) { value_stack.pop_back (); retval = value_stack.size (); @@ -285,9 +297,12 @@ return retval; } - void clear (void) + void clear (void) { clear (scope ()); } + + void clear (scope_id s) { - if (! (is_hidden () || is_inherited ())) + if (! (is_hidden () || is_inherited ()) + && s == scope ()) { if (is_global ()) unmark_global (); @@ -295,22 +310,33 @@ if (is_persistent ()) { symbol_table::persistent_varref (name) - = varval (xcurrent_context); + = varval (); unmark_persistent (); } - varref (xcurrent_context) = octave_value (); + varref () = octave_value (); } } - bool is_defined (context_id context) const + 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 ()); } @@ -355,31 +381,49 @@ void init_persistent (void) { - if (! is_defined (xcurrent_context)) + if (! is_defined ()) { mark_persistent (); - varref (xcurrent_context) = symbol_table::persistent_varval (name); + 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); } - symbol_record_rep *dup (void) const + context_id active_context (void) const; + + scope_id scope (void) const { return decl_scope; } + + void set_curr_fcn (octave_user_function *fcn) { - return new symbol_record_rep (name, varval (xcurrent_context), + 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; @@ -388,6 +432,8 @@ fcn_info *finfo; + bool valid; + octave_refcount<size_t> count; private: @@ -401,10 +447,11 @@ public: - symbol_record (const std::string& nm = std::string (), + 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 (nm, v, sc)) { } + : rep (new symbol_record_rep (s, nm, v, sc)) { } symbol_record (const symbol_record& sr) : rep (sr.rep) @@ -432,39 +479,50 @@ delete rep; } - symbol_record dup (void) const { return symbol_record (rep->dup ()); } + symbol_record dup (scope_id new_scope) const + { + return symbol_record (rep->dup (new_scope)); + } 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 = xcurrent_context) + 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 = xcurrent_context) + octave_value& varref (context_id context = xdefault_context) { return rep->varref (context); } - octave_value varval (context_id context = xcurrent_context) const + octave_value varval (context_id context = xdefault_context) const { return rep->varval (context); } - void push_context (void) { rep->push_context (); } - - size_t pop_context (void) { return rep->pop_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 (); } - bool is_defined (context_id context = xcurrent_context) const + void clear (scope_id s) { rep->clear (s); } + + bool is_defined (context_id context = xdefault_context) const { return rep->is_defined (context); } - bool is_variable (context_id context = xcurrent_context) const + bool is_valid (void) const + { + return rep->is_valid (); + } + + bool is_variable (context_id context = xdefault_context) const { return rep->is_variable (context); } @@ -500,8 +558,16 @@ 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 { @@ -928,7 +994,7 @@ if (p == all_instances.end ()) { - symbol_table *inst = new symbol_table (); + symbol_table *inst = new symbol_table (scope); if (inst) all_instances[scope] = instance = inst; @@ -1009,7 +1075,7 @@ { scope_id new_scope = alloc_scope (); - symbol_table *new_symbol_table = new symbol_table (); + symbol_table *new_symbol_table = new symbol_table (scope); if (new_symbol_table) { @@ -1034,7 +1100,8 @@ { symbol_table *inst = get_instance (scope); - return inst ? inst->do_find_symbol (name) : symbol_record (); + return inst ? inst->do_find_symbol (name) : + symbol_record (scope); } static void @@ -1074,7 +1141,7 @@ static void force_variable (const std::string& name, scope_id scope = xcurrent_scope, - context_id context = xcurrent_context) + context_id context = xdefault_context) { symbol_table *inst = get_instance (scope); @@ -1084,7 +1151,7 @@ static octave_value& varref (const std::string& name, scope_id scope = xcurrent_scope, - context_id context = xcurrent_context) + context_id context = xdefault_context) { static octave_value foobar; @@ -1095,7 +1162,7 @@ static octave_value varval (const std::string& name, scope_id scope = xcurrent_scope, - context_id context = xcurrent_context) + context_id context = xdefault_context) { symbol_table *inst = get_instance (scope); @@ -1263,6 +1330,17 @@ } } + 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) { @@ -1620,7 +1698,7 @@ static std::list<symbol_record> all_variables (scope_id scope = xcurrent_scope, - context_id context = xcurrent_context, + context_id context = xdefault_context, bool defined_only = true) { symbol_table *inst = get_instance (scope); @@ -1672,7 +1750,8 @@ // may be handled the same way. if (pat.match (p->first)) - retval.push_back (symbol_record (p->first, p->second, + retval.push_back (symbol_record (xglobal_scope, + p->first, p->second, symbol_record::global)); } @@ -1694,7 +1773,8 @@ // may be handled the same way. if (pat.is_match (p->first)) - retval.push_back (symbol_record (p->first, p->second, + retval.push_back (symbol_record (xglobal_scope, + p->first, p->second, symbol_record::global)); } @@ -1924,7 +2004,8 @@ 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. + // 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; } @@ -1953,6 +2034,9 @@ 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); @@ -1961,6 +2045,12 @@ // 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; @@ -2000,8 +2090,11 @@ static context_id xcurrent_context; - symbol_table (void) - : table_name (), table (), curr_fcn (0), persistent_table () { } + 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) { } @@ -2017,7 +2110,7 @@ { if (! instance && create) { - symbol_table *inst = new symbol_table (); + symbol_table *inst = new symbol_table (scope); if (inst) { @@ -2041,7 +2134,7 @@ { if (create) { - retval = new symbol_table (); + retval = new symbol_table (scope); if (retval) all_instances[scope] = retval; @@ -2063,6 +2156,13 @@ 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; @@ -2072,7 +2172,7 @@ 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.insert_symbol_record (p->second.dup (new_symbol_table.my_scope)); } symbol_record do_find_symbol (const std::string& name) @@ -2126,8 +2226,17 @@ { table_iterator p = table.find (name); - return p == table.end () - ? (table[name] = symbol_record (name)) : p->second; + 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) @@ -2207,15 +2316,15 @@ void do_push_context (void) { for (table_iterator p = table.begin (); p != table.end (); p++) - p->second.push_context (); + 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 () == 0) - table.erase (p++); + if (p->second.pop_context (my_scope) == 0) + table.erase (p++); else p++; } @@ -2224,7 +2333,7 @@ void do_clear_variables (void) { for (table_iterator p = table.begin (); p != table.end (); p++) - p->second.clear (); + p->second.clear (my_scope); } void do_clear_objects (void) @@ -2234,7 +2343,7 @@ symbol_record& sr = p->second; octave_value& val = sr.varref (); if (val.is_object()) - p->second.clear (); + p->second.clear (my_scope); } } @@ -2268,7 +2377,7 @@ table_iterator p = table.find (name); if (p != table.end ()) - p->second.clear (); + p->second.clear (my_scope); } void do_clear_global_pattern (const std::string& pat) @@ -2308,7 +2417,7 @@ if (sr.is_defined () || sr.is_global ()) { if (pattern.match (sr.name ())) - sr.clear (); + sr.clear (my_scope); } } } @@ -2324,7 +2433,7 @@ if (sr.is_defined () || sr.is_global ()) { if (pattern.is_match (sr.name ())) - sr.clear (); + sr.clear (my_scope); } } } @@ -2462,6 +2571,25 @@ 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,