changeset 24356:8b14ba8296af

refactor symbol_record object When referencing non-local variables, look in correct parent scope context. Cache pointer to parent scope for non-local access. Don't cache pointer to declaration scope. * symrec.h, symrec.cc (symbol_record::symbol_record_rep::m_fwd_scope): New data member. (symbol_record::symbol_record_rep::symbol_record_rep): Eliminate symbol_scope argument. Change all uses. (symbol_record::symbol_record_rep::assign, symbol_record::symbol_record_rep::do_non_const_unary_op): New argument, context Change all uses. Don't look to forward reference here. (symbol_record::symbol_record_rep::varref, symbol_record::symbol_record_rep::varval): New argument, context. Change all uses. Use context from forward scope when forwarding to non-local reference. (symbol_record::symbol_record_rep::clear, symbol_record::symbol_record_rep::is_defind, symbol_record::symbol_record_rep::is_variable, symbol_record::symbol_record_rep::dump): New argument, context. Change all uses. (symbol_record::symbol_record_rep::bind_fwd_rep): New argument, fwd_scope. Change all uses. (symbol_record::symbol_record_rep::bind_fwd_rep, symbol_record::symbol_record_rep::unbind_fwd_rep): Return after forwarding. (symbol_record::symbol_record_rep::get_fwd_scope_context): New function. (symbol_record::symbol_record_rep::get_decl_scope_context): Delete. (symbol_record::symbol_record_rep::m_decl_scope): Delete data member and all uses. (symbol_record::symbol_record): Eliminate symbol_scope argument. Change all uses. (symbol_record::find, symbol_record::assign, symbol_record::do_non_const_unary_opt, symbol_record::varval, symbol_record::clear, symbol_record::is_defined, symbol_record::is_undefined, symbol_record::is_valid, symbol_record::is_variable, symbol_record::dump): New arg, context. Change all uses. (symbol_record::decl_scope): Delete. (symbol_record::bind_fwd_rep): New arg, fwd_scope. Change all uses. * load-save.h, load-save.cc (do_save): New argument, context. Change all uses. (save_vars): Work with scope instead of symbol table. * variables.cc (symbol_info::symbol_info, symbol_info::append): New arg, context. Change all uses. * oct-lvalue.h, oct-lvalue.cc (octave_lvalue::m_context): New data member. (octave_lvalue::octave_lvalue): New argument, context. Change all uses. * pt-decl.h (tree_decl_elt::is_defined, tree_decl_elt::is_variable): New argument, context. Change all uses. * pt-id.h, pt-id.cc (tree_identifier::link_to_global): New argument, global_scope. (tree_identifier::is_defined, tree_identifier::is_variable, tree_black_hole::is_variable): New argument, context. Change all uses. * pt-misc.h, pt-misc.cc (tree_parameter_list::is_defined): New argument, context. Change all uses.
author John W. Eaton <jwe@octave.org>
date Mon, 04 Dec 2017 12:30:40 -0500
parents cc3b3ceb155c
children ff4717c3223f
files libinterp/corefcn/load-save.cc libinterp/corefcn/symrec.cc libinterp/corefcn/symrec.h libinterp/corefcn/symscope.cc libinterp/corefcn/symscope.h libinterp/corefcn/variables.cc libinterp/octave-value/ov-fcn-handle.cc libinterp/parse-tree/lex.ll libinterp/parse-tree/oct-lvalue.cc libinterp/parse-tree/oct-lvalue.h libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-decl.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h libinterp/parse-tree/pt-idx.cc libinterp/parse-tree/pt-jit.cc libinterp/parse-tree/pt-misc.cc libinterp/parse-tree/pt-misc.h
diffstat 19 files changed, 276 insertions(+), 225 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/load-save.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/load-save.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -960,9 +960,10 @@
 
 void
 do_save (std::ostream& os, const octave::symbol_record& sr,
+         octave::symbol_record::context_id context,
          load_save_format fmt, bool save_as_floats)
 {
-  octave_value val = sr.varval ();
+  octave_value val = sr.varval (context);
 
   if (val.is_defined ())
     {
@@ -1009,15 +1010,17 @@
 save_vars (std::ostream& os, const std::string& pattern,
            load_save_format fmt, bool save_as_floats)
 {
-  octave::symbol_table& symtab = octave::__get_symbol_table__ ("save_vars");
+  octave::symbol_scope *scope = octave::__require_current_scope__ ("save_vars");
 
-  std::list<octave::symbol_record> vars = symtab.glob (pattern);
+  octave::symbol_record::context_id context = scope->current_context ();
+
+  std::list<octave::symbol_record> vars = scope->glob (pattern);
 
   size_t saved = 0;
 
   for (const auto& var : vars)
     {
-      do_save (os, var, fmt, save_as_floats);
+      do_save (os, var, context, fmt, save_as_floats);
 
       saved++;
     }
@@ -1334,13 +1337,15 @@
 
   octave::symbol_scope *top_scope = symtab.top_scope ();
 
+  octave::symbol_record::context_id context = top_scope->current_context ();
+
   std::list<octave::symbol_record> vars = top_scope->all_variables ();
 
   double save_mem_size = 0;
 
   for (const auto& var : vars)
     {
-      octave_value val = var.varval ();
+      octave_value val = var.varval (context);
 
       if (val.is_defined ())
         {
--- a/libinterp/corefcn/symrec.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/symrec.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -42,9 +42,9 @@
 namespace octave
 {
   symbol_record::context_id
-  symbol_record::symbol_record_rep::get_decl_scope_context (void) const
+  symbol_record::symbol_record_rep::get_fwd_scope_context (void) const
   {
-    return m_decl_scope ? m_decl_scope->current_context () : 0;
+    return m_fwd_scope ? m_fwd_scope->current_context () : 0;
   }
 
   void
@@ -66,15 +66,17 @@
     if (auto t_fwd_rep = m_fwd_rep.lock ())
       return t_fwd_rep->dup (new_scope);
 
-    return new symbol_record_rep (new_scope, m_name, varval (),
+    static const context_id FIXME_CONTEXT = 0;
+
+    return new symbol_record_rep (m_name, varval (FIXME_CONTEXT),
                                   m_storage_class);
   }
 
   octave_value
-  symbol_record::symbol_record_rep::dump (void) const
+  symbol_record::symbol_record_rep::dump (context_id context) const
   {
     if (auto t_fwd_rep = m_fwd_rep.lock ())
-      return t_fwd_rep->dump ();
+      return t_fwd_rep->dump (context);
 
     std::map<std::string, octave_value> m
       = {{ "name", m_name },
@@ -86,7 +88,7 @@
          { "global", is_global () },
          { "persistent", is_persistent () }};
 
-    octave_value val = varval ();
+    octave_value val = varval (context);
 
     if (val.is_defined ())
       m["value"] = val;
@@ -94,21 +96,16 @@
     return octave_value (m);
   }
 
-  symbol_record::symbol_record (void)
-    : m_rep (new symbol_record_rep (__get_current_scope__ ("symbol_record"),
-                                    "", octave_value (), local))
-
-  { }
-
   octave_value
-  symbol_record::find (const octave_value_list& args) const
+  symbol_record::find (context_id context,
+                       const octave_value_list& args) const
   {
     octave_value retval;
 
     symbol_table& symtab
       = __get_symbol_table__ ("symbol_record::find");
 
-    retval = varval ();
+    retval = varval (context);
 
     if (retval.is_undefined ())
       {
--- a/libinterp/corefcn/symrec.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/symrec.h	Mon Dec 04 12:30:40 2017 -0500
@@ -78,11 +78,10 @@
     {
     public:
 
-      symbol_record_rep (symbol_scope *s, const std::string& nm,
+      symbol_record_rep (const std::string& nm,
                          const octave_value& v, unsigned int sc)
-        : m_decl_scope (s), m_name (nm),
-          m_fwd_rep (), m_value_stack (), m_storage_class (sc),
-          m_valid (true)
+        : m_storage_class (sc), m_name (nm), m_fwd_scope (nullptr),
+          m_fwd_rep (), m_value_stack (), m_valid (true)
       {
         m_value_stack.push_back (v);
       }
@@ -95,77 +94,48 @@
 
       ~symbol_record_rep (void) = default;
 
-      void assign (const octave_value& value)
+      void assign (const octave_value& value, context_id context)
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          {
-            t_fwd_rep->assign (value);
-            return;
-          }
-
-        varref () = value;
+        varref(context) = value;
       }
 
       void assign (octave_value::assign_op op,
                    const std::string& type,
                    const std::list<octave_value_list>& idx,
-                   const octave_value& value)
+                   const octave_value& value, context_id context)
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          {
-            t_fwd_rep->assign (op, type, idx, value);
-            return;
-          }
-
-        varref().assign (op, type, idx, value);
+        varref(context).assign (op, type, idx, value);
       }
 
-      void assign (octave_value::assign_op op, const octave_value& value)
+      void assign (octave_value::assign_op op, const octave_value& value,
+                   context_id context)
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          {
-            t_fwd_rep->assign (op, value);
-            return;
-          }
-
-        varref().assign (op, value);
+        varref(context).assign (op, value);
       }
 
-      void do_non_const_unary_op (octave_value::unary_op op)
+      void do_non_const_unary_op (octave_value::unary_op op,
+                                  context_id context)
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          {
-            t_fwd_rep->do_non_const_unary_op (op);
-            return;
-          }
-
-        varref().do_non_const_unary_op (op);
+        varref(context).do_non_const_unary_op (op);
       }
 
       void do_non_const_unary_op (octave_value::unary_op op,
                                   const std::string& type,
-                                  const std::list<octave_value_list>& idx)
+                                  const std::list<octave_value_list>& idx,
+                                  context_id context)
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          {
-            t_fwd_rep->do_non_const_unary_op (op, type, idx);
-            return;
-          }
-
-        varref().do_non_const_unary_op (op, type, idx);
+        varref(context).do_non_const_unary_op (op, type, idx);
       }
 
-      context_id get_decl_scope_context (void) const;
+      context_id get_fwd_scope_context (void) const;
 
-      octave_value& varref (void)
+      octave_value& varref (context_id context)
       {
         if (auto t_fwd_rep = m_fwd_rep.lock ())
-          return t_fwd_rep->varref ();
+          return t_fwd_rep->varref (get_fwd_scope_context ());
 
-        context_id context = 0;
-
-        if (m_decl_scope && ! (is_persistent () || is_global ()))
-          context = get_decl_scope_context ();
+        if (is_persistent ())
+          context = 0;
 
         context_id n = m_value_stack.size ();
         while (n++ <= context)
@@ -174,15 +144,13 @@
         return m_value_stack[context];
       }
 
-      octave_value varval (void) const
+      octave_value varval (context_id context) const
       {
         if (auto t_fwd_rep = m_fwd_rep.lock ())
-          return t_fwd_rep->varval ();
+          return t_fwd_rep->varval (get_fwd_scope_context ());
 
-        context_id context = 0;
-
-        if (m_decl_scope && ! (is_persistent () || is_global ()))
-          context = get_decl_scope_context ();
+        if (is_persistent ())
+          context = 0;
 
         if (context < m_value_stack.size ())
           return m_value_stack[context];
@@ -229,7 +197,7 @@
         return retval;
       }
 
-      void clear (void)
+      void clear (context_id context)
       {
         // There is no need to do anything with a fowarded
         // symbol_record_rep here.
@@ -251,19 +219,16 @@
             if (is_global ())
               unbind_fwd_rep ();
 
-            assign (octave_value ());
+            assign (octave_value (), context);
 
             if (is_persistent ())
               unmark_persistent ();
           }
       }
 
-      bool is_defined (void) const
+      bool is_defined (context_id context) const
       {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          return t_fwd_rep->is_defined ();
-
-        return varval ().is_defined ();
+        return varval (context).is_defined ();
       }
 
       bool is_valid (void) const
@@ -274,12 +239,12 @@
         return m_valid;
       }
 
-      bool is_variable (void) const
+      bool is_variable (context_id context) const
       {
         if (auto t_fwd_rep = m_fwd_rep.lock ())
-          return t_fwd_rep->is_variable ();
+          return t_fwd_rep->is_variable (context);
 
-        return (! is_local () || is_defined ());
+        return (! is_local () || is_defined (context));
       }
 
       bool is_local (void) const
@@ -527,33 +492,34 @@
         m_valid = false;
       }
 
