diff src/symtab.cc @ 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 eff4a5933e28
children de72463862c4
line wrap: on
line diff
--- a/src/symtab.cc	Tue Apr 10 17:14:24 2012 -0400
+++ b/src/symtab.cc	Tue Apr 10 20:42:22 2012 -0400
@@ -78,11 +78,25 @@
   singleton_cleanup_list::add (cleanup_instance);
 }
 
+symbol_table::context_id
+symbol_table::symbol_record::symbol_record_rep::active_context (void) const
+{
+  octave_user_function *fcn = curr_fcn;
+
+  // FIXME -- If active_context () == -1, then it does not make much
+  // sense to use this symbol_record. This means an attempt at accessing
+  // a variable from a function that has not been called yet is
+  // happening. This should be cleared up when an implementing closures.
+
+  return fcn && fcn->active_context () != static_cast<context_id> (-1)
+    ? fcn->active_context () : xcurrent_context;
+}
+
 void
 symbol_table::symbol_record::symbol_record_rep::dump
   (std::ostream& os, const std::string& prefix) const
 {
-  octave_value val = varval (xcurrent_context);
+  octave_value val = varval ();
 
   os << prefix << name;
 
@@ -625,40 +639,23 @@
       // subfunctions if we are currently executing a function defined
       // from a .m file.
 
-      scope_val_iterator r = subfunctions.find (xcurrent_scope);
-
       octave_user_function *curr_fcn = symbol_table::get_curr_fcn ();
 
-      if (r != subfunctions.end ())
+      for (scope_id scope = xcurrent_scope; scope >= 0;)
         {
-          // FIXME -- out-of-date check here.
-
-          return r->second;
-        }
-      else
-        {
-          if (curr_fcn)
+          scope_val_iterator r = subfunctions.find (scope);
+          if (r != subfunctions.end ())
             {
-              // FIXME -- maybe it would be better if we could just get
-              // a pointer to the parent function so we would have
-              // access to all info about it instead of only being able
-              // to query the current function for specific bits of info
-              // about its parent function?
+              // FIXME -- out-of-date check here.
 
-              scope_id pscope = curr_fcn->parent_fcn_scope ();
+              return r->second;
+            }
 
-              if (pscope > 0)
-                {
-                  r = subfunctions.find (pscope);
-
-                  if (r != subfunctions.end ())
-                    {
-                      // FIXME -- out-of-date check here.
-
-                      return r->second;
-                    }
-                }
-            }
+          octave_user_function *scope_curr_fcn = get_curr_fcn (scope);
+          if (scope_curr_fcn)
+            scope = scope_curr_fcn->parent_fcn_scope ();
+          else
+            scope = -1;
         }
 
       // Private function.
@@ -896,29 +893,21 @@
   // subfunctions if we are currently executing a function defined
   // from a .m file.
 
-  scope_val_iterator r = subfunctions.find (xcurrent_scope);
-
-  if (r != subfunctions.end ())
+  for (scope_id scope = xcurrent_scope; scope >= 0;)
     {
-      // FIXME -- out-of-date check here.
-
-      return r->second;
-    }
-  else if (curr_fcn)
-    {
-      scope_id pscope = curr_fcn->parent_fcn_scope ();
+      scope_val_iterator r = subfunctions.find (scope);
+      if (r != subfunctions.end ())
+        {
+          // FIXME -- out-of-date check here.
 
-      if (pscope > 0)
-        {
-          r = subfunctions.find (pscope);
+          return r->second;
+        }
 
-          if (r != subfunctions.end ())
-            {
-              // FIXME -- out-of-date check here.
-
-              return r->second;
-            }
-        }
+      octave_user_function *scope_curr_fcn = get_curr_fcn (scope);
+      if (scope_curr_fcn)
+        scope = scope_curr_fcn->parent_fcn_scope ();
+      else
+        scope = -1;
     }
 
   return octave_value ();
@@ -1144,6 +1133,23 @@
     }
 }
 
+void
+symbol_table::install_nestfunction (const std::string& name,
+                                    const octave_value& fcn,
+                                    scope_id parent_scope)
+{
+  install_subfunction (name, fcn, parent_scope);
+
+  // Stash the nest_parent for resolving variables after parsing is done.
+  octave_function *fv = fcn.function_value();
+
+  symbol_table *fcn_table = get_instance (fv->scope());
+
+  symbol_table *parent_table = get_instance (parent_scope);
+
+  parent_table->add_nest_child (*fcn_table);
+}
+
 octave_value
 symbol_table::find (const std::string& name,
                     const octave_value_list& args,
@@ -1456,6 +1462,44 @@
     }
 }
 
+void
+symbol_table::do_update_nest (void)
+{
+  if (nest_parent || nest_children.size ())
+    curr_fcn->mark_as_nested_function ();
+
+  if (nest_parent)
+    {
+      // fix bad symbol_records
+      for (table_iterator ti = table.begin (); ti != table.end (); ++ti)
+        {
+          symbol_record &ours = ti->second;
+          symbol_record parents;
+          if (! ours.is_formal ()
+              && nest_parent->look_nonlocal (ti->first, parents))
+            {
+              if (ours.is_global () || ours.is_persistent ())
+                ::error ("global and persistent may only be used in the topmost level in which a nested variable is used");
+                
+              if (! ours.is_formal ())
+                {
+                  ours.invalidate ();
+                  ti->second = parents;
+                }
+            }
+          else
+            ours.set_curr_fcn (curr_fcn);
+        }
+    }
+  else if (nest_children.size())
+    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)
+    (*iter)->do_update_nest ();
+}
+
 DEFUN (ignore_function_time_stamp, args, nargout,
     "-*- texinfo -*-\n\
 @deftypefn  {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\