Mercurial > hg > octave-nkf
changeset 15236:44d6ffdf9479
Disallow new variables in nested functions (bug #36271)
* src/ov-usr-fcn.cc (octave_user_function::bind_automatic_vars):
Use force_varref.
* src/variables.cc (bind_ans): Use force_varref.
* src/pt-id.cc (tree_identifier::rvalue, tree_identifier::lvalue):
Identify static workspace errors.
* src/pt-id.h (tree_identifier::static_workspace_error): New function.
* src/symtab.cc (symbol_table::do_update_nest): Mark static workspaces.
* src/symtab.h (symbol_table::symbol_record::symbol_record_rep::is_added_static,
symbol_table::symbol_record::symbol_record_rep::mark_added_static,
symbol_table::symbol_record::symbol_record_rep::unmark_added_static,
symbol_table::symbol_record::is_added_static,
symbol_table::symbol_record::mark_added_static,
symbol_table::symbol_record::unmark_added_static, symbol_table::force_varref):
New functions.
(symbol_table::symbol_table): Initialize static_workspace to false.
(symbol_table::do_insert): Added force_add parameter. Mark records as
added_static.
(symbol_table::do_varref): Added force_add parameter.
* test/nest/test_nest.m: Added nest_eval tests.
* test/nest/module.mk: Added nest/nest_eval.m.
* test/nest/nest_eval.m: New file.
author | Max Brister <max@2bass.com> |
---|---|
date | Tue, 17 Apr 2012 21:24:20 -0600 |
parents | ab3d4c1affee |
children | d65ef0fc5e05 |
files | libinterp/interpfcn/symtab.cc libinterp/interpfcn/symtab.h libinterp/interpfcn/variables.cc libinterp/octave-value/ov-usr-fcn.cc libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h test/nest/module.mk test/nest/nest_eval.m test/nest/test_nest.m |
diffstat | 9 files changed, 75 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/interpfcn/symtab.cc +++ b/libinterp/interpfcn/symtab.cc @@ -1492,8 +1492,11 @@ } } else if (nest_children.size ()) - for (table_iterator ti = table.begin (); ti != table.end (); ++ti) - ti->second.set_curr_fcn (curr_fcn); + { + static_workspace = true; + for (table_iterator ti = table.begin (); ti != table.end (); ++ti) + ti->second.set_curr_fcn (curr_fcn); + } for (std::vector<symbol_table*>::iterator iter = nest_children.begin (); iter != nest_children.end (); ++iter)
--- a/libinterp/interpfcn/symtab.h +++ b/libinterp/interpfcn/symtab.h @@ -199,6 +199,10 @@ // temporary variables forced into symbol table for parsing static const unsigned int forced = 128; + // this symbol may NOT become a variable. + // (symbol added to a static workspace) + static const unsigned int added_static = 256; + private: class @@ -348,6 +352,7 @@ 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; } + bool is_added_static (void) const {return storage_class & added_static; } void mark_local (void) { storage_class |= local; } void mark_automatic (void) { storage_class |= automatic; } @@ -369,6 +374,7 @@ storage_class |= persistent; } void mark_forced (void) { storage_class |= forced; } + void mark_added_static (void) { storage_class |= added_static; } void unmark_local (void) { storage_class &= ~local; } void unmark_automatic (void) { storage_class &= ~automatic; } @@ -378,6 +384,7 @@ void unmark_global (void) { storage_class &= ~global; } void unmark_persistent (void) { storage_class &= ~persistent; } void unmark_forced (void) { storage_class &= ~forced; } + void unmark_added_static (void) { storage_class &= ~added_static; } void init_persistent (void) { @@ -535,6 +542,7 @@ 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 (); } + bool is_added_static (void) const { return rep->is_added_static (); } void mark_local (void) { rep->mark_local (); } void mark_automatic (void) { rep->mark_automatic (); } @@ -544,6 +552,7 @@ void mark_global (void) { rep->mark_global (); } void mark_persistent (void) { rep->mark_persistent (); } void mark_forced (void) { rep->mark_forced (); } + void mark_added_static (void) { rep->mark_added_static (); } void unmark_local (void) { rep->unmark_local (); } void unmark_automatic (void) { rep->unmark_automatic (); } @@ -553,6 +562,7 @@ void unmark_global (void) { rep->unmark_global (); } void unmark_persistent (void) { rep->unmark_persistent (); } void unmark_forced (void) { rep->unmark_forced (); } + void unmark_added_static (void) { rep->unmark_added_static (); } void init_persistent (void) { rep->init_persistent (); } @@ -1207,13 +1217,23 @@ static octave_value& varref (const std::string& name, scope_id scope = xcurrent_scope, - context_id context = xdefault_context) + context_id context = xdefault_context, + bool force_add = false) { static octave_value foobar; symbol_table *inst = get_instance (scope); - return inst ? inst->do_varref (name, context) : foobar; + return inst ? inst->do_varref (name, context, force_add) : foobar; + } + + // Convenience function to greatly simplify + // octave_user_function::bind_automatic_vars + static octave_value& force_varref (const std::string& name, + scope_id scope = xcurrent_scope, + context_id context = xdefault_context) + { + return varref (name, scope, context, true); } static octave_value varval (const std::string& name, @@ -2110,6 +2130,9 @@ // The associated user code (may be null). octave_user_function *curr_fcn; + // If true then no variables can be added. + bool static_workspace; + // Map from names of global variables to values. static std::map<std::string, octave_value> global_table; @@ -2150,7 +2173,7 @@ symbol_table (scope_id scope) : my_scope (scope), table_name (), table (), nest_children (), nest_parent (0), - curr_fcn (0), persistent_table () { } + curr_fcn (0), static_workspace (false), persistent_table () { } ~symbol_table (void) { } @@ -2278,18 +2301,23 @@ octave_value do_builtin_find (const std::string& name); - symbol_record& do_insert (const std::string& name) + symbol_record& do_insert (const std::string& name, bool force_add = false) { 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; + symbol_record ret (my_scope, name); + + if (nest_parent && nest_parent->look_nonlocal (name, ret)) + return table[name] = ret; else - return table[name] = symbol_record (my_scope, name, octave_value ()); + { + if (static_workspace && ! force_add) + ret.mark_added_static (); + + return table[name] = ret; + } } else return p->second; @@ -2309,13 +2337,13 @@ p->second.force_variable (context); } - octave_value& do_varref (const std::string& name, context_id context) + octave_value& do_varref (const std::string& name, context_id context, bool force_add) { table_iterator p = table.find (name); if (p == table.end ()) { - symbol_record& sr = do_insert (name); + symbol_record& sr = do_insert (name, force_add); return sr.varref (context); }
--- a/libinterp/interpfcn/variables.cc +++ b/libinterp/interpfcn/variables.cc @@ -1881,7 +1881,7 @@ } else { - symbol_table::varref (ans) = val; + symbol_table::force_varref (ans) = val; if (print) val.print_with_name (octave_stdout, ans);
--- a/libinterp/octave-value/ov-usr-fcn.cc +++ b/libinterp/octave-value/ov-usr-fcn.cc @@ -581,8 +581,8 @@ // which might be redefined in a function. Keep the old argn name // for backward compatibility of functions that use it directly. - symbol_table::varref ("argn") = arg_names; - symbol_table::varref (".argn.") = Cell (arg_names); + symbol_table::force_varref ("argn") = arg_names; + symbol_table::force_varref (".argn.") = Cell (arg_names); symbol_table::mark_hidden (".argn."); @@ -590,8 +590,8 @@ symbol_table::mark_automatic (".argn."); } - symbol_table::varref (".nargin.") = nargin; - symbol_table::varref (".nargout.") = nargout; + symbol_table::force_varref (".nargin.") = nargin; + symbol_table::force_varref (".nargout.") = nargout; symbol_table::mark_hidden (".nargin."); symbol_table::mark_hidden (".nargout.");
--- a/libinterp/parse-tree/pt-id.cc +++ b/libinterp/parse-tree/pt-id.cc @@ -94,6 +94,8 @@ retval = val; } } + else if (sym->is_added_static ()) + static_workspace_error (); else eval_undefined_error (); @@ -116,6 +118,9 @@ octave_lvalue tree_identifier::lvalue (void) { + if (sym->is_added_static ()) + static_workspace_error (); + return octave_lvalue (&(sym->varref ())); }
--- a/libinterp/parse-tree/pt-id.h +++ b/libinterp/parse-tree/pt-id.h @@ -109,6 +109,12 @@ void eval_undefined_error (void); + void static_workspace_error (void) + { + ::error ("can not add variable \"%s\" to a static workspace", + name ().c_str ()); + } + tree_identifier *dup (symbol_table::scope_id scope, symbol_table::context_id context) const;
--- a/test/nest/module.mk +++ b/test/nest/module.mk @@ -1,6 +1,7 @@ nest_FCN_FILES = \ nest/arg_nest.m \ nest/arg_ret.m \ + nest/nest_eval.m \ nest/no_closure.m \ nest/persistent_nest.m \ nest/recursive_nest.m \
new file mode 100644 --- /dev/null +++ b/test/nest/nest_eval.m @@ -0,0 +1,8 @@ +function x = nest_eval (a, b) + eval (a); + nested (); + + function nested () + eval (b); + endfunction +endfunction
--- a/test/nest/test_nest.m +++ b/test/nest/test_nest.m @@ -47,7 +47,12 @@ %!test %! scope3; +%!assert (nest_eval ("x = 5;", "x = 6;"), 6); +%!assert (nest_eval ("x = 5;", "y = 6;"), 5); +%!assert (nest_eval ("x = -5; x = abs (x);", "y = 6;"), 5); + %!error <D' undefined near line 7> scope2 %!error <handles to nested functions are not yet supported> no_closure (0) %!error <handles to nested functions are not yet supported> no_closure (1) - +%!error <can not add variable "y" to a static workspace> nest_eval ("y = 5;", "") +%!error <can not add variable "y" to a static workspace> nest_eval ("y;", "")