-      symbol_scope *decl_scope (void)
+      void bind_fwd_rep (symbol_scope *fwd_scope,
+                         const std::shared_ptr<symbol_record_rep>& fwd_rep)
       {
         if (auto t_fwd_rep = m_fwd_rep.lock ())
-          return t_fwd_rep->decl_scope ();
-
-        return m_decl_scope;
-      }
+          {
+            t_fwd_rep->bind_fwd_rep (fwd_scope, fwd_rep);
+            return;
+          }
 
-      void bind_fwd_rep (const std::shared_ptr<symbol_record_rep>& fwd_rep)
-      {
-        if (auto t_fwd_rep = m_fwd_rep.lock ())
-          t_fwd_rep->bind_fwd_rep (fwd_rep);
-
+        m_fwd_scope = fwd_scope;
         m_fwd_rep = fwd_rep;
       }
 
       void unbind_fwd_rep (void)
       {
         if (auto t_fwd_rep = m_fwd_rep.lock ())
-          t_fwd_rep->unbind_fwd_rep ();
+          {
+            t_fwd_rep->unbind_fwd_rep ();
+            return;
+          }
 
+        m_fwd_scope = nullptr;
         m_fwd_rep.reset ();
       }
 
       symbol_record_rep * dup (symbol_scope *new_scope) const;
 
