# HG changeset patch
# User Max Brister <max@2bass.com>
# Date 1332014149 21600
# Node ID fc03e0ff1e23175b6b098e3be122449808200376
# Parent  12ccdce2c2166170195b7f9739be4828cd4371db
bug 35772: Nested function support

diff -r 12ccdce2c216 -r fc03e0ff1e23 src/oct-parse.yy
--- a/src/oct-parse.yy	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/oct-parse.yy	Sat Mar 17 13:55:49 2012 -0600
@@ -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 ();
@@ -2862,7 +2869,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)
@@ -2934,14 +2945,27 @@
 
       fcn->define_ret_list (ret_list);
 
+      assert (static_cast<size_t>(current_function_depth) == function_scopes.size());
       if (current_function_depth > 1 || parsing_subfunctions)
         {
           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)
         {
           // We are either reading a script file or defining a function
@@ -2979,6 +3003,7 @@
     parsing_subfunctions = true;
 
   current_function_depth--;
+  function_scopes.pop_back ();
 
   lexer_flags.defining_func--;
   lexer_flags.parsed_function_name.pop ();
@@ -3448,6 +3473,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);
@@ -3458,6 +3484,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;
@@ -3576,11 +3603,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
         {
@@ -4292,6 +4314,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);
@@ -4306,6 +4329,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;
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/ov-fcn-handle.cc
--- a/src/ov-fcn-handle.cc	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/ov-fcn-handle.cc	Sat Mar 17 13:55:49 2012 -0600
@@ -80,6 +80,9 @@
 
   if (uf && nm != anonymous)
     symbol_table::cache_name (uf->scope (), nm);
+
+  if (uf && uf->is_nested_function ())
+    ::error ("function handles to nested functions is not yet supported");
 }
 
 octave_value_list
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/ov-usr-fcn.cc
--- a/src/ov-usr-fcn.cc	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/ov-usr-fcn.cc	Sat Mar 17 13:55:49 2012 -0600
@@ -188,8 +188,9 @@
     system_fcn_file (false), call_depth (-1),
     num_named_args (param_list ? param_list->length () : 0),
     subfunction (false), inline_function (false),
-    anonymous_function (false), class_constructor (false),
-    class_method (false), parent_scope (-1), local_scope (sid),
+    anonymous_function (false), nested_function(false),
+    class_constructor (false), class_method (false),
+    parent_scope (-1), local_scope (sid),
     curr_unwind_protect_frame (0)
 {
   if (cmd_list)
@@ -387,7 +388,7 @@
   // Save old and set current symbol table context, for
   // eval_undefined_error().
 
-  int context = is_anonymous_function () ? 0 : call_depth;
+  int context = active_context ();
 
   octave_call_stack::push (this, local_scope, context);
   frame.add_fcn (octave_call_stack::pop);
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/ov-usr-fcn.h
--- a/src/ov-usr-fcn.h	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/ov-usr-fcn.h	Sat Mar 17 13:55:49 2012 -0600
@@ -177,6 +177,12 @@
 
   ~octave_user_function (void);
 
+  symbol_table::context_id active_context () const
+  {
+    return is_anonymous_function ()
+      ? 0 : static_cast<symbol_table::context_id>(call_depth);
+  }
+
   octave_function *function_value (bool = false) { return this; }
 
   octave_user_function *user_function_value (bool = false) { return this; }
@@ -277,6 +283,10 @@
       : false;
   }
 
+  bool is_nested_function (void) const { return nested_function; }
+
+  void mark_as_nested_function (void) { nested_function = true; }
+
   void mark_as_class_constructor (void) { class_constructor = true; }
 
   bool is_class_constructor (const std::string& cname = std::string ()) const
@@ -400,6 +410,9 @@
   // TRUE means this is an anonymous function.
   bool anonymous_function;
 
