# HG changeset patch # User Max Brister # Date 1334719460 21600 # Node ID 44d6ffdf9479e4e6c77c513b59cd84a6a1c474df # Parent ab3d4c1affee89153ef3d8a37ff27f412025dc6b 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. diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/interpfcn/symtab.cc --- a/libinterp/interpfcn/symtab.cc Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/interpfcn/symtab.cc Tue Apr 17 21:24:20 2012 -0600 @@ -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::iterator iter = nest_children.begin (); iter != nest_children.end (); ++iter) diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/interpfcn/symtab.h --- a/libinterp/interpfcn/symtab.h Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/interpfcn/symtab.h Tue Apr 17 21:24:20 2012 -0600 @@ -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 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); } diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/interpfcn/variables.cc --- a/libinterp/interpfcn/variables.cc Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/interpfcn/variables.cc Tue Apr 17 21:24:20 2012 -0600 @@ -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); diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/octave-value/ov-usr-fcn.cc --- a/libinterp/octave-value/ov-usr-fcn.cc Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/octave-value/ov-usr-fcn.cc Tue Apr 17 21:24:20 2012 -0600 @@ -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."); diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/parse-tree/pt-id.cc --- a/libinterp/parse-tree/pt-id.cc Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/parse-tree/pt-id.cc Tue Apr 17 21:24:20 2012 -0600 @@ -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 ())); } diff -r ab3d4c1affee -r 44d6ffdf9479 libinterp/parse-tree/pt-id.h --- a/libinterp/parse-tree/pt-id.h Sat Aug 25 16:16:20 2012 -0600 +++ b/libinterp/parse-tree/pt-id.h Tue Apr 17 21:24:20 2012 -0600 @@ -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; diff -r ab3d4c1affee -r 44d6ffdf9479 test/nest/module.mk --- a/test/nest/module.mk Sat Aug 25 16:16:20 2012 -0600 +++ b/test/nest/module.mk Tue Apr 17 21:24:20 2012 -0600 @@ -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 \ diff -r ab3d4c1affee -r 44d6ffdf9479 test/nest/nest_eval.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/nest/nest_eval.m Tue Apr 17 21:24:20 2012 -0600 @@ -0,0 +1,8 @@ +function x = nest_eval (a, b) + eval (a); + nested (); + + function nested () + eval (b); + endfunction +endfunction diff -r ab3d4c1affee -r 44d6ffdf9479 test/nest/test_nest.m --- a/test/nest/test_nest.m Sat Aug 25 16:16:20 2012 -0600 +++ b/test/nest/test_nest.m Tue Apr 17 21:24:20 2012 -0600 @@ -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 scope2 %!error no_closure (0) %!error no_closure (1) - +%!error nest_eval ("y = 5;", "") +%!error nest_eval ("y;", "")