-      octave_value dump (void) const;
+      octave_value dump (context_id context) const;
 
       std::string name (void) const { return m_name; }
 
@@ -561,27 +527,26 @@
 
     private:
 
-      symbol_scope *m_decl_scope;
+      unsigned int m_storage_class;
 
       std::string m_name;
 
+      symbol_scope *m_fwd_scope;
+
       std::weak_ptr<symbol_record_rep> m_fwd_rep;
 
       std::deque<octave_value> m_value_stack;
 
-      unsigned int m_storage_class;
-
       bool m_valid;
     };
 
   public:
 
-    symbol_record (void);
-
-    symbol_record (symbol_scope *s, const std::string& nm = "",
+    symbol_record (const std::string& nm = "",
                    const octave_value& v = octave_value (),
                    unsigned int sc = local)
-      : m_rep (new symbol_record_rep (s, nm, v, sc)) { }
+      : m_rep (new symbol_record_rep (nm, v, sc))
+    { }
 
     symbol_record (const symbol_record& sr) = default;
 
@@ -599,57 +564,60 @@
     void rename (const std::string& new_name) { m_rep->rename (new_name); }
 
     octave_value
-    find (const octave_value_list& args = octave_value_list ()) const;
+    find (context_id context,
+          const octave_value_list& args = octave_value_list ()) const;
 
-    void assign (const octave_value& value)
+    void assign (const octave_value& value, context_id context)
     {
-      m_rep->assign (value);
+      m_rep->assign (value, context);
     }
 
     void assign (octave_value::assign_op op,
                  const std::string& type,
                  const std::list<octave_value_list>& idx,
-                 const octave_value& value)
+                 const octave_value& value, context_id context)
     {
-      m_rep->assign (op, type, idx, value);
+      m_rep->assign (op, type, idx, value, context);
     }
 
-    void assign (octave_value::assign_op op, const octave_value& value)
+    void assign (octave_value::assign_op op, const octave_value& value,
+                 context_id context)
     {
-      m_rep->assign (op, value);
+      m_rep->assign (op, value, context);
     }
 
-    void do_non_const_unary_op (octave_value::unary_op op)
+    void do_non_const_unary_op (octave_value::unary_op op, context_id context)
     {
-      m_rep->do_non_const_unary_op (op);
+      m_rep->do_non_const_unary_op (op, context);
     }
 
     void do_non_const_unary_op (octave_value::unary_op op,
                                 const std::string& type,
-                                const std::list<octave_value_list>& idx)
+                                const std::list<octave_value_list>& idx,
+                                context_id context)
     {
-      m_rep->do_non_const_unary_op (op, type, idx);
+      m_rep->do_non_const_unary_op (op, type, idx, context);
     }
 
-    octave_value varval (void) const
+    octave_value varval (context_id context) const
     {
-      return m_rep->varval ();
+      return m_rep->varval (context);
     }
 
     void push_context (void) { m_rep->push_context (); }
 
     size_t pop_context (void) { return m_rep->pop_context (); }
 