+  // TRUE means this is a nested function. (either a child or parent)
+  bool nested_function;
+
   // TRUE means this function is the constructor for class object.
   bool class_constructor;
 
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/pt-id.h
--- a/src/pt-id.h	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/pt-id.h	Sat Mar 17 13:55:49 2012 -0600
@@ -128,10 +128,11 @@
   {
     symbol_table::scope_id curr_scope = symbol_table::current_scope ();
 
-    if (scope != curr_scope)
+    if (scope != curr_scope || ! sym.is_valid ())
       {
         scope = curr_scope;
         sym = symbol_table::insert (sym.name ());
+        assert (sym.is_valid ());
       }
 
     return sym;
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/symtab.cc
--- a/src/symtab.cc	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/symtab.cc	Sat Mar 17 13:55:49 2012 -0600
@@ -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.
+          scope_val_iterator r = subfunctions.find (scope);
+          if (r != subfunctions.end ())
+            {
+              // FIXME -- out-of-date check here.
 
-          return r->second;
-        }
-      else
-        {
-          if (curr_fcn)
-            {
-              // 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?
+              return r->second;
+            }
 
-              scope_id pscope = curr_fcn->parent_fcn_scope ();
-
-              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);
+  for (scope_id scope = xcurrent_scope; scope >= 0;)
+    {
+      scope_val_iterator r = subfunctions.find (scope);
+      if (r != subfunctions.end ())
+        {
+          // FIXME -- out-of-date check here.
 
-  if (r != subfunctions.end ())
-    {
-      // FIXME -- out-of-date check here.
+          return r->second;
+        }
 
-      return r->second;
-    }
-  else if (curr_fcn)
-    {
-      scope_id pscope = curr_fcn->parent_fcn_scope ();
-
-      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;
     }
 
   return octave_value ();
@@ -1144,6 +1133,24 @@
     }
 }
 
+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();
+  assert (fv);
+  symbol_table *fcn_table = get_instance (fv->scope());
+  symbol_table *parent_table = get_instance (parent_scope);
+  assert (fcn_table);
+  assert (parent_table);
+
+  parent_table->add_nest_child (*fcn_table);
+}
+
 octave_value
 symbol_table::find (const std::string& name,
                     const octave_value_list& args,
@@ -1456,6 +1463,47 @@
     }
 }
 
+void
+symbol_table::do_update_nest ()
+{
+  assert (curr_fcn);
+
+  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\
diff -r 12ccdce2c216 -r fc03e0ff1e23 src/symtab.h
--- a/src/symtab.h	Fri Mar 09 16:39:24 2012 -0500
+++ b/src/symtab.h	Sat Mar 17 13:55:49 2012 -0600
@@ -206,22 +206,27 @@
     {
     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 (const std::string& nm,
+                         const octave_value& v,
+                         unsigned int sc, scope_id s)
+        : 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 +234,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 +245,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 +253,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 +263,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 +284,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 +298,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 +311,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 +382,48 @@
 
       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),
-                                      storage_class);
+        curr_fcn = fcn;
       }
 
+      symbol_record_rep *dup (scope_id new_scope) const
+      {
+        return new symbol_record_rep (name, varval (), storage_class, new_scope);
+      }
+
       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:
@@ -403,8 +449,8 @@
 
     symbol_record (const std::string& nm = std::string (),
                    const octave_value& v = octave_value (),
-                   unsigned int sc = local)
-      : rep (new symbol_record_rep (nm, v, sc)) { }
+                   unsigned int sc = local, scope_id s = xcurrent_scope)
+      : rep (new symbol_record_rep (nm, v, sc, s)) { }
 
     symbol_record (const symbol_record& sr)
       : rep (sr.rep)
@@ -432,39 +478,49 @@
         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)
+    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 +556,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 +992,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 +1073,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 +1098,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 ("", octave_value (), symbol_record::local, scope);
   }
 
   static void
@@ -1074,7 +1139,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 +1149,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 +1160,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 +1328,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 +1696,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);
@@ -1673,7 +1749,8 @@
 
         if (pat.match (p->first))
           retval.push_back (symbol_record (p->first, p->second,
-                                           symbol_record::global));
+                                           symbol_record::global,
+                                           xglobal_scope));
       }
 
     return retval;
@@ -1695,7 +1772,8 @@
 
         if (pat.is_match (p->first))
           retval.push_back (symbol_record (p->first, p->second,
-                                           symbol_record::global));
+                                           symbol_record::global,
+                                           xglobal_scope));
       }
 
     return retval;
@@ -1922,11 +2000,8 @@
     {
       assert (scope != xtop_scope && scope != xglobal_scope);
       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.
-      assert (inst->curr_fcn == 0 || curr_fcn == 0);
-      inst->curr_fcn = curr_fcn;
+      if (inst)
+        inst->do_set_curr_fcn (curr_fcn);
     }
 
   static void cleanup (void);
