diff src/oct-parse.yy @ 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 e6aa044253eb
children 3a10d5bdada8
line wrap: on
line diff
--- a/src/oct-parse.yy	Tue Apr 10 17:14:24 2012 -0400
+++ b/src/oct-parse.yy	Tue Apr 10 20:42:22 2012 -0400
@@ -115,6 +115,11 @@
 //     nested function.
 static int current_function_depth = 0;
 
+// A stack holding the nested function scopes being parsed.
+// We don't use std::stack, because we want the clear method. Also, we
+// must access one from the top
+static std::vector<symbol_table::scope_id> function_scopes;
+
 // Maximum function depth detected. Just here to determine whether
 // we have nested functions or just implicitly ended subfunctions.
 static int max_function_depth = 0;
@@ -1226,6 +1231,8 @@
 
                     symbol_table::set_scope (symbol_table::alloc_scope ());
 
+                    function_scopes.push_back (symbol_table::current_scope ());
+
                     if (! reading_script_file && current_function_depth == 1
                         && ! parsing_subfunctions)
                       primary_fcn_scope = symbol_table::current_scope ();
@@ -2867,7 +2874,11 @@
       if (current_function_depth > 1 || parsing_subfunctions)
         {
           fcn->stash_parent_fcn_name (curr_fcn_file_name);
-          fcn->stash_parent_fcn_scope (primary_fcn_scope);
+
+          if (current_function_depth > 1)
+            fcn->stash_parent_fcn_scope (function_scopes[function_scopes.size()-2]);
+          else
+            fcn->stash_parent_fcn_scope (primary_fcn_scope);
         }
 
       if (lexer_flags.parsing_class_method)
@@ -2943,10 +2954,22 @@
         {
           fcn->mark_as_subfunction ();
 
-          symbol_table::install_subfunction (nm, octave_value (fcn),
-                                             primary_fcn_scope);
+          if (endfunction_found && function_scopes.size () > 1)
+            {
+              symbol_table::scope_id pscope
+                = function_scopes[function_scopes.size()-2];
+
+              symbol_table::install_nestfunction (nm, octave_value (fcn),
+                                                  pscope);
+            }
+          else
+            symbol_table::install_subfunction (nm, octave_value (fcn),
+                                               primary_fcn_scope);
         }
 
+      if (current_function_depth == 1 && fcn)
+        symbol_table::update_nest (fcn->scope ());
+
       if (! reading_fcn_file && current_function_depth == 1)
         {
           // We are either reading a script file or defining a function
@@ -2985,6 +3008,7 @@
     parsing_subfunctions = true;
 
   current_function_depth--;
+  function_scopes.pop_back ();
 
   lexer_flags.defining_func--;
   lexer_flags.parsed_function_name.pop ();
@@ -3454,6 +3478,7 @@
   frame.protect_var (line_editing);
   frame.protect_var (current_class_name);
   frame.protect_var (current_function_depth);
+  frame.protect_var (function_scopes);
   frame.protect_var (max_function_depth);
   frame.protect_var (parsing_subfunctions);
   frame.protect_var (endfunction_found);
@@ -3464,6 +3489,7 @@
   line_editing = false;
   current_class_name = dispatch_type;
   current_function_depth = 0;
+  function_scopes.clear ();
   max_function_depth = 0;
   parsing_subfunctions = false;
   endfunction_found = false;
@@ -3582,11 +3608,6 @@
           if (status != 0)
             error ("parse error while reading %s file %s",
                    file_type.c_str(), ff.c_str ());
-          else if (reading_fcn_file && endfunction_found
-                   && max_function_depth > 1)
-            warning_with_id ("Octave:nested-functions-coerced",
-                             "nested functions are coerced into subfunctions "
-                             "in file %s", ff.c_str ());
         }
       else
         {
@@ -4298,6 +4319,7 @@
   frame.protect_var (line_editing);
   frame.protect_var (current_eval_string);
   frame.protect_var (current_function_depth);
+  frame.protect_var (function_scopes);
   frame.protect_var (max_function_depth);
   frame.protect_var (parsing_subfunctions);
   frame.protect_var (endfunction_found);
@@ -4312,6 +4334,7 @@
   parser_end_of_input = false;
   line_editing = false;
   current_function_depth = 0;
+  function_scopes.clear ();
   max_function_depth = 0;
   parsing_subfunctions = false;
   endfunction_found = false;