-    void clear (void) { m_rep->clear (); }
+    void clear (context_id context) { m_rep->clear (context); }
 
-    bool is_defined (void) const
+    bool is_defined (context_id context) const
     {
-      return m_rep->is_defined ();
+      return m_rep->is_defined (context);
     }
 
-    bool is_undefined (void) const
+    bool is_undefined (context_id context) const
     {
-      return ! m_rep->is_defined ();
+      return ! m_rep->is_defined (context);
     }
 
     bool is_valid (void) const
@@ -657,9 +625,9 @@
       return m_rep->is_valid ();
     }
 
-    bool is_variable (void) const
+    bool is_variable (context_id context) const
     {
-      return m_rep->is_variable ();
+      return m_rep->is_variable (context);
     }
 
     bool is_local (void) const { return m_rep->is_local (); }
@@ -692,18 +660,19 @@
 
     void invalidate (void) { m_rep->invalidate (); }
 
-    symbol_scope *decl_scope (void) { return m_rep->decl_scope (); }
-
     unsigned int storage_class (void) const { return m_rep->storage_class (); }
 
-    void bind_fwd_rep (const symbol_record& sr)
+    void bind_fwd_rep (symbol_scope *fwd_scope, const symbol_record& sr)
     {
-      m_rep->bind_fwd_rep (sr.m_rep);
+      m_rep->bind_fwd_rep (fwd_scope, sr.m_rep);
     }
 
     void unbind_fwd_rep (void) { m_rep->unbind_fwd_rep (); }
 
-    octave_value dump (void) const { return m_rep->dump (); }
+    octave_value dump (context_id context) const
+    {
+      return m_rep->dump (context);
+    }
 
   private:
 
--- a/libinterp/corefcn/symscope.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/symscope.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -60,7 +60,7 @@
               return symtab.global_varval (name);
             else
               {
-                octave_value val = sr.varval ();
+                octave_value val = sr.varval (m_context);
 
                 if (val.is_defined ())
                   return val;
@@ -90,7 +90,7 @@
 
     if (p == m_symbols.end ())
       {
-        symbol_record ret (this, name);
+        symbol_record ret (name);
 
         if (m_is_nested && m_parent && m_parent->look_nonlocal (name, ret))
           return m_symbols[name] = ret;
@@ -118,7 +118,7 @@
 
         if (! sr.is_hidden ())
           {
-            octave_value val = sr.varval ();
+            octave_value val = sr.varval (m_context);
 
             if (val.is_defined ())
               {
@@ -180,7 +180,7 @@
       {
         std::string nm = nm_sr.first;
         const symbol_record& sr = nm_sr.second;
-        info_map[nm] = sr.dump ();
+        info_map[nm] = sr.dump (m_context);
       }
 
     return octave_value (info_map);
@@ -301,7 +301,7 @@
       }
     else if (! p->second.is_automatic ())
       {
-        result.bind_fwd_rep (p->second);
+        result.bind_fwd_rep (this, p->second);
         return true;
       }
 
@@ -312,7 +312,8 @@
   symbol_scope::bind_script_symbols (symbol_scope *curr_scope)
   {
     for (auto& nm_sr : m_symbols)
-      nm_sr.second.bind_fwd_rep (curr_scope->find_symbol (nm_sr.first));
+      nm_sr.second.bind_fwd_rep (curr_scope,
+                                 curr_scope->find_symbol (nm_sr.first));
   }
 
   void
--- a/libinterp/corefcn/symscope.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/symscope.h	Mon Dec 04 12:30:40 2017 -0500
@@ -137,7 +137,7 @@
 
                   if (val.is_defined ())
                     {
-                      sr.assign (val);
+                      sr.assign (val, m_context);
 
                       sr.mark_inherited ();
                     }
@@ -192,10 +192,10 @@
         {
           symbol_record& sr = insert (name, force_add);
 
-          sr.assign (value);
+          sr.assign (value, m_context);
         }
       else
-        p->second.assign (value);
+        p->second.assign (value, m_context);
     }
 
     void assign (const std::string& name,
@@ -212,10 +212,10 @@
         {
           symbol_record& sr = insert (name, true);
 
-          sr.assign (value);
+          sr.assign (value, m_context);
         }
       else
-        p->second.assign (value);
+        p->second.assign (value, m_context);
     }
 
     octave_value varval (const std::string& name) const
@@ -223,7 +223,7 @@
       table_const_iterator p = m_symbols.find (name);
 
       return (p != m_symbols.end ()
-              ? p->second.varval () : octave_value ());
+              ? p->second.varval (m_context) : octave_value ());
     }
 
     bool is_variable (const std::string& name) const
@@ -236,7 +236,7 @@
         {
           const symbol_record& sr = p->second;
 
-          retval = sr.is_variable ();
+          retval = sr.is_variable (m_context);
         }
 
       return retval;
@@ -268,14 +268,14 @@
           symbol_record& sr = nm_sr.second;
 
           if (! sr.is_persistent ())
-            sr.clear ();
+            sr.clear (m_context);
         }
     }
 
     void clear_variables (void)
     {
       for (auto& nm_sr : m_symbols)
-        nm_sr.second.clear ();
+        nm_sr.second.clear (m_context);
     }
 
     void clear_objects (void)
@@ -283,9 +283,9 @@
       for (auto& nm_sr : m_symbols)
         {
           symbol_record& sr = nm_sr.second;
-          octave_value val = sr.varval ();
+          octave_value val = sr.varval (m_context);
           if (val.isobject ())
-            nm_sr.second.clear ();
+            nm_sr.second.clear (m_context);
         }
     }
 