@@ -1953,6 +2028,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 +2039,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,10 +2084,17 @@
 
   static context_id xcurrent_context;
 
-  symbol_table (void)
-    : table_name (), table (), curr_fcn (0), persistent_table () { }
-
-  ~symbol_table (void) { }
+  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)
+  {
+    // prevent using a symbol_record with a bad curr_fcn
+    // do_set_curr_fcn (0);
+  }
 
   static symbol_table *get_instance (scope_id scope, bool create = true)
   {
@@ -2017,7 +2108,7 @@
           {
             if (! instance && create)
               {
-                symbol_table *inst = new symbol_table ();
+                symbol_table *inst = new symbol_table (scope);
 
                 if (inst)
                   {
@@ -2041,7 +2132,7 @@
               {
                 if (create)
                   {
-                    retval = new symbol_table ();
+                    retval = new symbol_table (scope);
 
                     if (retval)
                       all_instances[scope] = retval;
@@ -2063,6 +2154,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 +2170,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 +2224,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;
+
+        return table[name] = symbol_record (name, octave_value (), symbol_record::local,
+                                            my_scope);
+      }
+    else
+      return p->second;
   }
 
   void do_force_variable (const std::string& name, context_id context)
@@ -2156,13 +2263,17 @@
       }
     else
       return p->second.varref (context);
+
   }
 
   octave_value do_varval (const std::string& name, context_id context) const
   {
     table_const_iterator p = table.find (name);
 
-    return (p != table.end ()) ? p->second.varval (context) : octave_value ();
+    if (p != table.end ())
+      return p->second.varval (context);
+
+    return octave_value ();
   }
 
   octave_value& do_persistent_varref (const std::string& name)
@@ -2207,15 +2318,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 +2335,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 +2345,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 +2379,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 +2419,7 @@
         if (sr.is_defined () || sr.is_global ())
           {
             if (pattern.match (sr.name ()))
-              sr.clear ();
+              sr.clear (my_scope);
           }
       }
   }
@@ -2324,7 +2435,7 @@
         if (sr.is_defined () || sr.is_global ())
           {
             if (pattern.is_match (sr.name ()))
-              sr.clear ();
+              sr.clear (my_scope);
           }
       }
   }