@@ -294,7 +294,7 @@
       table_iterator p = m_symbols.find (name);
 
       if (p != m_symbols.end ())
-        p->second.clear ();
+        p->second.clear (m_context);
     }
 
     void clear_variable_pattern (const std::string& pat)
@@ -305,10 +305,10 @@
         {
           symbol_record& sr = nm_sr.second;
 
-          if (sr.is_defined () || sr.is_global ())
+          if (sr.is_defined (m_context) || sr.is_global ())
             {
               if (pattern.match (sr.name ()))
-                sr.clear ();
+                sr.clear (m_context);
             }
         }
     }
@@ -321,10 +321,10 @@
         {
           symbol_record& sr = nm_sr.second;
 
-          if (sr.is_defined () || sr.is_global ())
+          if (sr.is_defined (m_context) || sr.is_global ())
             {
               if (pattern.is_match (sr.name ()))
-                sr.clear ();
+                sr.clear (m_context);
             }
         }
     }
@@ -354,7 +354,7 @@
         {
           const symbol_record& sr = nm_sr.second;
 
-          if ((defined_only && ! sr.is_defined ())
+          if ((defined_only && ! sr.is_defined (m_context))
               || (sr.storage_class () & exclude))
             continue;
 
@@ -377,7 +377,7 @@
             {
               const symbol_record& sr = nm_sr.second;
 
-              if (vars_only && ! sr.is_variable ())
+              if (vars_only && ! sr.is_variable (m_context))
                 continue;
 
               retval.push_back (sr);
@@ -400,7 +400,7 @@
             {
               const symbol_record& sr = nm_sr.second;
 
-              if (vars_only && ! sr.is_variable ())
+              if (vars_only && ! sr.is_variable (m_context))
                 continue;
 
               retval.push_back (sr);
@@ -416,7 +416,7 @@
 
       for (const auto& nm_sr : m_symbols)
         {
-          if (nm_sr.second.is_variable ())
+          if (nm_sr.second.is_variable (m_context))
             retval.push_back (nm_sr.first);
         }
 
@@ -431,7 +431,7 @@
 
       return (p != m_symbols.end ()
               && ! p->second.is_global ()
-              && p->second.is_defined ());
+              && p->second.is_defined (m_context));
     }
 
     bool is_global (const std::string& name) const
--- a/libinterp/corefcn/variables.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/corefcn/variables.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -1131,6 +1131,7 @@
   struct symbol_info
   {
     symbol_info (const octave::symbol_record& sr,
+                 octave::symbol_record::context_id context,
                  const std::string& expr_str = "",
                  const octave_value& expr_val = octave_value ())
       : name (expr_str.empty () ? sr.name () : expr_str),
@@ -1141,7 +1142,8 @@
         is_global (sr.is_global ()),
         is_persistent (sr.is_persistent ())
     {
-      varval = (expr_val.is_undefined () ? sr.varval () : expr_val);
+      varval = (expr_val.is_undefined ()
+                ? sr.varval (context) : expr_val);
 
       is_complex = varval.iscomplex ();
     }
@@ -1294,16 +1296,18 @@
 
   ~symbol_info_list (void) = default;
 
-  void append (const octave::symbol_record& sr)
+  void append (const octave::symbol_record& sr,
+               octave::symbol_record::context_id context)
   {
-    lst.push_back (symbol_info (sr));
+    lst.push_back (symbol_info (sr, context));
   }
 
   void append (const octave::symbol_record& sr,
+               octave::symbol_record::context_id context,
                const std::string& expr_str,
                const octave_value& expr_val)
   {
-    lst.push_back (symbol_info (sr, expr_str, expr_val));
+    lst.push_back (symbol_info (sr, context, expr_str, expr_val));
   }
 
   size_t size (void) const { return lst.size (); }
@@ -1695,6 +1699,8 @@
 
   octave::symbol_scope *scope = symtab.current_scope ();
 
+  octave::symbol_record::context_id context = scope->current_context ();
+
   for (int j = 0; j < npats; j++)
     {
       std::string pat = pats[j];
@@ -1708,10 +1714,10 @@
 
           for (const auto& symrec : tmp)
             {
-              if (symrec.is_variable ())
+              if (symrec.is_variable (context))
                 {
                   if (verbose)
-                    symbol_stats.append (symrec);
+                    symbol_stats.append (symrec, context);
                   else
                     symbol_names.push_back (symrec.name ());
                 }
@@ -1746,7 +1752,7 @@
                           octave_value expr_val
                             = octave::eval_string (pat, true, parse_status);
 
-                          symbol_stats.append (sr, pat, expr_val);
+                          symbol_stats.append (sr, context, pat, expr_val);
                         }
                     }
                 }
@@ -1760,10 +1766,10 @@
 
               for (const auto& symrec : tmp)
                 {
-                  if (symrec.is_variable ())
+                  if (symrec.is_variable (context))
                     {
                       if (verbose)
-                        symbol_stats.append (symrec);
+                        symbol_stats.append (symrec, context);
                       else
                         symbol_names.push_back (symrec.name ());
                     }
--- a/libinterp/octave-value/ov-fcn-handle.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -61,6 +61,7 @@
 #include "pt-misc.h"
 #include "pt-pr-code.h"
 #include "pt-stmt.h"
+#include "symscope.h"
 #include "unwind-prot.h"
 #include "variables.h"
 
@@ -353,8 +354,12 @@
 
       octave_user_function *f = fcn.user_function_value ();
       octave::symbol_scope *f_scope = f->scope ();
+      octave::symbol_record::context_id context = 0;
       if (f_scope)
-        vars = f_scope->all_variables ();
+        {
+          vars = f_scope->all_variables ();
+          context = f_scope->current_context ();
+        }
 
       size_t varlen = vars.size ();
 
@@ -364,8 +369,8 @@
 
           for (const auto& symrec : vars)
             {
-              if (! save_text_data (os, symrec.varval (), symrec.name (),
-                                    false, 0))
+              if (! save_text_data (os, symrec.varval (context),
+                                    symrec.name (), false, 0))
                 return ! os.fail ();
             }
         }
@@ -530,8 +535,12 @@
 
       octave_user_function *f = fcn.user_function_value ();
       octave::symbol_scope *f_scope = f->scope ();
+      octave::symbol_record::context_id context = 0;
       if (f_scope)
-        vars = f_scope->all_variables ();
+        {
+          vars = f_scope->all_variables ();
+          context = f_scope->current_context ();
+        }
 
       size_t varlen = vars.size ();
 
@@ -556,8 +565,8 @@
         {
           for (const auto& symrec : vars)
             {
-              if (! save_binary_data (os, symrec.varval (), symrec.name (),
-                                      "", 0, save_as_floats))
+              if (! save_binary_data (os, symrec.varval (context),
+                                      symrec.name (), "", 0, save_as_floats))
                 return ! os.fail ();
             }
         }
@@ -786,8 +795,12 @@
 
       octave_user_function *f = fcn.user_function_value ();
       octave::symbol_scope *f_scope = f->scope ();
+      octave::symbol_record::context_id context = 0;
       if (f_scope)
-        vars = f_scope->all_variables ();
+        {
+          vars = f_scope->all_variables ();
+          context = f_scope->current_context ();
+        }
 
       size_t varlen = vars.size ();
 
@@ -836,8 +849,8 @@
 
           for (const auto& symrec : vars)
             {
-              if (! add_hdf5_data (data_hid, symrec.varval (), symrec.name (),
-                                   "", false, save_as_floats))
+              if (! add_hdf5_data (data_hid, symrec.varval (context),
+                                   symrec.name (), "", false, save_as_floats))
                 break;
             }
           H5Gclose (data_hid);
@@ -1759,8 +1772,12 @@
 
       octave_user_function *fu = fh->user_function_value ();
       octave::symbol_scope *fu_scope = fu->scope ();
+      octave::symbol_record::context_id context = 0;
       if (fu_scope)
-        vars = fu_scope->all_variables ();
+        {
+          vars = fu_scope->all_variables ();
+          context = fu_scope->current_context ();
+        }
 
       size_t varlen = vars.size ();
 
@@ -1768,7 +1785,7 @@
         {
           octave_scalar_map ws;
           for (const auto& symrec : vars)
-            ws.assign (symrec.name (), symrec.varval ());
+            ws.assign (symrec.name (), symrec.varval (context));
 
           m.setfield ("workspace", ws);
         }
@@ -1980,6 +1997,11 @@
 
           if (arg_list && arg_list->length () > 0)
             {
+              octave::symbol_scope *scope = tw->get_current_scope ();
+
+              octave::symbol_record::context_id context
+                = scope->current_context ();
+
               bool bad = false;
               int nargs = arg_list->length ();
               octave_value_list arg_template (nargs);
@@ -2005,7 +2027,7 @@
                         {
                           arg_mask[iarg] = arginmap[elt_id->name ()];
                         }
-                      else if (elt_id->is_defined ())
+                      else if (elt_id->is_defined (context))
                         {
                           arg_template(iarg) = tw->evaluate (elt_id);
                           arg_mask[iarg] = -1;
@@ -2028,7 +2050,7 @@
               if (! bad)
                 {
                   // If the head is a value, use it as root.
-                  if (head_id->is_defined ())
+                  if (head_id->is_defined (context))
                     root_val = tw->evaluate (head_id);
                   else
                     {
--- a/libinterp/parse-tree/lex.ll	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/lex.ll	Mon Dec 04 12:30:40 2017 -0500
@@ -3158,10 +3158,7 @@
 
     symbol_scope *scope = symtab_context.curr_scope ();
 
-    symbol_record sr
-      = (scope
-         ? scope->insert (ident)
-         : symbol_record (scope, ident));
+    symbol_record sr = (scope ? scope->insert (ident) : symbol_record (ident));
 
     token *tok = new token (NAME, sr, input_line_number, current_input_column);
 
--- a/libinterp/parse-tree/oct-lvalue.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/oct-lvalue.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -37,9 +37,9 @@
     if (! is_black_hole ())
       {
         if (m_idx.empty ())
-          m_sym.assign (op, rhs);
+          m_sym.assign (op, rhs, m_context);
         else
-          m_sym.assign (op, m_type, m_idx, rhs);
+          m_sym.assign (op, m_type, m_idx, rhs, m_context);
       }
   }
 
@@ -72,9 +72,9 @@
     if (! is_black_hole ())
       {
         if (m_idx.empty ())
-          m_sym.do_non_const_unary_op (op);
+          m_sym.do_non_const_unary_op (op, m_context);
         else
-          m_sym.do_non_const_unary_op (op, m_type, m_idx);
+          m_sym.do_non_const_unary_op (op, m_type, m_idx, m_context);
       }
   }
 
@@ -84,7 +84,7 @@
 
     if (! is_black_hole ())
       {
-        octave_value val = m_sym.varval ();
+        octave_value val = m_sym.varval (m_context);
 
         if (m_idx.empty ())
           retval = val;
--- a/libinterp/parse-tree/oct-lvalue.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/oct-lvalue.h	Mon Dec 04 12:30:40 2017 -0500
@@ -36,8 +36,14 @@
   {
   public:
 
-    octave_lvalue (const symbol_record& sr = symbol_record ())
-      : m_sym (sr), m_black_hole (false), m_type (), m_idx (), m_nel (1)
+    octave_lvalue (void)
+      : m_sym (), m_context (0), m_black_hole (false), m_type (),
+        m_idx (), m_nel (1)
+    { }
+
+    octave_lvalue (const symbol_record& sr, symbol_record::context_id context)
+      : m_sym (sr), m_context (context), m_black_hole (false),
+        m_type (), m_idx (), m_nel (1)
     { }
 
     octave_lvalue (const octave_lvalue& vr) = default;
@@ -52,17 +58,17 @@
 
     bool is_defined (void) const
     {
-      return ! is_black_hole () && m_sym.is_defined ();
+      return ! is_black_hole () && m_sym.is_defined (m_context);
     }
 
     bool is_undefined (void) const
     {
-      return is_black_hole () || m_sym.is_undefined ();
+      return is_black_hole () || m_sym.is_undefined (m_context);
     }
 
     bool isstruct (void) const { return value().isstruct (); }
 
-    void define (const octave_value& v) { m_sym.assign (v); }
+    void define (const octave_value& v) { m_sym.assign (v, m_context); }
 
     void assign (octave_value::assign_op, const octave_value&);
 
@@ -86,6 +92,8 @@
 
     symbol_record m_sym;
 
+    symbol_record::context_id m_context;
+
     bool m_black_hole;
 
     std::string m_type;
--- a/libinterp/parse-tree/oct-parse.in.yy	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/oct-parse.in.yy	Mon Dec 04 12:30:40 2017 -0500
@@ -5421,10 +5421,15 @@
 
                     if (expr->is_identifier ())
                       {
+                        octave::symbol_scope *scope = tw.get_current_scope ();
+
+                        octave::symbol_record::context_id context
+                          = scope->current_context ();
+
                         tree_identifier *id
                           = dynamic_cast<tree_identifier *> (expr);
 
-                        do_bind_ans = (! id->is_variable ());
+                        do_bind_ans = (! id->is_variable (context));
                       }
                     else
                       do_bind_ans = (! expr->is_assignment_expression ());
--- a/libinterp/parse-tree/pt-decl.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-decl.h	Mon Dec 04 12:30:40 2017 -0500
@@ -65,9 +65,15 @@
 
     ~tree_decl_elt (void);
 
-    bool is_defined (void) { return id ? id->is_defined () : false; }
+    bool is_defined (symbol_record::context_id context)
+    {
+      return id ? id->is_defined (context) : false;
+    }
 
-    bool is_variable (void) { return id ? id->is_variable () : false; }
+    bool is_variable (symbol_record::context_id context)
+    {
+      return id ? id->is_variable (context) : false;
+    }
 
     void mark_as_formal_parameter (void)
     {
--- a/libinterp/parse-tree/pt-eval.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-eval.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -582,13 +582,17 @@
       return varargout;
     else if (nargout <= len)
       {
+        symbol_scope *scope = get_current_scope ();
+
+        symbol_record::context_id context = scope->current_context ();
+
         octave_value_list retval (nargout);
 
         int i = 0;
 
         for (tree_decl_elt *elt : *ret_list)
           {
-            if (elt->is_defined ())
+            if (elt->is_defined (context))
               {
                 octave_value tmp = evaluate (elt);
                 retval(i) = tmp;
@@ -716,7 +720,7 @@
 
             symbol_record global_sym = symtab.find_global_symbol (id->name ());
 
-            id->link_to_global (global_sym);
+            id->link_to_global (symtab.global_scope (), global_sym);
           }
         else if (elt.is_persistent ())
           id->mark_persistent ();
@@ -1037,9 +1041,13 @@
   {
     octave_value_list retval;
 
+    symbol_scope *scope = get_current_scope ();
+
+    symbol_record::context_id context = scope->current_context ();
+
     symbol_record sym = expr.symbol ();
 
-    octave_value val = sym.find ();
+    octave_value val = sym.find (context);
 
     if (val.is_defined ())
       {
@@ -1145,8 +1153,16 @@
 {
   std::string extra_message;
 
+  // FIXME: make this a member function for direct access to symbol
+  // table and scope?
+
+  octave::symbol_scope *scope
+    = octave::__require_current_scope__ ("final_index_error");
+
+  octave::symbol_record::context_id context = scope->current_context ();
+
   if (expr->is_identifier ()
-      && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable ())
+      && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable (context))
     {
       std::string var = expr->name ();
 
@@ -1272,7 +1288,11 @@
       {
         tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
 
-        if (! id->is_variable ())
+        symbol_scope *scope = get_current_scope ();
+
+        symbol_record::context_id context = scope->current_context ();
+
+        if (! id->is_variable (context))
           {
             octave_value_list first_args;
 
@@ -1297,7 +1317,7 @@
 
             octave_function *fcn = nullptr;
 
-            octave_value val = id->do_lookup (first_args);
+            octave_value val = id->do_lookup (context, first_args);
 
             if (val.is_function ())
               fcn = val.function_value (true);
@@ -2258,9 +2278,13 @@
 
                 if (expr->is_identifier ())
                   {
+                    symbol_scope *scope = get_current_scope ();
+
+                    symbol_record::context_id context = scope->current_context ();
+
                     tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
 
-                    do_bind_ans = (! id->is_variable ());
+                    do_bind_ans = (! id->is_variable (context));
                   }
                 else
                   do_bind_ans = (! expr->is_assignment_expression ());
@@ -2447,11 +2471,10 @@
         if (catch_code)
           {
             tree_identifier *expr_id = cmd.identifier ();
-            octave_lvalue ult;
 
             if (expr_id)
               {
-                ult = expr_id->lvalue (this);
+                octave_lvalue ult = expr_id->lvalue (this);
 
                 octave_scalar_map err;
 
@@ -2715,8 +2738,7 @@
           }
         else
           {
-            symbol_scope *scope
-              = m_interpreter.require_current_scope ("tree_evaluator::bind_ans");
+            symbol_scope *scope = get_current_scope ();
 
             scope->force_assign (ans, val);
 
--- a/libinterp/parse-tree/pt-id.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-id.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -40,10 +40,11 @@
 
   class tree_evaluator;
 
-  void tree_identifier::link_to_global (const symbol_record& global_sym)
+  void tree_identifier::link_to_global (symbol_scope *global_scope,
+                                        const symbol_record& global_sym)
   {
     if (! sym.is_global ())
-      sym.bind_fwd_rep (global_sym);
+      sym.bind_fwd_rep (global_scope, global_sym);
   }
 
   void
@@ -64,12 +65,14 @@
   }
 
   octave_lvalue
-  tree_identifier::lvalue (tree_evaluator *)
+  tree_identifier::lvalue (tree_evaluator *tw)
   {
     if (sym.is_added_static ())
       static_workspace_error ();
 
-    return octave_lvalue (sym);
+    symbol_scope *scope = tw->get_current_scope ();
+
+    return octave_lvalue (sym, scope->current_context ());
   }
 
   tree_identifier *
--- a/libinterp/parse-tree/pt-id.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-id.h	Mon Dec 04 12:30:40 2017 -0500
@@ -71,9 +71,15 @@
 
     std::string name (void) const { return sym.name (); }
 
-    bool is_defined (void) { return sym.is_defined (); }
+    bool is_defined (symbol_record::context_id context)
+    {
+      return sym.is_defined (context);
+    }
 
-    virtual bool is_variable (void) const { return sym.is_variable (); }
+    virtual bool is_variable (symbol_record::context_id context) const
+    {
+      return sym.is_variable (context);
+    }
 
     virtual bool is_black_hole (void) { return false; }
 
@@ -93,12 +99,14 @@
     //     then .mex files, then .m files.
 
     octave_value
-    do_lookup (const octave_value_list& args = octave_value_list ())
+    do_lookup (symbol_record::context_id context,
+               const octave_value_list& args = octave_value_list ())
     {
-      return sym.find (args);
+      return sym.find (context, args);
     }
 
-    void link_to_global (const symbol_record& global_sym);
+    void link_to_global (symbol_scope *global_scope,
+                         const symbol_record& global_sym);
 
     void mark_persistent (void) { sym.init_persistent (); }
 
@@ -146,7 +154,7 @@
 
     std::string name (void) const { return "~"; }
 
-    bool is_variable (void) const { return false; }
+    bool is_variable (symbol_record::context_id) const { return false; }
 
     bool is_black_hole (void) { return true; }
 
--- a/libinterp/parse-tree/pt-idx.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-idx.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -206,15 +206,17 @@
 {
   std::string extra_message;
 
+  octave::symbol_table& symtab = octave::__get_symbol_table__ ("final_index_error");
+
+  octave::symbol_record::context_id context = symtab.current_context ();
+
   if (expr->is_identifier ()
-      && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable ())
+      && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable (context))
     {
       std::string var = expr->name ();
 
       e.set_var (var);
 
-      octave::symbol_table& symtab = octave::__get_symbol_table__ ("final_index_error");
-
       octave_value fcn = symtab.find_function (var);
 
       if (fcn.is_function ())
--- a/libinterp/parse-tree/pt-jit.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-jit.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -797,7 +797,7 @@
           {
             tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
 
-            do_bind_ans = (! id->is_variable ());
+            do_bind_ans = (! id->is_variable (scope->current_context ()));
           }
         else
           do_bind_ans = (! expr->is_assignment_expression ());
@@ -1144,7 +1144,7 @@
       return create_variable (vname, jit_typeinfo::get_any (), false);
     else
       {
-        octave_value val = record.varval ();
+        octave_value val = record.varval (scope->current_context ());
         if (val.is_undefined ())
           val = symtab.find_function (vname);
 
--- a/libinterp/parse-tree/pt-misc.cc	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-misc.cc	Mon Dec 04 12:30:40 2017 -0500
@@ -60,13 +60,13 @@
   }
 
   bool
-  tree_parameter_list::is_defined (void)
+  tree_parameter_list::is_defined (symbol_record::context_id context)
   {
     bool status = true;
 
     for (tree_decl_elt *elt : *this)
       {
-        if (! elt->is_variable ())
+        if (! elt->is_variable (context))
           {
             status = false;
             break;
--- a/libinterp/parse-tree/pt-misc.h	Mon Dec 04 01:26:06 2017 -0500
+++ b/libinterp/parse-tree/pt-misc.h	Mon Dec 04 12:30:40 2017 -0500
@@ -76,7 +76,7 @@
 
     bool varargs_only (void) { return (marked_for_varargs < 0); }
 
-    bool is_defined (void);
+    bool is_defined (symbol_record::context_id context);
 
     std::list<std::string> variable_names (void) const;