@@ -2352,7 +2463,7 @@
     for (table_const_iterator p = table.begin (); p != table.end (); p++)
       {
         const symbol_record& sr = p->second;
-
+        
         if (defined_only && ! sr.is_defined (context))
           continue;
 
@@ -2462,6 +2573,42 @@
   void do_dump (std::ostream& os);
 
   void do_cache_name (const std::string& name) { table_name = name; }
+
+  void do_update_nest ();
+
+  void do_set_curr_fcn (octave_user_function *fcn)
+  {
+    // 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.
+    assert (curr_fcn == 0 || fcn == 0);
+    curr_fcn = fcn;
+
+    // incase of an usurp we need to update curr_fcn of symbol_records
+    // for (table_iterator ti = table.begin (); ti != table.end (); ++ti)
+    //   {
+    //     symbol_record &r = ti->second;
+    //     if (r.scope () == my_scope)
+    //       r.set_curr_fcn (curr_fcn);
+    //   }
+  }
+
+  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,
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/arg_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/arg_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,8 @@
+# arg_nest.m
+function x = arg_nest
+  x = 1;
+  A (x);
+  function A (x)
+    x = 2;
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/arg_ret.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/arg_ret.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,7 @@
+function a = arg_ret
+  a = 10;
+  f;
+  function a = f
+    a = 5;
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/module.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/module.mk	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,17 @@
+nest_FCN_FILES = \
+  nest/arg_nest.m \
+  nest/arg_ret.m \
+  nest/no_closure.m \
+  nest/recursive_nest.m \
+  nest/recursive_nest2.m \
+  nest/recursive_nest3.m \
+  nest/scope0.m \
+  nest/scope1.m \
+  nest/scope2.m \
+  nest/script_nest.m \
+  nest/script_nest_script.m \
+  nest/test_nest.m \
+  nest/varg_nest.m \
+  nest/varg_nest2.m
+
+FCN_FILES += $(nest_FCN_FILES)
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/no_closure.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/no_closure.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,11 @@
+# no_closure.m
+function no_closure (n)
+  if n == 0
+    x = @no_closure;
+  else
+    f = @no_closure;
+  endif
+
+  function f
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/persistent_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/persistent_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,10 @@
+# persistent_nest
+function y = persistent_nest ()
+  persistent x = 0;
+  g;
+  y = x;
+
+  function g
+    x = x + 1;
+  end
+end
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/recursive_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/recursive_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,13 @@
+# recursive_nest.m
+function x = recursive_nest ()
+  global recursive_nest_inc = 1
+  x = 5;
+  f (20);
+
+  function f (n)
+    if n > 0
+      x = x + recursive_nest_inc;
+      f (n - 1);
+    end
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/recursive_nest2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/recursive_nest2.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,21 @@
+# recursive_nest2.m
+function x = recursive_nest2 ()
+  x = B (20);
+  function v = B (n)
+    Y = 0;
+    BB (n);
+    C;
+    v = Y;
+    function BB (m)
+      if m > 0
+	Y = Y + 1;
+	BB(m - 1);
+	C;
+      end
+    endfunction
+  endfunction
+
+  function C
+    Y = 0;
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/recursive_nest3.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/recursive_nest3.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,13 @@
+function x = recursive_nest3 ()
+  y = 5;
+  f (y);
+  x = y;
+  g (x);
+  function f (y)
+    y = 10;
+  endfunction
+
+  function g (x)
+    x = 10;
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/scope0.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/scope0.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,16 @@
+# scope0.m
+function scope0
+  C;
+  function A
+    B;
+    function B
+    endfunction
+  endfunction
+
+  function C
+    D;
+    function D
+      A;
+    endfunction
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/scope1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/scope1.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,20 @@
+# scope1.m
+function scope1 (n)
+  value = n;
+  if value
+    C;
+  end
+  function A
+    B;
+    function B
+      scope1 (0);
+    endfunction
+  endfunction
+
+  function C
+    D;
+    function D
+      A;
+    endfunction
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/scope2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/scope2.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,17 @@
+# scope2.m
+function scope2
+  C;
+  function A
+    B;
+    function B
+      D;
+    endfunction
+  endfunction
+
+  function C
+    D;
+    function D
+      A;
+    endfunction
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/scope3.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/scope3.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,19 @@
+# scope3.m
+function scope3
+  C;
+  function A
+    B;
+    function B
+      E;
+    endfunction
+    function E
+    endfunction
+  endfunction
+
+  function C
+    D;
+    function D
+      A;
+    endfunction
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/script_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/script_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,11 @@
+# script_nest.m
+function x = script_nest
+  A (5)
+  function A (n)
+    if n <= 0
+      script_nest_script;
+    else
+      A (n - 1);
+    endif
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/script_nest_script.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/script_nest_script.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,2 @@
+# script_nest_script.m
+x = 5;
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/test_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/test_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,46 @@
+## Copyright (C) 2006-2012 John W. Eaton
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+%!assert (recursive_nest (), 25);
+
+%!assert (recursive_nest2 (), 20);
+
+%!assert (recursive_nest3 (), 5);
+
+%!assert (script_nest (), 5);
+
+%!assert (arg_ret (), 10);
+
+%!assert (varg_nest (-1), 6);
+
+%!assert (varg_nest2, 5);
+
+%!test
+%! scope0;
+
+%!test
+%! scope1 (1);
+
+%!test
+%! scope3;
+
+%!assert (arg_nest, 1);
+
+%!error <D' undefined near line 7> scope2;
+%!error <function handles to nested functions is not yet supported> no_closure (0);
+%!error <function handles to nested functions is not yet supported> no_closure (1);
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/varg_nest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/varg_nest.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,11 @@
+function x = varg_nest (varargin)
+  x = abs (f (-5)) + g;
+
+  function x = f (varargin)
+    x = abs (varargin{1});
+  endfunction
+
+  function x = g
+    x = abs (varargin{1});
+  endfunction
+endfunction
diff -r 12ccdce2c216 -r fc03e0ff1e23 test/nest/varg_nest2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/nest/varg_nest2.m	Sat Mar 17 13:55:49 2012 -0600
@@ -0,0 +1,14 @@
+function x = varg_nest2
+  [a, b] = f;
+  x = a;
+
+  if nargout == 1
+    x = a;
+  endif
+
+  function a, b = f
+    if nargout == 2
+      a = b = 5;
+    endif
+  endfunction
+endfunction
