changeset 23435:c452180ab672

begin refactoring parse tree evaluator * libinterp/parse-tree/pt-tm-const.cc, libinterp/parse-tree/pt-tm-const.h: New files, extracted from pt-mat.h and pt-mat.cc. * libinterp/parse-tree/module.mk: Update. * interpreter.cc, ov-class.cc, ov-classdef.cc, ov-classdef.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-usr-fcn.cc, oct-parse.in.yy, pt-arg-list.cc, pt-arg-list.h, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc, pt-binop.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc, pt-cell.h, pt-classdef.cc, pt-classdef.h, pt-cmd.cc, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h, pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-funcall.cc, pt-funcall.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h, pt-jit.cc, pt-jump.cc, pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-select.cc, pt-select.h, pt-stmt.cc, pt-stmt.h, pt-unop.cc, pt-unop.h: Use tree_evaluator class to walk the parse tree instead of rvalue methods in the parse tree classes. Maintain a stack in the evaluator class to accumulate results. Pass pointer to evaluator to function objects and other classes as needed for evaluation. This is a work in progress that is not yet complete. The ultimate goal is to move all evaluation into the tree_evaluator class instead of spreading that work among many different classes. The global pointer to the current evaluator should also be eliminated.
author John W. Eaton <jwe@octave.org>
date Fri, 21 Apr 2017 18:07:40 -0400
parents f4d4d83f15c5
children c715a1aebbd5
files libinterp/corefcn/interpreter.cc libinterp/corefcn/profiler.h libinterp/octave-value/ov-class.cc libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-fcn-handle.h libinterp/octave-value/ov-usr-fcn.cc libinterp/parse-tree/module.mk libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-arg-list.cc libinterp/parse-tree/pt-arg-list.h libinterp/parse-tree/pt-array-list.h libinterp/parse-tree/pt-assign.cc libinterp/parse-tree/pt-assign.h libinterp/parse-tree/pt-binop.cc libinterp/parse-tree/pt-binop.h libinterp/parse-tree/pt-cbinop.cc libinterp/parse-tree/pt-cbinop.h libinterp/parse-tree/pt-cell.cc libinterp/parse-tree/pt-cell.h libinterp/parse-tree/pt-classdef.cc libinterp/parse-tree/pt-classdef.h libinterp/parse-tree/pt-cmd.cc libinterp/parse-tree/pt-cmd.h libinterp/parse-tree/pt-colon.cc libinterp/parse-tree/pt-colon.h libinterp/parse-tree/pt-const.cc libinterp/parse-tree/pt-const.h libinterp/parse-tree/pt-decl.cc libinterp/parse-tree/pt-decl.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h libinterp/parse-tree/pt-except.cc libinterp/parse-tree/pt-except.h libinterp/parse-tree/pt-exp.cc libinterp/parse-tree/pt-exp.h libinterp/parse-tree/pt-fcn-handle.cc libinterp/parse-tree/pt-fcn-handle.h libinterp/parse-tree/pt-funcall.cc libinterp/parse-tree/pt-funcall.h libinterp/parse-tree/pt-id.cc libinterp/parse-tree/pt-id.h libinterp/parse-tree/pt-idx.cc libinterp/parse-tree/pt-idx.h libinterp/parse-tree/pt-jit.cc libinterp/parse-tree/pt-jump.cc libinterp/parse-tree/pt-jump.h libinterp/parse-tree/pt-loop.cc libinterp/parse-tree/pt-loop.h libinterp/parse-tree/pt-mat.cc libinterp/parse-tree/pt-mat.h libinterp/parse-tree/pt-misc.cc libinterp/parse-tree/pt-misc.h libinterp/parse-tree/pt-select.cc libinterp/parse-tree/pt-select.h libinterp/parse-tree/pt-stmt.cc libinterp/parse-tree/pt-stmt.h libinterp/parse-tree/pt-tm-const.cc libinterp/parse-tree/pt-tm-const.h libinterp/parse-tree/pt-unop.cc libinterp/parse-tree/pt-unop.h
diffstat 62 files changed, 2861 insertions(+), 3080 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/interpreter.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/corefcn/interpreter.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -426,7 +426,7 @@
 
     install_builtins ();
 
-    install_classdef ();
+    install_classdef (m_evaluator);
 
     bool line_editing = false;
     bool traditional = false;
--- a/libinterp/corefcn/profiler.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/corefcn/profiler.h	Fri Apr 21 18:07:40 2017 -0400
@@ -219,6 +219,6 @@
     profile_data_accumulator::enter<classname> pe (profiler, *this);
 
 #define END_PROFILER_BLOCK                      \
-    }  // end of block => call pe's destructor
+  }  // end of block => call pe's destructor
 
 #endif
--- a/libinterp/octave-value/ov-class.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-class.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -456,7 +456,7 @@
 
           // Since we're handling subsref, if the list has more than one
           // element, return it as a comma-separated list so that we can
-          // pass it to rvalue1.
+          // pass it to the evaluator
           if (retval.length () > 1)
             retval = octave_value (retval);
         }
--- a/libinterp/octave-value/ov-classdef.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-classdef.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -37,6 +37,7 @@
 #include "ov-usr-fcn.h"
 #include "pt-assign.h"
 #include "pt-classdef.h"
+#include "pt-eval.h"
 #include "pt-funcall.h"
 #include "pt-idx.h"
 #include "pt-misc.h"
@@ -420,9 +421,11 @@
   return retval;
 }
 
-bool
+static bool
 is_method_executing (const octave_value& ov, const cdef_object& obj)
 {
+  octave::tree_evaluator *tw = octave::current_evaluator;
+
   octave_function* stack_fcn = octave::call_stack::current ();
 
   octave_function* method_fcn = ov.function_value (true);
@@ -450,7 +453,11 @@
 
           if (pl && pl->size () > 0)
             {
-              octave_value arg0 = pl->front ()->lvalue ().value ();
+              octave::tree_decl_elt *elt = pl->front ();
+
+              octave_lvalue ref = elt->lvalue (tw);
+
+              octave_value arg0 = ref.value ();
 
               if (arg0.is_defined () && arg0.type_name () == "object")
                 {
@@ -640,10 +647,10 @@
 }
 
 static cdef_class
-make_class (const std::string& name,
+make_class (octave::tree_evaluator *tw, const std::string& name,
             const std::list<cdef_class>& super_list = std::list<cdef_class> ())
 {
-  cdef_class cls (name, super_list);
+  cdef_class cls (tw, name, super_list);
 
   cls.set_class (cdef_class::meta_class ());
   cls.put ("Abstract", false);
@@ -695,15 +702,17 @@
 }
 
 static cdef_class
-make_class (const std::string& name, const cdef_class& super)
+make_class (octave::tree_evaluator *tw, const std::string& name,
+            const cdef_class& super)
 {
-  return make_class (name, std::list<cdef_class> (1, super));
+  return make_class (tw, name, std::list<cdef_class> (1, super));
 }
 
 static cdef_class
-make_meta_class (const std::string& name, const cdef_class& super)
+make_meta_class (octave::tree_evaluator *tw, const std::string& name,
+                 const cdef_class& super)
 {
-  cdef_class cls = make_class (name, super);
+  cdef_class cls = make_class (tw, name, super);
 
   cls.put ("Sealed", true);
   cls.mark_as_meta_class ();
@@ -1786,10 +1795,10 @@
 #endif
 }
 
-cdef_class::cdef_class_rep::cdef_class_rep (const std::list<cdef_class>&
-                                            superclasses)
-  : cdef_meta_object_rep (), member_count (0), handle_class (false),
-    object_count (0), meta (false)
+cdef_class::cdef_class_rep::cdef_class_rep (octave::tree_evaluator *tw,
+                                            const std::list<cdef_class>& superclasses)
+  : cdef_meta_object_rep (), m_evaluator (tw), member_count (0),
+    handle_class (false), object_count (0), meta (false)
 {
   put ("SuperClasses", to_ov (superclasses));
   implicit_ctor_list = superclasses;
@@ -2445,7 +2454,8 @@
       if (this_cls == cdef_class::meta_class ())
         {
           if (! empty_class.ok ())
-            empty_class = make_class ("", std::list<cdef_class> ());
+            empty_class = make_class (m_evaluator, "",
+                                      std::list<cdef_class> ());
           obj = empty_class;
         }
       else if (this_cls == cdef_class::meta_property ())
@@ -2453,7 +2463,8 @@
           static cdef_property empty_property;
 
           if (! empty_class.ok ())
-            empty_class = make_class ("", std::list<cdef_class> ());
+            empty_class = make_class (m_evaluator, "",
+                                      std::list<cdef_class> ());
           if (! empty_property.ok ())
             empty_property = make_property (empty_class, "");
           obj = empty_property;
@@ -2463,7 +2474,8 @@
           static cdef_method empty_method;
 
           if (! empty_class.ok ())
-            empty_class = make_class ("", std::list<cdef_class> ());
+            empty_class = make_class (m_evaluator, "",
+                                      std::list<cdef_class> ());
           if (! empty_method.ok ())
             empty_method = make_method (empty_class, "", octave_value ());
           obj = empty_method;
@@ -2500,13 +2512,16 @@
 }
 
 static octave_value
-compute_attribute_value (octave::tree_classdef_attribute* t)
+compute_attribute_value (octave::tree_evaluator *tw,
+                         octave::tree_classdef_attribute* t)
 {
-  if (t->expression ())
+  octave::tree_expression *expr = t->expression ();
+
+  if (expr)
     {
-      if (t->expression ()->is_identifier ())
+      if (expr->is_identifier ())
         {
-          std::string s = t->expression ()->name ();
+          std::string s = expr->name ();
 
           if (s == "public")
             return std::string ("public");
@@ -2516,7 +2531,7 @@
             return std::string ("private");
         }
 
-      return t->expression ()->rvalue1 ();
+      return tw->evaluate (expr);
     }
   else
     return octave_value (true);
@@ -2535,7 +2550,8 @@
 }
 
 cdef_class
-cdef_class::make_meta_class (octave::tree_classdef* t, bool is_at_folder)
+cdef_class::make_meta_class (octave::tree_evaluator *tw,
+                             octave::tree_classdef* t, bool is_at_folder)
 {
   cdef_class retval;
   std::string class_name, full_class_name;
@@ -2572,7 +2588,7 @@
         }
     }
 
-  retval = ::make_class (full_class_name, slist);
+  retval = ::make_class (tw, full_class_name, slist);
 
   // Package owning this class
 
@@ -2591,7 +2607,7 @@
       for (const auto& attr : (*t->attribute_list ()))
         {
           std::string aname = attr->ident ()->name ();
-          octave_value avalue = compute_attribute_value (attr);
+          octave_value avalue = compute_attribute_value (tw, attr);
 
 #if DEBUG_TRACE
           std::cerr << "class attribute: " << aname << " = "
@@ -2631,7 +2647,7 @@
               for (auto& attr_p : *mb_p->attribute_list ())
                 {
                   std::string aname = attr_p->ident ()->name ();
-                  octave_value avalue = compute_attribute_value (attr_p);
+                  octave_value avalue = compute_attribute_value (tw, attr_p);
 
 #if DEBUG_TRACE
                   std::cerr << "method attribute: " << aname << " = "
@@ -2736,7 +2752,7 @@
               for (auto& attr_p : *pb_p->attribute_list ())
                 {
                   std::string aname = attr_p->ident ()->name ();
-                  octave_value avalue = compute_attribute_value (attr_p);
+                  octave_value avalue = compute_attribute_value (tw, attr_p);
 
 #if DEBUG_TRACE
                   std::cerr << "property attribute: " << aname << " = "
@@ -2769,9 +2785,10 @@
                             << std::endl;
 #endif
 
-                  if (prop_p->expression ())
+                  octave::tree_expression *expr = prop_p->expression ();
+                  if (expr)
                     {
-                      octave_value pvalue = prop_p->expression ()->rvalue1 ();
+                      octave_value pvalue = tw->evaluate (expr);
 
 #if DEBUG_TRACE
                       std::cerr << "property default: "
@@ -3338,23 +3355,23 @@
 cdef_package cdef_package::_meta = cdef_package ();
 
 void
-install_classdef (void)
+install_classdef (octave::tree_evaluator *tw)
 {
   octave_classdef::register_type ();
 
   // bootstrap
-  cdef_class handle = make_class ("handle");
-  cdef_class meta_class = cdef_class::_meta_class = make_meta_class ("meta.class", handle);
+  cdef_class handle = make_class (tw, "handle");
+  cdef_class meta_class = cdef_class::_meta_class = make_meta_class (tw, "meta.class", handle);
   handle.set_class (meta_class);
   meta_class.set_class (meta_class);
 
   // meta classes
-  cdef_class meta_property = cdef_class::_meta_property = make_meta_class ("meta.property", handle);
-  cdef_class meta_method = cdef_class::_meta_method = make_meta_class ("meta.method", handle);
-  cdef_class meta_package = cdef_class::_meta_package = make_meta_class ("meta.package", handle);
-
-  cdef_class meta_event = make_meta_class ("meta.event", handle);
-  cdef_class meta_dynproperty = make_meta_class ("meta.dynamicproperty", handle);
+  cdef_class meta_property = cdef_class::_meta_property = make_meta_class (tw, "meta.property", handle);
+  cdef_class meta_method = cdef_class::_meta_method = make_meta_class (tw, "meta.method", handle);
+  cdef_class meta_package = cdef_class::_meta_package = make_meta_class (tw, "meta.package", handle);
+
+  cdef_class meta_event = make_meta_class (tw, "meta.event", handle);
+  cdef_class meta_dynproperty = make_meta_class (tw, "meta.dynamicproperty", handle);
 
   // meta.class properties
   meta_class.install_property (make_attribute (meta_class, "Abstract"));
--- a/libinterp/octave-value/ov-classdef.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-classdef.h	Fri Apr 21 18:07:40 2017 -0400
@@ -43,6 +43,7 @@
 namespace octave
 {
   class tree_classdef;
+  class tree_evaluator;
 }
 
 // This is mainly a boostrap class to declare the expected interface.
@@ -616,10 +617,12 @@
   {
   public:
     cdef_class_rep (void)
-      : cdef_meta_object_rep (), member_count (0), handle_class (false),
-        object_count (0), meta (false) { }
+      : cdef_meta_object_rep (), m_evaluator (0), member_count (0),
+        handle_class (false), object_count (0), meta (false)
+    { }
 
-    cdef_class_rep (const std::list<cdef_class>& superclasses);
+    cdef_class_rep (octave::tree_evaluator *tw,
+                    const std::list<cdef_class>& superclasses);
 
     cdef_object_rep* copy (void) const { return new cdef_class_rep (*this); }
 
@@ -702,6 +705,8 @@
 
     bool is_meta_class (void) const { return meta; }
 
+    octave::tree_evaluator *evaluator (void) const { return m_evaluator; }
+
   private:
     void load_all_methods (void);
 
@@ -720,6 +725,9 @@
     }
 
   private:
+
+    octave::tree_evaluator *m_evaluator;
+
     // The @-directory were this class is loaded from.
     // (not used yet)
     std::string directory;
@@ -756,7 +764,8 @@
 
   private:
     cdef_class_rep (const cdef_class_rep& c)
-      : cdef_meta_object_rep (c), directory (c.directory),
+      : cdef_meta_object_rep (c), m_evaluator (c.m_evaluator),
+        directory (c.directory),
         method_map (c.method_map), property_map (c.property_map),
         member_count (c.member_count), handle_class (c.handle_class),
         implicit_ctor_list (c.implicit_ctor_list),
@@ -768,9 +777,9 @@
   cdef_class (void)
     : cdef_meta_object () { }
 
-  cdef_class (const std::string& nm,
+  cdef_class (octave::tree_evaluator *tw, const std::string& nm,
               const std::list<cdef_class>& superclasses)
-    : cdef_meta_object (new cdef_class_rep (superclasses))
+    : cdef_meta_object (new cdef_class_rep (tw, superclasses))
   { get_rep ()->set_name (nm); }
 
   cdef_class (const cdef_class& cls)
@@ -832,7 +841,8 @@
   void delete_object (cdef_object obj)
   { get_rep ()->delete_object (obj); }
 
-  static cdef_class make_meta_class (octave::tree_classdef* t,
+  static cdef_class make_meta_class (octave::tree_evaluator *tw,
+                                     octave::tree_classdef* t,
                                      bool is_at_folder = false);
 
   octave_function* get_method_function (const std::string& nm);
@@ -886,6 +896,9 @@
   const cdef_class_rep* get_rep (void) const
   { return dynamic_cast<const cdef_class_rep *> (cdef_object::get_rep ()); }
 
+  octave::tree_evaluator *evaluator (void) const
+  { return get_rep ()->evaluator (); }
+
   friend bool operator == (const cdef_class&, const cdef_class&);
   friend bool operator != (const cdef_class&, const cdef_class&);
   friend bool operator < (const cdef_class&, const cdef_class&);
@@ -896,7 +909,7 @@
   static cdef_class _meta_method;
   static cdef_class _meta_package;
 
-  friend void install_classdef (void);
+  friend void install_classdef (octave::tree_evaluator *);
 };
 
 inline bool
@@ -1393,7 +1406,7 @@
 private:
   static cdef_package _meta;
 
-  friend void install_classdef (void);
+  friend void install_classdef (octave::tree_evaluator *);
 };
 
 class
@@ -1524,7 +1537,7 @@
 to_cdef (const cdef_object& obj)
 { return obj; }
 
-OCTINTERP_API void install_classdef (void);
+OCTINTERP_API void install_classdef (octave::tree_evaluator *);
 
 class
 cdef_manager
--- a/libinterp/octave-value/ov-fcn-handle.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -54,6 +54,7 @@
 #include "pt-arg-list.h"
 #include "pt-assign.h"
 #include "pt-cmd.h"
+#include "pt-eval.h"
 #include "pt-exp.h"
 #include "pt-idx.h"
 #include "pt-misc.h"
@@ -1917,7 +1918,8 @@
 { }
 
 octave_fcn_handle *
-octave_fcn_binder::maybe_binder (const octave_value& f)
+octave_fcn_binder::maybe_binder (const octave_value& f,
+                                 octave::tree_evaluator *tw)
 {
   octave_fcn_handle *retval = 0;
 
@@ -1989,7 +1991,7 @@
                   octave::tree_expression *elt = *it;
                   if (elt && elt->is_constant ())
                     {
-                      arg_template(iarg) = elt->rvalue1 ();
+                      arg_template(iarg) = tw->evaluate (elt);
                       arg_mask[iarg] = -1;
                     }
                   else if (elt && elt->is_identifier ())
@@ -2002,7 +2004,7 @@
                         }
                       else if (elt_id->is_defined ())
                         {
-                          arg_template(iarg) = elt_id->rvalue1 ();
+                          arg_template(iarg) = tw->evaluate (elt_id);
                           arg_mask[iarg] = -1;
                         }
                       else
@@ -2024,7 +2026,7 @@
                 {
                   // If the head is a value, use it as root.
                   if (head_id->is_defined ())
-                    root_val = head_id->rvalue1 ();
+                    root_val = tw->evaluate (head_id);
                   else
                     {
                       // It's a name.
--- a/libinterp/octave-value/ov-fcn-handle.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-fcn-handle.h	Fri Apr 21 18:07:40 2017 -0400
@@ -35,6 +35,11 @@
 #include "ov-fcn.h"
 #include "ov-typeinfo.h"
 
+namespace octave
+{
+  class tree_evaluator;
+}
+
 // Function handles.
 
 class
@@ -200,7 +205,8 @@
 public:
 
   // Factory method.
-  static octave_fcn_handle *maybe_binder (const octave_value& f);
+  static octave_fcn_handle *maybe_binder (const octave_value& f,
+                                          octave::tree_evaluator *tw);
 
   octave_value_list
   do_multi_index_op (int nargout, const octave_value_list& args);
--- a/libinterp/octave-value/ov-usr-fcn.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/octave-value/ov-usr-fcn.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -150,7 +150,9 @@
 
       BEGIN_PROFILER_BLOCK (octave_user_script)
 
-        cmd_list->accept (*octave::current_evaluator);
+      octave::tree_evaluator *tw = octave::current_evaluator;
+
+      cmd_list->accept (*tw);
 
       END_PROFILER_BLOCK
 
@@ -521,8 +523,10 @@
 
   string_vector arg_names = args.name_tags ();
 
+  octave::tree_evaluator *tw = octave::current_evaluator;
+
   if (param_list && ! param_list->varargs_only ())
-    param_list->define_from_arg_vector (args);
+    tw->define_parameter_list_from_arg_vector (param_list, args);
 
   // For classdef constructor, pre-populate the output arguments
   // with the pre-initialized object instance, extracted above.
@@ -533,7 +537,7 @@
         error ("%s: invalid classdef constructor, no output argument defined",
                dispatch_class ().c_str ());
 
-      ret_list->define_from_arg_vector (ret_args);
+      tw->define_parameter_list_from_arg_vector (ret_list, ret_args);
     }
 
   // Force parameter list to be undefined when this function exits.
@@ -541,14 +545,16 @@
   // variables that are also named function parameters.
 
   if (param_list)
-    frame.add_method (param_list, &octave::tree_parameter_list::undefine);
+    frame.add_method (tw, &octave::tree_evaluator::undefine_parameter_list,
+                      param_list);
 
   // Force return list to be undefined when this function exits.
   // Doing so decrements the reference counts on the values of local
   // variables that are also named values returned by this function.
 
   if (ret_list)
-    frame.add_method (ret_list, &octave::tree_parameter_list::undefine);
+    frame.add_method (tw, &octave::tree_evaluator::undefine_parameter_list,
+                      ret_list);
 
   if (call_depth == 0)
     {
@@ -600,13 +606,11 @@
         {
           octave::call_stack::set_location (stmt->line (), stmt->column ());
 
-          retval = (lvalue_list
-                    ? expr->rvalue (nargout, lvalue_list)
-                    : expr->rvalue (nargout));
+          retval = tw->evaluate_n (expr, nargout, lvalue_list);
         }
     }
   else
-    cmd_list->accept (*octave::current_evaluator);
+    cmd_list->accept (*tw);
 
   END_PROFILER_BLOCK
 
@@ -623,7 +627,8 @@
 
   if (ret_list && ! is_special_expr ())
     {
-      ret_list->initialize_undefined_elements (my_name, nargout, Matrix ());
+      tw->initialize_undefined_parameter_list_elements (ret_list, my_name,
+                                                        nargout, Matrix ());
 
       Cell varargout;
 
@@ -635,7 +640,7 @@
             varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
         }
 
-      retval = ret_list->convert_to_const_vector (nargout, varargout);
+      retval = tw->convert_parameter_list_to_const_vector (ret_list, nargout, varargout);
     }
 
   return retval;
--- a/libinterp/parse-tree/module.mk	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/module.mk	Fri Apr 21 18:07:40 2017 -0400
@@ -34,6 +34,7 @@
   libinterp/parse-tree/pt-pr-code.h \
   libinterp/parse-tree/pt-select.h \
   libinterp/parse-tree/pt-stmt.h \
+  libinterp/parse-tree/pt-tm-const.h \
   libinterp/parse-tree/pt-unop.h \
   libinterp/parse-tree/pt-walk.h \
   libinterp/parse-tree/pt.h \
@@ -80,6 +81,7 @@
   libinterp/parse-tree/pt-pr-code.cc \
   libinterp/parse-tree/pt-select.cc \
   libinterp/parse-tree/pt-stmt.cc \
+  libinterp/parse-tree/pt-tm-const.cc \
   libinterp/parse-tree/pt-unop.cc \
   libinterp/parse-tree/pt-walk.cc \
   libinterp/parse-tree/pt.cc \
--- a/libinterp/parse-tree/oct-parse.in.yy	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri Apr 21 18:07:40 2017 -0400
@@ -2356,7 +2356,7 @@
               {
                 try
                   {
-                    octave_value tmp = e->rvalue1 ();
+                    octave_value tmp = octave::current_evaluator->evaluate (e);
 
                     tree_constant *tc_retval
                       = new tree_constant (tmp, base->line (), base->column ());
@@ -3913,7 +3913,7 @@
 
     if (e->is_constant ())
       {
-        octave_value ov = e->rvalue1 ();
+        octave_value ov = octave::current_evaluator->evaluate (e);
 
         delete e;
 
@@ -3981,7 +3981,7 @@
       {
         try
           {
-            octave_value tmp = array_list->rvalue1 ();
+            octave_value tmp = octave::current_evaluator->evaluate (array_list);
 
             tree_constant *tc_retval
               = new tree_constant (tmp, array_list->line (),
@@ -4337,7 +4337,7 @@
               bool is_at_folder = ! dispatch_type.empty ();
 
               fcn_ptr =
-                parser.classdef_object->make_meta_class (is_at_folder);
+                parser.classdef_object->make_meta_class (octave::current_evaluator, is_at_folder);
 
               delete (parser.classdef_object);
 
@@ -5131,7 +5131,7 @@
                     else
                       do_bind_ans = (! expr->is_assignment_expression ());
 
-                    retval = expr->rvalue (nargout);
+                    retval = octave::current_evaluator->evaluate_n (expr, nargout);
 
                     if (do_bind_ans && ! retval.empty ())
                       bind_ans (retval(0), expr->print_result ());
--- a/libinterp/parse-tree/pt-arg-list.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-arg-list.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -37,6 +37,7 @@
 #include "ov-usr-fcn.h"
 #include "parse.h"
 #include "pt-arg-list.h"
+#include "pt-eval.h"
 #include "pt-exp.h"
 #include "pt-id.h"
 #include "pt-idx.h"
@@ -204,7 +205,8 @@
 namespace octave
 {
   octave_value_list
-  tree_argument_list::convert_to_const_vector (const octave_value *object)
+  tree_argument_list::convert_to_const_vector (tree_evaluator *tw,
+                                               const octave_value *object)
   {
     // END doesn't make sense for functions.  Maybe we need a different
     // way of asking an octave_value object this question?
@@ -243,7 +245,7 @@
 
         if (elt)
           {
-            octave_value tmp = elt->rvalue1 ();
+            octave_value tmp = tw->evaluate (elt);
 
             if (tmp.is_cs_list ())
               args.push_back (tmp.list_value ());
@@ -261,12 +263,12 @@
   }
 
   std::list<octave_lvalue>
-  tree_argument_list::lvalue_list (void)
+  tree_argument_list::lvalue_list (tree_evaluator *tw)
   {
     std::list<octave_lvalue> retval;
 
     for (tree_expression* elt : *this)
-      retval.push_back (elt->lvalue ());
+      retval.push_back (elt->lvalue (tw));
 
     return retval;
   }
@@ -325,10 +327,4 @@
 
     return new_list;
   }
-
-  void
-  tree_argument_list::accept (tree_walker& tw)
-  {
-    tw.visit_argument_list (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-arg-list.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-arg-list.h	Fri Apr 21 18:07:40 2017 -0400
@@ -33,14 +33,14 @@
 #include "str-vec.h"
 
 #include "base-list.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
+  class tree_evaluator;
   class tree_expression;
 
-  class tree_walker;
-
   // Argument lists.  Used to hold the list of expressions that are the
   // arguments in a function call or index expression.
 
@@ -90,9 +90,10 @@
 
     bool is_valid_lvalue_list (void) const;
 
-    octave_value_list convert_to_const_vector (const octave_value *object = 0);
+    octave_value_list convert_to_const_vector (tree_evaluator *tw,
+                                               const octave_value *object = 0);
 
-    std::list<octave_lvalue> lvalue_list (void);
+    std::list<octave_lvalue> lvalue_list (tree_evaluator *tw);
 
     string_vector get_arg_names (void) const;
 
@@ -101,7 +102,10 @@
     tree_argument_list *dup (symbol_table::scope_id scope,
                              symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_argument_list (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-array-list.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-array-list.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,6 +32,8 @@
 
 namespace octave
 {
+  class tree_walker;
+
   // Base class for cell arrays and matrices.
 
   class tree_array_list : public tree_expression,
--- a/libinterp/parse-tree/pt-assign.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-assign.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -39,7 +39,6 @@
 #include "pt-arg-list.h"
 #include "pt-bp.h"
 #include "pt-assign.h"
-#include "pt-eval.h"
 #include "pt-walk.h"
 #include "utils.h"
 #include "variables.h"
@@ -62,80 +61,6 @@
     delete rhs;
   }
 
-  octave_value_list
-  tree_simple_assignment::rvalue (int nargout)
-  {
-    if (nargout > 1)
-      error ("invalid number of output arguments for expression X = RHS");
-
-    return rvalue1 (nargout);
-  }
-
-  octave_value
-  tree_simple_assignment::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (rhs)
-      {
-        octave_value rhs_val = rhs->rvalue1 ();
-
-        if (rhs_val.is_undefined ())
-          error ("value on right hand side of assignment is undefined");
-
-        if (rhs_val.is_cs_list ())
-          {
-            const octave_value_list lst = rhs_val.list_value ();
-
-            if (lst.empty ())
-              error ("invalid number of elements on RHS of assignment");
-
-            rhs_val = lst(0);
-          }
-
-        try
-          {
-            octave_lvalue ult = lhs->lvalue ();
-
-            if (ult.numel () != 1)
-              err_nonbraced_cs_list_assignment ();
-
-            ult.assign (etype, rhs_val);
-
-            if (etype == octave_value::op_asn_eq)
-              retval = rhs_val;
-            else
-              retval = ult.value ();
-
-            if (print_result ()
-                && octave::tree_evaluator::statement_printing_enabled ())
-              {
-                // We clear any index here so that we can
-                // get the new value of the referenced
-                // object below, instead of the indexed
-                // value (which should be the same as the
-                // right hand side value).
-
-                ult.clear_index ();
-
-                octave_value lhs_val = ult.value ();
-
-                octave_value_list args = ovl (lhs_val);
-                args.stash_name_tags (string_vector (lhs->name ()));
-                octave::feval ("display", args);
-              }
-          }
-        catch (octave::index_exception& e)
-          {
-            e.set_var (lhs->name ());
-            std::string msg = e.message ();
-            error_with_id (e.err_id (), msg.c_str ());
-          }
-      }
-
-    return retval;
-  }
-
   std::string
   tree_simple_assignment::oper (void) const
   {
@@ -156,12 +81,6 @@
     return new_sa;
   }
 
-  void
-  tree_simple_assignment::accept (tree_walker& tw)
-  {
-    tw.visit_simple_assignment (*this);
-  }
-
   // Multi-valued assignment expressions.
 
   tree_multi_assignment::tree_multi_assignment
@@ -178,171 +97,6 @@
     delete rhs;
   }
 
-  octave_value
-  tree_multi_assignment::rvalue1 (int nargout)
-  {
-    octave_value retval;
-
-    const octave_value_list tmp = rvalue (nargout);
-
-    if (! tmp.empty ())
-      retval = tmp(0);
-
-    return retval;
-  }
-
-  // FIXME: this works, but it would look a little better if
-  // it were broken up into a couple of separate functions.
-
-  octave_value_list
-  tree_multi_assignment::rvalue (int)
-  {
-    octave_value_list retval;
-
-    if (rhs)
-      {
-        std::list<octave_lvalue> lvalue_list = lhs->lvalue_list ();
-
-        octave_idx_type n_out = 0;
-
-        for (const auto& lval : lvalue_list)
-          n_out += lval.numel ();
-
-        // The following trick is used to keep rhs_val constant.
-        const octave_value_list rhs_val1 = rhs->rvalue (n_out, &lvalue_list);
-        const octave_value_list rhs_val = (rhs_val1.length () == 1
-                                           && rhs_val1(0).is_cs_list ()
-                                           ? rhs_val1(0).list_value ()
-                                           : rhs_val1);
-
-        octave_idx_type k = 0;
-
-        octave_idx_type n = rhs_val.length ();
-
-        // To avoid copying per elements and possible optimizations, we
-        // postpone joining the final values.
-        std::list<octave_value_list> retval_list;
-
-        tree_argument_list::iterator q = lhs->begin ();
-
-        for (octave_lvalue ult : lvalue_list)
-          {
-            tree_expression *lhs_elt = *q++;
-
-            octave_idx_type nel = ult.numel ();
-
-            if (nel != 1)
-              {
-                // Huge kluge so that wrapper scripts with lines like
-                //
-                //   [varargout{1:nargout}] = fcn (args);
-                //
-                // Will work the same as calling fcn directly when nargout
-                // is 0 and fcn produces more than one output even when
-                // nargout is 0.  This only works if varargout has not yet
-                // been defined.  See also bug #43813.
-
-                if (lvalue_list.size () == 1 && nel == 0 && n > 0
-                    && ! ult.is_black_hole () && ult.is_undefined ()
-                    && ult.index_type () == "{" && ult.index_is_empty ())
-                  {
-                    // Convert undefined lvalue with empty index to a cell
-                    // array with a single value and indexed by 1 to
-                    // handle a single output.
-
-                    nel = 1;
-
-                    ult.define (Cell (1, 1));
-
-                    ult.clear_index ();
-                    std::list<octave_value_list> idx;
-                    idx.push_back (octave_value_list (octave_value (1)));
-                    ult.set_index ("{", idx);
-                  }
-
-                if (k + nel > n)
-                  error ("some elements undefined in return list");
-
-                // This element of the return list expects a
-                // comma-separated list of values.  Slicing avoids
-                // copying.
-
-                octave_value_list ovl = rhs_val.slice (k, nel);
-
-                ult.assign (octave_value::op_asn_eq, octave_value (ovl));
-
-                retval_list.push_back (ovl);
-
-                k += nel;
-              }
-            else
-              {
-                if (k < n)
-                  {
-                    ult.assign (octave_value::op_asn_eq, rhs_val(k));
-
-                    if (ult.is_black_hole ())
-                      {
-                        k++;
-                        continue;
-                      }
-                    else
-                      {
-                        retval_list.push_back (rhs_val(k));
-
-                        k++;
-                      }
-                  }
-                else
-                  {
-                    // This can happen for a function like
-                    //
-                    //   function varargout = f ()
-                    //     varargout{1} = nargout;
-                    //   endfunction
-                    //
-                    // called with
-                    //
-                    //    [a, ~] = f ();
-                    //
-                    // Then the list of of RHS values will contain one
-                    // element but we are iterating over the list of all
-                    // RHS values.  We shouldn't complain that a value we
-                    // don't need is missing from the list.
-
-                    if (! ult.is_black_hole ())
-                      error ("element number %d undefined in return list", k+1);
-
-                    k++;
-                    continue;
-                  }
-              }
-
-            if (print_result ()
-                && octave::tree_evaluator::statement_printing_enabled ())
-              {
-                // We clear any index here so that we can get
-                // the new value of the referenced object below,
-                // instead of the indexed value (which should be
-                // the same as the right hand side value).
-
-                ult.clear_index ();
-
-                octave_value lhs_val = ult.value ();
-
-                octave_value_list args = ovl (lhs_val);
-                args.stash_name_tags (string_vector (lhs_elt->name ()));
-                octave::feval ("display", args);
-              }
-          }
-
-        // Concatenate return values.
-        retval = retval_list;
-      }
-
-    return retval;
-  }
-
   std::string
   tree_multi_assignment::oper (void) const
   {
@@ -362,12 +116,6 @@
 
     return new_ma;
   }
-
-  void
-  tree_multi_assignment::accept (tree_walker& tw)
-  {
-    tw.visit_multi_assignment (*this);
-  }
 }
 
 /*
--- a/libinterp/parse-tree/pt-assign.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-assign.h	Fri Apr 21 18:07:40 2017 -0400
@@ -34,14 +34,13 @@
 
 #include "ov.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
   class tree_argument_list;
 
-  class tree_walker;
-
   // Simple assignment expressions.
 
   class tree_simple_assignment : public tree_expression
@@ -69,10 +68,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     bool is_assignment_expression (void) const { return true; }
 
     std::string oper (void) const;
@@ -84,8 +79,11 @@
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
-
+    void accept (tree_walker& tw)
+    {
+      tw.visit_simple_assignment (*this);
+    }
+    
     octave_value::assign_op op_type (void) const { return etype; }
 
   private:
@@ -137,10 +135,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     std::string oper (void) const;
 
     tree_argument_list *left_hand_side (void) { return lhs; }
@@ -150,7 +144,10 @@
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_multi_assignment (*this);
+    }
 
     octave_value::assign_op op_type (void) const
     { return octave_value::op_asn_eq; }
--- a/libinterp/parse-tree/pt-binop.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-binop.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -38,20 +38,6 @@
 {
   // Binary expressions.
 
-  octave_value_list
-  tree_binary_expression::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("binary operator '%s': invalid number of output arguments",
-             oper ().c_str ());
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
   void
   tree_binary_expression::matlab_style_short_circuit_warning (const char *op)
   {
@@ -62,80 +48,6 @@
     braindead_shortcircuit_warning_issued = true;
   }
 
-  octave_value
-  tree_binary_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (eligible_for_braindead_shortcircuit)
-      {
-        if (op_lhs)
-          {
-            octave_value a = op_lhs->rvalue1 ();
-
-            if (a.ndims () == 2 && a.rows () == 1 && a.columns () == 1)
-              {
-                bool result = false;
-
-                bool a_true = a.is_true ();
-
-                if (a_true)
-                  {
-                    if (etype == octave_value::op_el_or)
-                      {
-                        matlab_style_short_circuit_warning ("|");
-                        return octave_value (true);
-                      }
-                  }
-                else
-                  {
-                    if (etype == octave_value::op_el_and)
-                      {
-                        matlab_style_short_circuit_warning ("&");
-                        return octave_value (false);
-                      }
-                  }
-
-                if (op_rhs)
-                  {
-                    octave_value b = op_rhs->rvalue1 ();
-
-                    result = b.is_true ();
-                  }
-
-                return octave_value (result);
-              }
-          }
-      }
-
-    if (op_lhs)
-      {
-        octave_value a = op_lhs->rvalue1 ();
-
-        if (a.is_defined () && op_rhs)
-          {
-            octave_value b = op_rhs->rvalue1 ();
-
-            if (b.is_defined ())
-              {
-                BEGIN_PROFILER_BLOCK (tree_binary_expression)
-
-                  // Note: The profiler does not catch the braindead
-                  // short-circuit evaluation code above, but that should be
-                  // ok.  The evaluation of operands and the operator itself
-                  // is entangled and it's not clear where to start/stop
-                  // timing the operator to make it reasonable.
-
-                  retval = ::do_binary_op (etype, a, b);
-
-                END_PROFILER_BLOCK
-                  }
-          }
-      }
-
-    return retval;
-  }
-
   std::string
   tree_binary_expression::oper (void) const
   {
@@ -156,70 +68,8 @@
     return new_be;
   }
 
-  void
-  tree_binary_expression::accept (tree_walker& tw)
-  {
-    tw.visit_binary_expression (*this);
-  }
-
   // Boolean expressions.
 
-  octave_value_list
-  tree_boolean_expression::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("binary operator '%s': invalid number of output arguments",
-             oper ().c_str ());
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
-  octave_value
-  tree_boolean_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    bool result = false;
-
-    // This evaluation is not caught by the profiler, since we can't find
-    // a reasonable place where to time.  Note that we don't want to
-    // include evaluation of LHS or RHS into the timing, but this is
-    // entangled together with short-circuit evaluation here.
-
-    if (op_lhs)
-      {
-        octave_value a = op_lhs->rvalue1 ();
-
-        bool a_true = a.is_true ();
-
-        if (a_true)
-          {
-            if (etype == bool_or)
-              return octave_value (true);
-          }
-        else
-          {
-            if (etype == bool_and)
-              return octave_value (false);
-          }
-
-        if (op_rhs)
-          {
-            octave_value b = op_rhs->rvalue1 ();
-
-            result = b.is_true ();
-          }
-
-        retval = octave_value (result);
-      }
-
-    return retval;
-  }
-
   std::string
   tree_boolean_expression::oper (void) const
   {
@@ -255,10 +105,4 @@
 
     return new_be;
   }
-
-  void
-  tree_boolean_expression::accept (tree_walker& tw)
-  {
-    tw.visit_boolean_expression (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-binop.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-binop.h	Fri Apr 21 18:07:40 2017 -0400
@@ -33,12 +33,11 @@
 
 #include "ov.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // Binary expressions.
 
   class tree_binary_expression : public tree_expression
@@ -93,10 +92,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     std::string oper (void) const;
 
     octave_value::binary_op op_type (void) const { return etype; }
@@ -104,13 +99,23 @@
     tree_expression *lhs (void) { return op_lhs; }
     tree_expression *rhs (void) { return op_rhs; }
 
+    bool is_eligible_for_braindead_shortcircuit (void) const
+    {
+      return eligible_for_braindead_shortcircuit;
+    }
+
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_binary_expression (*this);
+    }
 
     std::string profiler_name (void) const { return "binary " + oper (); }
 
+    void matlab_style_short_circuit_warning (const char *op);
+
   protected:
 
     // The operands for the expression.
@@ -129,8 +134,6 @@
     // TRUE if we have already issued a warning about short circuiting
     // for this operator.
     bool braindead_shortcircuit_warning_issued;
-
-    void matlab_style_short_circuit_warning (const char *op);
   };
 
   // Boolean expressions.
@@ -165,10 +168,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     std::string oper (void) const;
 
     type op_type (void) const { return etype; }
@@ -176,7 +175,10 @@
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_boolean_expression (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-cbinop.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cbinop.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -35,41 +35,6 @@
 namespace octave
 {
   typedef tree_expression* tree_expression_ptr_t;
-
-  octave_value_list
-  tree_compound_binary_expression::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("binary operator '%s': invalid number of output arguments",
-             oper ().c_str ());
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
-  octave_value
-  tree_compound_binary_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (op_lhs)
-      {
-        octave_value a = op_lhs->rvalue1 ();
-
-        if (a.is_defined () && op_rhs)
-          {
-            octave_value b = op_rhs->rvalue1 ();
-
-            if (b.is_defined ())
-              retval = ::do_binary_op (etype, a, b);
-          }
-      }
-
-    return retval;
-  }
 }
 
 // If a tree expression is a transpose or hermitian transpose, return
@@ -239,10 +204,4 @@
 
     return ret;
   }
-
-  void
-  tree_compound_binary_expression::accept (tree_walker& tw)
-  {
-    tw.visit_compound_binary_expression (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-cbinop.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cbinop.h	Fri Apr 21 18:07:40 2017 -0400
@@ -33,12 +33,11 @@
 
 #include "ov.h"
 #include "pt-binop.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // Binary expressions that can be reduced to compound operations
 
   class tree_compound_binary_expression : public tree_binary_expression
@@ -57,11 +56,10 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_compound_binary_expression (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-cell.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cell.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -36,66 +36,6 @@
 
 namespace octave
 {
-  octave_value
-  tree_cell::rvalue1 (int)
-  {
-    octave_value retval;
-
-    octave_idx_type nr = length ();
-    octave_idx_type nc = -1;
-
-    Cell val;
-
-    octave_idx_type i = 0;
-
-    for (tree_argument_list* elt : *this)
-      {
-        octave_value_list row = elt->convert_to_const_vector ();
-
-        if (nr == 1)
-          // Optimize the single row case.
-          val = row.cell_value ();
-        else if (nc < 0)
-          {
-            nc = row.length ();
-
-            val = Cell (nr, nc);
-          }
-        else
-          {
-            octave_idx_type this_nc = row.length ();
-
-            if (this_nc != nc)
-              {
-                if (this_nc == 0)
-                  continue;  // blank line
-                else
-                  error ("number of columns must match");
-              }
-          }
-
-        for (octave_idx_type j = 0; j < nc; j++)
-          val(i,j) = row(j);
-
-        i++;
-      }
-
-    if (i < nr)
-      val.resize (dim_vector (i, nc));  // there were blank rows
-    retval = val;
-
-    return retval;
-  }
-
-  octave_value_list
-  tree_cell::rvalue (int nargout)
-  {
-    if (nargout > 1)
-      error ("invalid number of output arguments for cell array");
-
-    return rvalue1 (nargout);
-  }
-
   tree_expression *
   tree_cell::dup (symbol_table::scope_id scope,
                   symbol_table::context_id context) const
@@ -106,10 +46,4 @@
 
     return new_cell;
   }
-
-  void
-  tree_cell::accept (tree_walker& tw)
-  {
-    tw.visit_cell (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-cell.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cell.h	Fri Apr 21 18:07:40 2017 -0400
@@ -31,14 +31,13 @@
 class octave_value_list;
 
 #include "pt-mat.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
   class tree_argument_list;
 
-  class tree_walker;
-
   // General cells.
 
   class tree_cell : public tree_array_list
@@ -61,14 +60,13 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int);
-
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_cell (*this);
+    }
   };
 }
 
--- a/libinterp/parse-tree/pt-classdef.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-classdef.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -31,12 +31,6 @@
 {
   // Classdef attribute
 
-  void
-  tree_classdef_attribute::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_attribute (*this);
-  }
-
   // Classdef attribute_list
 
   tree_classdef_attribute_list::~tree_classdef_attribute_list (void)
@@ -49,20 +43,8 @@
       }
   }
 
-  void
-  tree_classdef_attribute_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_attribute_list (*this);
-  }
-
   // Classdef superclass
 
-  void
-  tree_classdef_superclass::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_superclass (*this);
-  }
-
   // Classdef superclass_list
 
   tree_classdef_superclass_list::~tree_classdef_superclass_list (void)
@@ -75,20 +57,8 @@
       }
   }
 
-  void
-  tree_classdef_superclass_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_superclass_list (*this);
-  }
-
   // Classdef property
 
-  void
-  tree_classdef_property::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_property (*this);
-  }
-
   // Classdef property_list
 
   tree_classdef_property_list::~tree_classdef_property_list (void)
@@ -101,44 +71,14 @@
       }
   }
 
-  void
-  tree_classdef_property_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_property_list (*this);
-  }
-
   // Classdef properties_block
 
-  void
-  tree_classdef_properties_block::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_properties_block (*this);
-  }
-
   // Classdef methods_list
 
-  void
-  tree_classdef_methods_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_methods_list (*this);
-  }
-
   // Classdef methods_block
 
-  void
-  tree_classdef_methods_block::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_methods_block (*this);
-  }
-
   // Classdef event
 
-  void
-  tree_classdef_event::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_event (*this);
-  }
-
   // Classdef events_list
 
   tree_classdef_events_list::~tree_classdef_events_list (void)
@@ -151,28 +91,10 @@
       }
   }
 
-  void
-  tree_classdef_events_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_events_list (*this);
-  }
-
   // Classdef events_block
 
-  void
-  tree_classdef_events_block::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_events_block (*this);
-  }
-
   // Classdef enum
 
-  void
-  tree_classdef_enum::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_enum (*this);
-  }
-
   // Classdef enum_list
 
   tree_classdef_enum_list::~tree_classdef_enum_list (void)
@@ -185,20 +107,8 @@
       }
   }
 
-  void
-  tree_classdef_enum_list::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_enum_list (*this);
-  }
-
   // Classdef enum_block
 
-  void
-  tree_classdef_enum_block::accept (tree_walker& tw)
-  {
-    tw.visit_classdef_enum_block (*this);
-  }
-
   // Classdef body
 
   tree_classdef_body::~tree_classdef_body (void)
@@ -235,9 +145,9 @@
   // Classdef
 
   octave_function*
-  tree_classdef::make_meta_class (bool is_at_folder)
+  tree_classdef::make_meta_class (tree_evaluator *tw, bool is_at_folder)
   {
-    cdef_class cls = cdef_class::make_meta_class (this, is_at_folder);
+    cdef_class cls = cdef_class::make_meta_class (tw, this, is_at_folder);
 
     if (cls.ok ())
       return cls.get_constructor_function ();
@@ -252,10 +162,4 @@
     // FIXME
     return 0;
   }
-
-  void
-  tree_classdef::accept (tree_walker& tw)
-  {
-    tw.visit_classdef (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-classdef.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-classdef.h	Fri Apr 21 18:07:40 2017 -0400
@@ -29,6 +29,7 @@
 
 #include "pt-cmd.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "pt-id.h"
 
 #include "base-list.h"
@@ -37,8 +38,6 @@
 
 namespace octave
 {
-  class tree_walker;
-
   class tree_classdef_attribute
   {
   public:
@@ -67,7 +66,10 @@
 
     bool negate (void) { return neg; }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_attribute (*this);
+    }
 
   private:
 
@@ -96,7 +98,10 @@
 
     ~tree_classdef_attribute_list (void);
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_attribute_list (*this);
+    }
   };
 
   class tree_classdef_superclass
@@ -117,7 +122,10 @@
 
     std::string class_name (void) { return cls_name; }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_superclass (*this);
+    }
 
   private:
 
@@ -144,7 +152,10 @@
 
     ~tree_classdef_superclass_list (void);
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_superclass_list (*this);
+    }
   };
 
   template <typename T>
@@ -222,7 +233,10 @@
 
     tree_expression *expression (void) { return expr; }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_property (*this);
+    }
 
   private:
 
@@ -250,7 +264,10 @@
 
     ~tree_classdef_property_list (void);
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_property_list (*this);
+    }
   };
 
   class tree_classdef_properties_block
@@ -274,7 +291,10 @@
 
     ~tree_classdef_properties_block (void) = default;
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_properties_block (*this);
+    }
   };
 
   class tree_classdef_methods_list : public octave::base_list<octave_value>
@@ -297,7 +317,10 @@
 
     ~tree_classdef_methods_list (void) = default;
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_methods_list (*this);
+    }
   };
 
   class tree_classdef_methods_block : public tree_classdef_element<octave_value>
@@ -319,7 +342,10 @@
 
     ~tree_classdef_methods_block (void) = default;
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_methods_block (*this);
+    }
   };
 
   class tree_classdef_event
@@ -341,7 +367,10 @@
 
     tree_identifier *ident (void) { return id; }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_event (*this);
+    }
 
   private:
 
@@ -368,7 +397,10 @@
 
     ~tree_classdef_events_list (void);
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_events_list (*this);
+    }
   };
 
   class tree_classdef_events_block
@@ -391,7 +423,10 @@
 
     ~tree_classdef_events_block (void) = default;
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_events_block (*this);
+    }
   };
 
   class tree_classdef_enum
@@ -419,7 +454,10 @@
 
     tree_expression *expression (void) { return expr; }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_enum (*this);
+    }
 
   private:
 
@@ -446,7 +484,10 @@
 
     ~tree_classdef_enum_list (void);
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_enum_list (*this);
+    }
   };
 
   class tree_classdef_enum_block
@@ -469,7 +510,10 @@
 
     ~tree_classdef_enum_block (void) = default;
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_enum_block (*this);
+    }
   };
 
   class tree_classdef_body
@@ -563,7 +607,10 @@
       return enum_lst;
     }
 
-    void accept (tree_walker&);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef_body (*this);
+    }
 
   private:
 
@@ -621,12 +668,16 @@
 
     const std::string& package_name (void) const { return pack_name; }
 
-    octave_function* make_meta_class (bool is_at_folder = false);
+    octave_function* make_meta_class (tree_evaluator *tw,
+                                      bool is_at_folder = false);
 
     tree_classdef *dup (symbol_table::scope_id scope,
                         symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_classdef (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-cmd.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cmd.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -39,12 +39,6 @@
                                    line (), column ());
   }
 
-  void
-  tree_no_op_command::accept (tree_walker& tw)
-  {
-    tw.visit_no_op_command (*this);
-  }
-
   // Function definition.
 
   tree_command *
@@ -53,10 +47,4 @@
   {
     return new tree_function_def (fcn, line (), column ());
   }
-
-  void
-  tree_function_def::accept (tree_walker& tw)
-  {
-    tw.visit_function_def (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-cmd.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-cmd.h	Fri Apr 21 18:07:40 2017 -0400
@@ -30,12 +30,11 @@
 #include "ov-fcn.h"
 #include "pt.h"
 #include "pt-bp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // A base class for commands.
 
   class tree_command : public tree
@@ -78,7 +77,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_no_op_command (*this);
+    }
 
     bool is_end_of_fcn_or_script (void) const
     {
@@ -116,7 +118,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_function_def (*this);
+    }
 
     octave_value function (void) { return fcn; }
 
--- a/libinterp/parse-tree/pt-colon.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-colon.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -65,68 +65,6 @@
     return retval;
   }
 
-  octave_value_list
-  tree_colon_expression::rvalue (int nargout)
-  {
-    if (nargout > 1)
-      error ("invalid number of output arguments for colon expression");
-
-    return rvalue1 (nargout);
-  }
-
-  octave_value
-  tree_colon_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (! op_base || ! op_limit)
-      return retval;
-
-    octave_value ov_base = op_base->rvalue1 ();
-
-    octave_value ov_limit = op_limit->rvalue1 ();
-
-    if (ov_base.is_object () || ov_limit.is_object ())
-      {
-        octave_value_list tmp1;
-
-        if (op_increment)
-          {
-            octave_value ov_increment = op_increment->rvalue1 ();
-
-            tmp1(2) = ov_limit;
-            tmp1(1) = ov_increment;
-            tmp1(0) = ov_base;
-          }
-        else
-          {
-            tmp1(1) = ov_limit;
-            tmp1(0) = ov_base;
-          }
-
-        octave_value fcn = symbol_table::find_function ("colon", tmp1);
-
-        if (! fcn.is_defined ())
-          error ("can not find overloaded colon function");
-
-        octave_value_list tmp2 = fcn.do_multi_index_op (1, tmp1);
-
-        retval = tmp2 (0);
-      }
-    else
-      {
-        octave_value ov_increment = 1.0;
-
-        if (op_increment)
-          ov_increment = op_increment->rvalue1 ();
-
-        retval = do_colon_op (ov_base, ov_increment, ov_limit,
-                              is_for_cmd_expr ());
-      }
-
-    return retval;
-  }
-
   void
   tree_colon_expression::eval_error (const std::string& s) const
   {
@@ -166,10 +104,4 @@
 
     return new_ce;
   }
-
-  void
-  tree_colon_expression::accept (tree_walker& tw)
-  {
-    tw.visit_colon_expression (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-colon.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-colon.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,12 +32,11 @@
 class octave_lvalue;
 
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // Colon expressions.
 
   class tree_colon_expression : public tree_expression
@@ -85,10 +84,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     void eval_error (const std::string& s) const;
 
     tree_expression *base (void) { return op_base; }
@@ -103,7 +98,10 @@
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_colon_expression (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-const.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-const.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -57,19 +57,6 @@
       val.print_raw (os, pr_as_read_syntax);
   }
 
-  octave_value_list
-  tree_constant::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("invalid number of output arguments for constant expression");
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
   tree_expression *
   tree_constant::dup (symbol_table::scope_id,
                       symbol_table::context_id) const
@@ -81,10 +68,4 @@
 
     return new_tc;
   }
-
-  void
-  tree_constant::accept (tree_walker& tw)
-  {
-    tw.visit_constant (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-const.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-const.h	Fri Apr 21 18:07:40 2017 -0400
@@ -33,12 +33,11 @@
 #include "ov.h"
 #include "pt-bp.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   class tree_constant : public tree_expression
   {
   public:
@@ -77,14 +76,15 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int = 1) { return val; }
-
-    octave_value_list rvalue (int nargout);
+    octave_value value (void) { return val; }
 
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_constant (*this);
+    }
 
     // Store the original text corresponding to this constant for later
     // pretty printing.
--- a/libinterp/parse-tree/pt-decl.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-decl.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -47,25 +47,6 @@
     delete expr;
   }
 
-  bool
-  tree_decl_elt::eval (void)
-  {
-    bool retval = false;
-
-    if (id && expr)
-      {
-        octave_lvalue ult = id->lvalue ();
-
-        octave_value init_val = expr->rvalue1 ();
-
-        ult.assign (octave_value::op_asn_eq, init_val);
-
-        retval = true;
-      }
-
-    return retval;
-  }
-
   tree_decl_elt *
   tree_decl_elt::dup (symbol_table::scope_id scope,
                       symbol_table::context_id context) const
@@ -74,12 +55,6 @@
                               expr ? expr->dup (scope, context) : 0);
   }
 
-  void
-  tree_decl_elt::accept (tree_walker& tw)
-  {
-    tw.visit_decl_elt (*this);
-  }
-
   // Initializer lists for declaration statements.
 
   tree_decl_init_list *
@@ -94,12 +69,6 @@
     return new_dil;
   }
 
-  void
-  tree_decl_init_list::accept (tree_walker& tw)
-  {
-    tw.visit_decl_init_list (*this);
-  }
-
   // Base class for declaration commands (global, static).
 
   tree_decl_command::~tree_decl_command (void)
@@ -118,12 +87,6 @@
                                line (), column ());
   }
 
-  void
-  tree_global_command::accept (tree_walker& tw)
-  {
-    tw.visit_global_command (*this);
-  }
-
   // Static.
 
   tree_command *
@@ -135,10 +98,4 @@
                                    : 0,
                                    line (), column ());
   }
-
-  void
-  tree_persistent_command::accept (tree_walker& tw)
-  {
-    tw.visit_persistent_command (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-decl.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-decl.h	Fri Apr 21 18:07:40 2017 -0400
@@ -31,15 +31,15 @@
 #include "oct-lvalue.h"
 #include "pt-cmd.h"
 #include "pt-id.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
+  class tree_evaluator;
   class tree_expression;
   class tree_identifier;
 
-  class tree_walker;
-
   // List of expressions that make up a declaration statement.
 
   class tree_decl_elt
@@ -57,8 +57,6 @@
 
     ~tree_decl_elt (void);
 
-    bool eval (void);
-
     bool is_defined (void) { return id ? id->is_defined () : false; }
 
     bool is_variable (void) { return id ? id->is_variable () : false; }
@@ -71,26 +69,11 @@
 
     bool lvalue_ok (void) { return id ? id->lvalue_ok () : false; }
 
-    // Do not allow functions to return null values.
-    octave_value rvalue1 (int nargout = 1)
-    {
-      return id ? id->rvalue1 (nargout).storable_value () : octave_value ();
-    }
-
-    octave_value_list rvalue (int nargout)
+    octave_lvalue lvalue (tree_evaluator *tw)
     {
-      octave_value_list retval;
-
-      if (nargout > 1)
-        error ("invalid number of output arguments in declaration list");
-
-      retval = rvalue1 (nargout);
-
-      return retval;
+      return id ? id->lvalue (tw) : octave_lvalue ();
     }
 
-    octave_lvalue lvalue (void) { return id ? id->lvalue () : octave_lvalue (); }
-
     tree_identifier *ident (void) { return id; }
 
     std::string name (void) { return id ? id->name () : ""; }
@@ -100,7 +83,10 @@
     tree_decl_elt *dup (symbol_table::scope_id scope,
                         symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_decl_elt (*this);
+    }
 
   private:
 
@@ -138,7 +124,10 @@
     tree_decl_init_list *dup (symbol_table::scope_id scope,
                               symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_decl_init_list (*this);
+    }
   };
 
   // Base class for declaration commands -- global, static, etc.
@@ -198,7 +187,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_global_command (*this);
+    }
 
   private:
 
@@ -228,7 +220,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_persistent_command (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-eval.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-eval.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -40,11 +40,15 @@
 #include "interpreter.h"
 #include "ov-fcn-handle.h"
 #include "ov-usr-fcn.h"
-#include "variables.h"
+#include "ov-re-sparse.h"
+#include "ov-cx-sparse.h"
+#include "profiler.h"
 #include "pt-all.h"
 #include "pt-eval.h"
+#include "pt-tm-const.h"
 #include "symtab.h"
 #include "unwind-prot.h"
+#include "variables.h"
 
 //FIXME: This should be part of tree_evaluator
 #include "pt-jit.h"
@@ -75,9 +79,66 @@
   // Normal evaluator.
 
   void
-  tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&)
+  tree_evaluator::reset (void)
+  {
+    m_value_stack.clear ();
+    m_lvalue_list_stack.pop ();
+    m_nargout_stack.pop ();
+  }
+
+  void
+  tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle& expr)
   {
-    panic_impossible ();
+    // FIXME: should CMD_LIST be limited to a single expression?
+    // I think that is what Matlab does.
+
+    tree_parameter_list *param_list = expr.parameter_list ();
+    tree_parameter_list *ret_list = expr.return_list ();
+    tree_statement_list *cmd_list = expr.body ();
+    symbol_table::scope_id this_scope = expr.scope ();
+
+    symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope);
+
+    if (new_scope > 0)
+      symbol_table::inherit (new_scope, symbol_table::current_scope (),
+                             symbol_table::current_context ());
+
+    octave_user_function *uf
+      = new octave_user_function (new_scope,
+                                  param_list ? param_list->dup (new_scope, 0) : 0,
+                                  ret_list ? ret_list->dup (new_scope, 0) : 0,
+                                  cmd_list ? cmd_list->dup (new_scope, 0) : 0);
+
+    octave_function *curr_fcn = octave::call_stack::current ();
+
+    if (curr_fcn)
+      {
+        // FIXME: maybe it would be better to just stash curr_fcn
+        // instead of individual bits of info about it?
+
+        uf->stash_parent_fcn_name (curr_fcn->name ());
+        uf->stash_dir_name (curr_fcn->dir_name ());
+
+        symbol_table::scope_id parent_scope = curr_fcn->parent_fcn_scope ();
+
+        if (parent_scope < 0)
+          parent_scope = curr_fcn->scope ();
+
+        uf->stash_parent_fcn_scope (parent_scope);
+
+        if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
+          uf->stash_dispatch_class (curr_fcn->dispatch_class ());
+      }
+
+    uf->mark_as_anonymous_function ();
+    uf->stash_fcn_file_name (expr.file_name ());
+    uf->stash_fcn_location (expr.line (), expr.column ());
+
+    octave_value ov_fcn (uf);
+
+    octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn, this));
+
+    m_value_stack.push (ovl (fh));
   }
 
   void
@@ -87,9 +148,166 @@
   }
 
   void
-  tree_evaluator::visit_binary_expression (tree_binary_expression&)
+  tree_evaluator::visit_binary_expression (tree_binary_expression& expr)
   {
-    panic_impossible ();
+    octave_value val;
+
+    tree_expression *op_lhs = expr.lhs ();
+    tree_expression *op_rhs = expr.rhs ();
+    octave_value::binary_op etype = expr.op_type ();
+
+    if (expr.is_eligible_for_braindead_shortcircuit ())
+      {
+        if (op_lhs)
+          {
+            octave_value a = evaluate (op_lhs);
+
+            if (a.ndims () == 2 && a.rows () == 1 && a.columns () == 1)
+              {
+                bool result = false;
+
+                bool a_true = a.is_true ();
+
+                if (a_true)
+                  {
+                    if (etype == octave_value::op_el_or)
+                      {
+                        expr.matlab_style_short_circuit_warning ("|");
+                        m_value_stack.push (ovl (octave_value (true)));
+                        return;
+                      }
+                  }
+                else
+                  {
+                    if (etype == octave_value::op_el_and)
+                      {
+                        expr.matlab_style_short_circuit_warning ("&");
+                        m_value_stack.push (ovl (octave_value (false)));
+                        return;
+                      }
+                  }
+
+                if (op_rhs)
+                  {
+                    octave_value b = evaluate (op_rhs);
+
+                    result = b.is_true ();
+                  }
+
+                m_value_stack.push (ovl (octave_value (result)));
+                return;
+              }
+          }
+      }
+
+    if (op_lhs)
+      {
+        octave_value a = evaluate (op_lhs);
+
+        if (a.is_defined () && op_rhs)
+          {
+            octave_value b = evaluate (op_rhs);
+
+            if (b.is_defined ())
+              {
+                profile_data_accumulator::enter<tree_binary_expression>
+                  block (profiler, expr);
+
+                // Note: The profiler does not catch the braindead
+                // short-circuit evaluation code above, but that should be
+                // ok.  The evaluation of operands and the operator itself
+                // is entangled and it's not clear where to start/stop
+                // timing the operator to make it reasonable.
+
+                val = ::do_binary_op (etype, a, b);
+              }
+          }
+      }
+
+    m_value_stack.push (ovl (val));
+  }
+
+  void
+  tree_evaluator::visit_boolean_expression (tree_boolean_expression& expr)
+  {
+    octave_value val;
+
+    bool result = false;
+
+    // This evaluation is not caught by the profiler, since we can't find
+    // a reasonable place where to time.  Note that we don't want to
+    // include evaluation of LHS or RHS into the timing, but this is
+    // entangled together with short-circuit evaluation here.
+
+    tree_expression *op_lhs = expr.lhs ();
+
+    if (op_lhs)
+      {
+        octave_value a = evaluate (op_lhs);
+
+        bool a_true = a.is_true ();
+
+        tree_boolean_expression::type etype = expr.op_type ();
+
+        if (a_true)
+          {
+            if (etype == tree_boolean_expression::bool_or)
+              {
+                m_value_stack.push (ovl (octave_value (true)));
+                return;
+              }
+          }
+        else
+          {
+            if (etype == tree_boolean_expression::bool_and)
+              {
+                m_value_stack.push (ovl (octave_value (false)));
+                return;
+              }
+          }
+
+        tree_expression *op_rhs = expr.rhs ();
+
+        if (op_rhs)
+          {
+            octave_value b = evaluate (op_rhs);
+
+            result = b.is_true ();
+          }
+
+        val = octave_value (result);
+      }
+
+    m_value_stack.push (ovl (val));
+  }
+
+  void
+  tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression& expr)
+  {
+    octave_value val;
+
+    tree_expression *op_lhs = expr.lhs ();
+
+    if (op_lhs)
+      {
+        octave_value a = evaluate (op_lhs);
+
+        tree_expression *op_rhs = expr.rhs ();
+
+        if (a.is_defined () && op_rhs)
+          {
+            octave_value b = evaluate (op_rhs);
+
+            if (b.is_defined ())
+              {
+                octave_value::binary_op etype = expr.op_type ();                
+
+                val = ::do_binary_op (etype, a, b);
+              }
+          }
+      }
+
+    m_value_stack.push (ovl (val));
   }
 
   void
@@ -105,9 +323,64 @@
   }
 
   void
-  tree_evaluator::visit_colon_expression (tree_colon_expression&)
+  tree_evaluator::visit_colon_expression (tree_colon_expression& expr)
   {
-    panic_impossible ();
+    octave_value val;
+
+    tree_expression *op_base = expr.base ();
+    tree_expression *op_limit = expr.limit ();
+
+    if (! op_base || ! op_limit)
+      {
+        m_value_stack.push (ovl (octave_value (val)));
+        return;
+      }
+
+    octave_value ov_base = evaluate (op_base);
+
+    octave_value ov_limit = evaluate (op_limit);
+
+    tree_expression *op_increment = expr.increment ();
+
+    if (ov_base.is_object () || ov_limit.is_object ())
+      {
+        octave_value_list tmp1;
+
+        if (op_increment)
+          {
+            octave_value ov_increment = evaluate (op_increment);
+
+            tmp1(2) = ov_limit;
+            tmp1(1) = ov_increment;
+            tmp1(0) = ov_base;
+          }
+        else
+          {
+            tmp1(1) = ov_limit;
+            tmp1(0) = ov_base;
+          }
+
+        octave_value fcn = symbol_table::find_function ("colon", tmp1);
+
+        if (! fcn.is_defined ())
+          error ("can not find overloaded colon function");
+
+        octave_value_list tmp2 = fcn.do_multi_index_op (1, tmp1);
+
+        val = tmp2 (0);
+      }
+    else
+      {
+        octave_value ov_increment = 1.0;
+
+        if (op_increment)
+          ov_increment = evaluate (op_increment);
+
+        val = do_colon_op (ov_base, ov_increment, ov_limit,
+                           expr.is_for_cmd_expr ());
+      }
+
+    m_value_stack.push (ovl (val));
   }
 
   void
@@ -134,72 +407,257 @@
     return ! (Vsilent_functions && (statement_context == function
                                     || statement_context == script));
   }
-}
-
-static inline void
-do_global_init (octave::tree_decl_elt& elt)
-{
-  octave::tree_identifier *id = elt.ident ();
-
-  if (id)
-    {
-      id->mark_global ();
-
-      octave_lvalue ult = id->lvalue ();
-
-      if (ult.is_undefined ())
-        {
-          octave::tree_expression *expr = elt.expression ();
-
-          octave_value init_val;
-
-          if (expr)
-            init_val = expr->rvalue1 ();
-          else
-            init_val = Matrix ();
-
-          ult.assign (octave_value::op_asn_eq, init_val);
-        }
-    }
-}
-
-static inline void
-do_static_init (octave::tree_decl_elt& elt)
-{
-  octave::tree_identifier *id = elt.ident ();
-
-  if (id)
-    {
-      id->mark_as_static ();
-
-      octave_lvalue ult = id->lvalue ();
-
-      if (ult.is_undefined ())
-        {
-          octave::tree_expression *expr = elt.expression ();
-
-          octave_value init_val;
-
-          if (expr)
-            init_val = expr->rvalue1 ();
-          else
-            init_val = Matrix ();
-
-          ult.assign (octave_value::op_asn_eq, init_val);
-        }
-    }
-}
-
-namespace octave
-{
+
+  octave_value
+  tree_evaluator::evaluate (tree_decl_elt *elt)
+  {
+    // Do not allow functions to return null values.
+
+    tree_identifier *id = elt->ident ();
+
+    return id ? evaluate (id).storable_value () : octave_value ();
+  }
+
+  void
+  tree_evaluator::initialize_undefined_parameter_list_elements
+    (tree_parameter_list *param_list, const std::string& warnfor,
+     int nargout, const octave_value& val)
+  {
+    bool warned = false;
+
+    int count = 0;
+
+    octave_value tmp = symbol_table::varval (".ignored.");
+    const Matrix ignored = tmp.is_defined () ? tmp.matrix_value () : Matrix ();
+
+    octave_idx_type k = 0;
+
+    for (tree_decl_elt* elt : *param_list)
+      {
+        if (++count > nargout)
+          break;
+
+        if (! elt->is_variable ())
+          {
+            if (! warned)
+              {
+                warned = true;
+
+                while (k < ignored.numel ())
+                  {
+                    octave_idx_type l = ignored (k);
+                    if (l == count)
+                      {
+                        warned = false;
+                        break;
+                      }
+                    else if (l > count)
+                      break;
+                    else
+                      k++;
+                  }
+
+                if (warned)
+                  {
+                    warning_with_id
+                      ("Octave:undefined-return-values",
+                       "%s: some elements in list of return values are undefined",
+                       warnfor.c_str ());
+                  }
+              }
+
+            octave_lvalue lval = elt->lvalue (this);
+
+            lval.assign (octave_value::op_asn_eq, val);
+          }
+      }
+  }
+
+  void
+  tree_evaluator::define_parameter_list_from_arg_vector
+    (tree_parameter_list *param_list, const octave_value_list& args)
+  {
+    int i = -1;
+
+    for (tree_decl_elt* elt : *param_list)
+      {
+        i++;
+
+        octave_lvalue ref = elt->lvalue (this);
+
+        if (i < args.length ())
+          {
+            if (args(i).is_defined () && args(i).is_magic_colon ())
+              {
+                if (! eval_decl_elt (elt))
+                  error ("no default value for argument %d", i+1);
+              }
+            else
+              ref.define (args(i));
+          }
+        else
+          eval_decl_elt (elt);
+      }
+  }
+
   void
-  tree_evaluator::do_decl_init_list (decl_elt_init_fcn fcn,
-                                     tree_decl_init_list *init_list)
+  tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list)
+  {
+    for (tree_decl_elt* elt : *param_list)
+      {
+        octave_lvalue ref = elt->lvalue (this);
+
+        ref.assign (octave_value::op_asn_eq, octave_value ());
+      }
+  }
+
+  octave_value_list
+  tree_evaluator::convert_parameter_list_to_const_vector
+    (tree_parameter_list *param_list, int nargout, const Cell& varargout)
+  {
+    octave_idx_type vlen = varargout.numel ();
+    int len = param_list->length ();
+
+    // Special case.  Will do a shallow copy.
+    if (len == 0)
+      return varargout;
+    else if (nargout <= len)
+      {
+        octave_value_list retval (nargout);
+
+        int i = 0;
+
+        for (tree_decl_elt* elt : *param_list)
+          {
+            if (elt->is_defined ())
+              retval(i++) = evaluate (elt);
+            else
+              break;
+          }
+
+        return retval;
+      }
+    else
+      {
+        octave_value_list retval (len + vlen);
+
+        int i = 0;
+
+        for (tree_decl_elt* elt : *param_list)
+          retval(i++) = evaluate (elt);
+
+        for (octave_idx_type j = 0; j < vlen; j++)
+          retval(i++) = varargout(j);
+
+        return retval;
+      }
+  }
+
+  bool
+  tree_evaluator::eval_decl_elt (tree_decl_elt *elt)
+  {
+    bool retval = false;
+
+    tree_identifier *id = elt->ident ();
+    tree_expression *expr = elt->expression ();
+
+    if (id && expr)
+      {
+        octave_lvalue ult = id->lvalue (this);
+
+        octave_value init_val = evaluate (expr);
+
+        ult.assign (octave_value::op_asn_eq, init_val);
+
+        retval = true;
+      }
+
+    return retval;
+  }
+
+  bool
+  tree_evaluator::switch_case_label_matches (tree_switch_case *expr,
+                                             const octave_value& val)
   {
-    if (init_list)
+    tree_expression *label = expr->case_label ();
+
+    octave_value label_value = evaluate (label);
+
+    if (label_value.is_defined ())
+      {
+        if (label_value.is_cell ())
+          {
+            Cell cell (label_value.cell_value ());
+
+            for (octave_idx_type i = 0; i < cell.rows (); i++)
+              {
+                for (octave_idx_type j = 0; j < cell.columns (); j++)
+                  {
+                    bool match = val.is_equal (cell(i,j));
+
+                    if (match)
+                      return true;
+                  }
+              }
+          }
+        else
+          return val.is_equal (label_value);
+      }
+
+    return false;
+  }
+
+  void
+  tree_evaluator::do_global_init (octave::tree_decl_elt& elt)
+  {
+    octave::tree_identifier *id = elt.ident ();
+
+    if (id)
       {
-        for (tree_decl_elt* elt : *init_list)
-          fcn (*elt);
+        id->mark_global ();
+
+        octave_lvalue ult = id->lvalue (this);
+
+        if (ult.is_undefined ())
+          {
+            octave::tree_expression *expr = elt.expression ();
+
+            octave_value init_val;
+
+            if (expr)
+              init_val = evaluate (expr);
+            else
+              init_val = Matrix ();
+
+            ult.assign (octave_value::op_asn_eq, init_val);
+          }
+      }
+  }
+
+  void
+  tree_evaluator::do_static_init (octave::tree_decl_elt& elt)
+  {
+    octave::tree_identifier *id = elt.ident ();
+
+    if (id)
+      {
+        id->mark_as_static ();
+
+        octave_lvalue ult = id->lvalue (this);
+
+        if (ult.is_undefined ())
+          {
+            octave::tree_expression *expr = elt.expression ();
+
+            octave_value init_val;
+
+            if (expr)
+              init_val = evaluate (expr);
+            else
+              init_val = Matrix ();
+
+            ult.assign (octave_value::op_asn_eq, init_val);
+          }
       }
   }
 
@@ -209,7 +667,17 @@
     if (debug_mode)
       do_breakpoint (cmd.is_breakpoint (true));
 
-    do_decl_init_list (do_global_init, cmd.initializer_list ());
+    tree_decl_init_list *init_list = cmd.initializer_list ();
+
+    if (init_list)
+      {
+        // If we called init_list->accept (*this), we would need a way
+        // to tell tree_evaluator::visit_decl_init_list that we are
+        // evaluating a global init list.
+
+        for (tree_decl_elt* elt : *init_list)
+          do_global_init (*elt);
+      }
   }
 
   void
@@ -218,7 +686,17 @@
     if (debug_mode)
       do_breakpoint (cmd.is_breakpoint (true));
 
-    do_decl_init_list (do_static_init, cmd.initializer_list ());
+    tree_decl_init_list *init_list = cmd.initializer_list ();
+
+    if (init_list)
+      {
+        // If we called init_list->accept (*this), we would need a way
+        // to tell tree_evaluator::visit_decl_init_list that we are
+        // evaluating a static init list.
+
+        for (tree_decl_elt* elt : *init_list)
+          do_static_init (*elt);
+      }
   }
 
   void
@@ -274,7 +752,7 @@
 
     tree_expression *expr = cmd.control_expr ();
 
-    octave_value rhs = expr->rvalue1 ();
+    octave_value rhs = evaluate (expr);
 
 #if defined (HAVE_LLVM)
     if (tree_jit::execute (cmd, rhs))
@@ -286,7 +764,7 @@
 
     tree_expression *lhs = cmd.left_hand_side ();
 
-    octave_lvalue ult = lhs->lvalue ();
+    octave_lvalue ult = lhs->lvalue (this);
 
     tree_statement_list *loop_body = cmd.body ();
 
@@ -386,7 +864,7 @@
 
     tree_expression *expr = cmd.control_expr ();
 
-    octave_value rhs = expr->rvalue1 ();
+    octave_value rhs = evaluate (expr);
 
     if (rhs.is_undefined ())
       return;
@@ -404,11 +882,11 @@
 
     tree_expression *elt = *p++;
 
-    octave_lvalue val_ref = elt->lvalue ();
+    octave_lvalue val_ref = elt->lvalue (this);
 
     elt = *p;
 
-    octave_lvalue key_ref = elt->lvalue ();
+    octave_lvalue key_ref = elt->lvalue (this);
 
     const octave_map tmp_val = rhs.map_value ();
 
@@ -442,12 +920,14 @@
   void
   tree_evaluator::visit_octave_user_script (octave_user_script&)
   {
+    // ??
     panic_impossible ();
   }
 
   void
   tree_evaluator::visit_octave_user_function (octave_user_function&)
   {
+    // ??
     panic_impossible ();
   }
 
@@ -484,9 +964,65 @@
   }
 
   void
-  tree_evaluator::visit_identifier (tree_identifier&)
+  tree_evaluator::visit_identifier (tree_identifier& expr)
   {
-    panic_impossible ();
+    octave_value_list retval;
+
+    symbol_table::symbol_reference sym = expr.symbol ();
+
+    octave_value val = sym->find ();
+
+    if (val.is_defined ())
+      {
+        // GAGME -- this would be cleaner if we required
+        // parens to indicate function calls.
+        //
+        // If this identifier refers to a function, we need to know
+        // whether it is indexed so that we can do the same thing
+        // for 'f' and 'f()'.  If the index is present and the function
+        // object declares it can handle it, return the function object
+        // and let tree_index_expression::rvalue handle indexing.
+        // Otherwise, arrange to call the function here, so that we don't
+        // return the function definition as a value.
+
+        octave_function *fcn = 0;
+
+        if (val.is_function ())
+          fcn = val.function_value (true);
+
+        int nargout = m_nargout_stack.top ();
+
+        if (fcn && ! (expr.is_postfix_indexed ()
+                      && fcn->is_postfix_index_handled (expr.postfix_index ())))
+          {
+            octave_value_list tmp_args;
+
+            const std::list<octave_lvalue> *lvalue_list
+              = m_lvalue_list_stack.top ();
+
+            retval = (lvalue_list
+                      ? val.do_multi_index_op (nargout, tmp_args, lvalue_list)
+                      : val.do_multi_index_op (nargout, tmp_args));
+          }
+        else
+          {
+            if (expr.print_result () && nargout == 0
+                && octave::tree_evaluator::statement_printing_enabled ())
+              {
+                octave_value_list args = ovl (val);
+                args.stash_name_tags (string_vector (expr.name ()));
+                octave::feval ("display", args);
+              }
+
+            retval = val;
+          }
+      }
+    else if (sym->is_added_static ())
+      expr.static_workspace_error ();
+    else
+      expr.eval_undefined_error ();
+
+    m_value_stack.push (retval);
   }
 
   void
@@ -517,7 +1053,7 @@
         if (debug_mode && ! tic->is_else_clause ())
           do_breakpoint (tic->is_breakpoint (true));
 
-        if (tic->is_else_clause () || expr->is_logically_true ("if"))
+        if (tic->is_else_clause () || is_logically_true (expr, "if"))
           {
             tree_statement_list *stmt_lst = tic->commands ();
 
@@ -528,29 +1064,657 @@
           }
       }
   }
-
+}
+
+static inline octave_value_list
+make_value_list (octave::tree_evaluator *tw, octave::tree_argument_list *args,
+                 const string_vector& arg_nm,
+                 const octave_value *object, bool rvalue = true)
+{
+  octave_value_list retval;
+
+  if (args)
+    {
+      if (rvalue && object && args->has_magic_end () && object->is_undefined ())
+        err_invalid_inquiry_subscript ();
+
+      retval = args->convert_to_const_vector (tw, object);
+    }
+
+  octave_idx_type n = retval.length ();
+
+  if (n > 0)
+    retval.stash_name_tags (arg_nm);
+
+  return retval;
+}
+
+// Final step of processing an indexing error.  Add the name of the
+// variable being indexed, if any, then issue an error.  (Will this also
+// be needed by pt-lvalue, which calls subsref?)
+
+static void
+final_index_error (octave::index_exception& e,
+                   const octave::tree_expression *expr)
+{
+  std::string extra_message;
+
+  if (expr->is_identifier ()
+      && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable ())
+    {
+      std::string var = expr->name ();
+
+      e.set_var (var);
+
+      octave_value fcn = symbol_table::find_function (var);
+
+      if (fcn.is_function ())
+        {
+          octave_function *fp = fcn.function_value ();
+
+          if (fp && fp->name () == var)
+            extra_message = " (note: variable '" + var + "' shadows function)";
+        }
+    }
+
+  std::string msg = e.message () + extra_message;
+
+  error_with_id (e.err_id (), msg.c_str ());
+}
+
+namespace octave
+{
   void
-  tree_evaluator::visit_index_expression (tree_index_expression&)
+  tree_evaluator::visit_index_expression (tree_index_expression& idx_expr)
+  {
+    octave_value_list retval;
+
+    int nargout = m_nargout_stack.top ();
+    
+    octave_value first_expr_val;
+
+    octave_value_list first_args;
+
+    bool have_args = false;
+
+    tree_expression *expr = idx_expr.expression ();
+    std::list<tree_argument_list *> args = idx_expr.arg_lists ();
+    std::string type = idx_expr.type_tags ();
+    std::list<string_vector> arg_nm = idx_expr.arg_names ();
+    std::list<tree_expression *> dyn_field = idx_expr.dyn_fields ();
+
+    if (expr->is_identifier () && type[0] == '(')
+      {
+        tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
+
+        if (! (id->is_variable () || args.empty ()))
+          {
+            tree_argument_list *al = *(args.begin ());
+
+            size_t n = al ? al->length () : 0;
+
+            if (n > 0)
+              {
+                string_vector anm = *(arg_nm.begin ());
+                have_args = true;
+                first_args = al -> convert_to_const_vector (this);
+                first_args.stash_name_tags (anm);
+
+                first_expr_val = id->do_lookup  (first_args);
+              }
+          }
+      }
+
+    if (first_expr_val.is_undefined ())
+      first_expr_val = evaluate (expr);
+
+    octave_value tmp = first_expr_val;
+    octave_idx_type tmpi = 0;
+
+    std::list<octave_value_list> idx;
+
+    int n = args.size ();
+
+    std::list<tree_argument_list *>::iterator p_args = args.begin ();
+    std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
+    std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
+
+    for (int i = 0; i < n; i++)
+      {
+        if (i > 0)
+          {
+            tree_argument_list *al = *p_args;
+
+            // In Matlab, () can only be followed by '.'.  In Octave, we
+            // do not enforce this for rvalue expressions, but we'll
+            // split the evaluation at this point.  This will,
+            // hopefully, allow Octave's looser rules apply smoothly for
+            // Matlab overloaded subsref codes.
+
+            // We might have an expression like
+            //
+            //   x{end}.a(end)
+            //
+            // and we are looking at the argument list that contains the
+            // second (or third, etc.) "end" token, so we must evaluate
+            // everything up to the point of that argument list so we
+            // can pass the appropriate value to the built-in end
+            // function.
+
+            // An expression like
+            //
+            //    s.a (f (1:end))
+            //
+            // can mean a lot of different things depending on the types
+            // of s, a, and f.  Let's just say it's complicated and that
+            // the following code is definitely not correct in all
+            // cases.  That it is already so complex makes me think that
+            // there must be a better way.
+
+            bool split = ((type[i-1] == '(' && type[i] != '.')
+                          || (al && al->has_magic_end ()
+                              && ! tmp.is_classdef_object ()));
+
+            if (split)
+              {
+                try
+                  {
+                    octave_value_list tmp_list
+                      =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout);
+
+                    tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
+                    tmpi = i;
+                    idx.clear ();
+
+                    if (tmp.is_cs_list ())
+                      err_indexed_cs_list ();
+
+                    if (tmp.is_function ())
+                      {
+                        octave_function *fcn = tmp.function_value (true);
+
+                        if (fcn && ! fcn->is_postfix_index_handled (type[i]))
+                          {
+                            octave_value_list empty_args;
+
+                            tmp_list = tmp.do_multi_index_op (1, empty_args);
+                            tmp = (tmp_list.length ()
+                                   ? tmp_list(0) : octave_value ());
+
+                            if (tmp.is_cs_list ())
+                              err_indexed_cs_list ();
+                          }
+                      }
+                  }
+                catch (octave::index_exception& e)  // problems with index range, type etc.
+                  {
+                    final_index_error (e, expr);
+                  }
+              }
+          }
+
+        switch (type[i])
+          {
+          case '(':
+            if (have_args)
+              {
+                idx.push_back (first_args);
+                have_args = false;
+              }
+            else
+              idx.push_back (make_value_list (this, *p_args, *p_arg_nm, &tmp));
+            break;
+
+          case '{':
+            idx.push_back (make_value_list (this, *p_args, *p_arg_nm, &tmp));
+            break;
+
+          case '.':
+            idx.push_back (octave_value
+                           (idx_expr.get_struct_index (this, p_arg_nm, p_dyn_field)));
+            break;
+
+          default:
+            panic_impossible ();
+          }
+
+        p_args++;
+        p_arg_nm++;
+        p_dyn_field++;
+      }
+
+    const std::list<octave_lvalue> *lvalue_list = m_lvalue_list_stack.top ();
+
+    try
+      {
+        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
+                              lvalue_list);
+      }
+    catch (octave::index_exception& e)  // range problems, bad index type, etc.
+      {
+        final_index_error (e, expr);
+      }
+
+    octave_value val = retval.length () ? retval(0) : octave_value ();
+
+    if (val.is_function ())
+      {
+        octave_function *fcn = val.function_value (true);
+
+        if (fcn)
+          {
+            octave_value_list empty_args;
+
+            retval = (lvalue_list
+                      ? val.do_multi_index_op (nargout, empty_args,
+                                               lvalue_list)
+                      : val.do_multi_index_op (nargout, empty_args));
+          }
+      }
+
+    m_value_stack.push (retval);
+  }
+  
+  void
+  tree_evaluator::visit_matrix (tree_matrix& expr)
   {
-    panic_impossible ();
+    octave_value retval = Matrix ();
+
+    bool all_strings_p = false;
+    bool all_sq_strings_p = false;
+    bool all_dq_strings_p = false;
+    bool all_empty_p = false;
+    bool all_real_p = false;
+    bool any_sparse_p = false;
+    bool any_class_p = false;
+    bool frc_str_conv = false;
+
+    tm_const tmp (expr, this);
+
+    if (tmp && ! tmp.empty ())
+      {
+        dim_vector dv = tmp.dims ();
+        all_strings_p = tmp.all_strings_p ();
+        all_sq_strings_p = tmp.all_sq_strings_p ();
+        all_dq_strings_p = tmp.all_dq_strings_p ();
+        all_empty_p = tmp.all_empty_p ();
+        all_real_p = tmp.all_real_p ();
+        any_sparse_p = tmp.any_sparse_p ();
+        any_class_p = tmp.any_class_p ();
+        frc_str_conv = tmp.some_strings_p ();
+
+        // Try to speed up the common cases.
+
+        std::string result_type = tmp.class_name ();
+
+        if (any_class_p)
+          {
+            retval = do_class_concat (tmp);
+          }
+        else if (result_type == "double")
+          {
+            if (any_sparse_p)
+              {
+                if (all_real_p)
+                  retval = do_single_type_concat<SparseMatrix> (dv, tmp);
+                else
+                  retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp);
+              }
+            else
+              {
+                if (all_real_p)
+                  retval = do_single_type_concat<NDArray> (dv, tmp);
+                else
+                  retval = do_single_type_concat<ComplexNDArray> (dv, tmp);
+              }
+          }
+        else if (result_type == "single")
+          {
+            if (all_real_p)
+              retval = do_single_type_concat<FloatNDArray> (dv, tmp);
+            else
+              retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp);
+          }
+        else if (result_type == "char")
+          {
+            char type = all_dq_strings_p ? '"' : '\'';
+
+            if (! all_strings_p)
+              warn_implicit_conversion ("Octave:num-to-str",
+                                        "numeric", result_type);
+            else
+              maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p);
+
+            charNDArray result (dv, Vstring_fill_char);
+
+            single_type_concat<charNDArray> (result, tmp);
+
+            retval = octave_value (result, type);
+          }
+        else if (result_type == "logical")
+          {
+            if (any_sparse_p)
+              retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp);
+            else
+              retval = do_single_type_concat<boolNDArray> (dv, tmp);
+          }
+        else if (result_type == "int8")
+          retval = do_single_type_concat<int8NDArray> (dv, tmp);
+        else if (result_type == "int16")
+          retval = do_single_type_concat<int16NDArray> (dv, tmp);
+        else if (result_type == "int32")
+          retval = do_single_type_concat<int32NDArray> (dv, tmp);
+        else if (result_type == "int64")
+          retval = do_single_type_concat<int64NDArray> (dv, tmp);
+        else if (result_type == "uint8")
+          retval = do_single_type_concat<uint8NDArray> (dv, tmp);
+        else if (result_type == "uint16")
+          retval = do_single_type_concat<uint16NDArray> (dv, tmp);
+        else if (result_type == "uint32")
+          retval = do_single_type_concat<uint32NDArray> (dv, tmp);
+        else if (result_type == "uint64")
+          retval = do_single_type_concat<uint64NDArray> (dv, tmp);
+        else if (result_type == "cell")
+          retval = do_single_type_concat<Cell> (dv, tmp);
+        else if (result_type == "struct")
+          retval = do_single_type_concat<octave_map> (dv, tmp);
+        else
+          {
+            // The line below might seem crazy, since we take a copy of
+            // the first argument, resize it to be empty and then resize
+            // it to be full.  This is done since it means that there is
+            // no recopying of data, as would happen if we used a single
+            // resize.  It should be noted that resize operation is also
+            // significantly slower than the do_cat_op function, so it
+            // makes sense to have an empty matrix and copy all data.
+            //
+            // We might also start with a empty octave_value using
+            //
+            //    ctmp = octave_value_typeinfo::lookup_type
+            //          (tmp.begin() -> begin() -> type_name());
+            //
+            // and then directly resize.  However, for some types there
+            // might be some additional setup needed, and so this should
+            // be avoided.
+
+            octave_value ctmp;
+
+            // Find the first non-empty object
+
+            if (any_sparse_p)
+              {
+                // Start with sparse matrix to avoid issues memory issues
+                // with things like [ones(1,4),sprandn(1e8,4,1e-4)]
+                if (all_real_p)
+                  ctmp = octave_sparse_matrix ().resize (dv);
+                else
+                  ctmp = octave_sparse_complex_matrix ().resize (dv);
+              }
+            else
+              {
+                for (tm_row_const& row : tmp)
+                  {
+                    octave_quit ();
+
+                    for (auto& elt : row)
+                      {
+                        octave_quit ();
+
+                        ctmp = elt;
+
+                        if (! ctmp.all_zero_dims ())
+                          goto found_non_empty;
+                      }
+                  }
+
+                ctmp = (*(tmp.begin () -> begin ()));
+
+              found_non_empty:
+
+                if (! all_empty_p)
+                  ctmp = ctmp.resize (dim_vector (0,0)).resize (dv);
+              }
+
+            // Now, extract the values from the individual elements and
+            // insert them in the result matrix.
+
+            int dv_len = dv.ndims ();
+            octave_idx_type ntmp = dv_len > 1 ? dv_len : 2;
+            Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
+
+            for (tm_row_const& row : tmp)
+              {
+                octave_quit ();
+
+                for (auto& elt : row)
+                  {
+                    octave_quit ();
+
+                    if (elt.is_empty ())
+                      continue;
+
+                    ctmp = do_cat_op (ctmp, elt, ra_idx);
+
+                    ra_idx (1) += elt.columns ();
+                  }
+
+                ra_idx (0) += row.rows ();
+                ra_idx (1) = 0;
+              }
+
+            retval = ctmp;
+
+            if (frc_str_conv && ! retval.is_string ())
+              retval = retval.convert_to_str ();
+          }
+      }
+
+    m_value_stack.push (retval);
   }
 
   void
-  tree_evaluator::visit_matrix (tree_matrix&)
+  tree_evaluator::visit_cell (tree_cell& expr)
   {
-    panic_impossible ();
+    octave_value retval;
+
+    octave_idx_type nr = expr.length ();
+    octave_idx_type nc = -1;
+
+    Cell val;
+
+    octave_idx_type i = 0;
+
+    for (tree_argument_list* elt : expr)
+      {
+        octave_value_list row = elt->convert_to_const_vector (this);
+
+        if (nr == 1)
+          // Optimize the single row case.
+          val = row.cell_value ();
+        else if (nc < 0)
+          {
+            nc = row.length ();
+
+            val = Cell (nr, nc);
+          }
+        else
+          {
+            octave_idx_type this_nc = row.length ();
+
+            if (this_nc != nc)
+              {
+                if (this_nc == 0)
+                  continue;  // blank line
+                else
+                  error ("number of columns must match");
+              }
+          }
+
+        for (octave_idx_type j = 0; j < nc; j++)
+          val(i,j) = row(j);
+
+        i++;
+      }
+
+    if (i < nr)
+      val.resize (dim_vector (i, nc));  // there were blank rows
+
+    retval = val;
+
+    m_value_stack.push (retval);
   }
 
   void
-  tree_evaluator::visit_cell (tree_cell&)
+  tree_evaluator::visit_multi_assignment (tree_multi_assignment& expr)
   {
-    panic_impossible ();
-  }
-
-  void
-  tree_evaluator::visit_multi_assignment (tree_multi_assignment&)
-  {
-    panic_impossible ();
+    octave_value_list val;
+
+    tree_expression *rhs = expr.right_hand_side ();
+
+    if (rhs)
+      {
+        tree_argument_list *lhs = expr.left_hand_side ();
+
+        std::list<octave_lvalue> lvalue_list = lhs->lvalue_list (this);
+
+        octave_idx_type n_out = 0;
+
+        for (const auto& lval : lvalue_list)
+          n_out += lval.numel ();
+
+        // The following trick is used to keep rhs_val constant.
+        const octave_value_list rhs_val1 = evaluate_n (rhs, n_out, &lvalue_list);
+        const octave_value_list rhs_val = (rhs_val1.length () == 1
+                                           && rhs_val1(0).is_cs_list ()
+                                           ? rhs_val1(0).list_value ()
+                                           : rhs_val1);
+
+        octave_idx_type k = 0;
+
+        octave_idx_type n = rhs_val.length ();
+
+        // To avoid copying per elements and possible optimizations, we
+        // postpone joining the final values.
+        std::list<octave_value_list> retval_list;
+
+        tree_argument_list::iterator q = lhs->begin ();
+
+        for (octave_lvalue ult : lvalue_list)
+          {
+            tree_expression *lhs_elt = *q++;
+
+            octave_idx_type nel = ult.numel ();
+
+            if (nel != 1)
+              {
+                // Huge kluge so that wrapper scripts with lines like
+                //
+                //   [varargout{1:nargout}] = fcn (args);
+                //
+                // Will work the same as calling fcn directly when nargout
+                // is 0 and fcn produces more than one output even when
+                // nargout is 0.  This only works if varargout has not yet
+                // been defined.  See also bug #43813.
+
+                if (lvalue_list.size () == 1 && nel == 0 && n > 0
+                    && ! ult.is_black_hole () && ult.is_undefined ()
+                    && ult.index_type () == "{" && ult.index_is_empty ())
+                  {
+                    // Convert undefined lvalue with empty index to a cell
+                    // array with a single value and indexed by 1 to
+                    // handle a single output.
+
+                    nel = 1;
+
+                    ult.define (Cell (1, 1));
+
+                    ult.clear_index ();
+                    std::list<octave_value_list> idx;
+                    idx.push_back (octave_value_list (octave_value (1)));
+                    ult.set_index ("{", idx);
+                  }
+
+                if (k + nel > n)
+                  error ("some elements undefined in return list");
+
+                // This element of the return list expects a
+                // comma-separated list of values.  Slicing avoids
+                // copying.
+
+                octave_value_list ovl = rhs_val.slice (k, nel);
+
+                ult.assign (octave_value::op_asn_eq, octave_value (ovl));
+
+                retval_list.push_back (ovl);
+
+                k += nel;
+              }
+            else
+              {
+                if (k < n)
+                  {
+                    ult.assign (octave_value::op_asn_eq, rhs_val(k));
+
+                    if (ult.is_black_hole ())
+                      {
+                        k++;
+                        continue;
+                      }
+                    else
+                      {
+                        retval_list.push_back (rhs_val(k));
+
+                        k++;
+                      }
+                  }
+                else
+                  {
+                    // This can happen for a function like
+                    //
+                    //   function varargout = f ()
+                    //     varargout{1} = nargout;
+                    //   endfunction
+                    //
+                    // called with
+                    //
+                    //    [a, ~] = f ();
+                    //
+                    // Then the list of of RHS values will contain one
+                    // element but we are iterating over the list of all
+                    // RHS values.  We shouldn't complain that a value we
+                    // don't need is missing from the list.
+
+                    if (! ult.is_black_hole ())
+                      error ("element number %d undefined in return list", k+1);
+
+                    k++;
+                    continue;
+                  }
+              }
+
+            if (expr.print_result ()
+                && octave::tree_evaluator::statement_printing_enabled ())
+              {
+                // We clear any index here so that we can get
+                // the new value of the referenced object below,
+                // instead of the indexed value (which should be
+                // the same as the right hand side value).
+
+                ult.clear_index ();
+
+                octave_value lhs_val = ult.value ();
+
+                octave_value_list args = ovl (lhs_val);
+                args.stash_name_tags (string_vector (lhs_elt->name ()));
+                octave::feval ("display", args);
+              }
+          }
+
+        // Concatenate return values.
+        val = retval_list;
+      }
+
+    m_value_stack.push (val);
   }
 
   void
@@ -561,21 +1725,58 @@
   }
 
   void
-  tree_evaluator::visit_constant (tree_constant&)
+  tree_evaluator::visit_constant (tree_constant& expr)
   {
-    panic_impossible ();
+    int nargout = m_nargout_stack.top ();
+
+    if (nargout > 1)
+      error ("invalid number of output arguments for constant expression");
+
+    m_value_stack.push (ovl (expr.value ()));
+  }
+
+  void
+  tree_evaluator::visit_fcn_handle (tree_fcn_handle& expr)
+  {
+    std::string nm = expr.name ();
+
+    octave_value fh = make_fcn_handle (nm);
+
+    m_value_stack.push (ovl (fh));
   }
 
   void
-  tree_evaluator::visit_fcn_handle (tree_fcn_handle&)
+  tree_evaluator::visit_funcall (tree_funcall& expr)
   {
-    panic_impossible ();
-  }
-
-  void
-  tree_evaluator::visit_funcall (tree_funcall&)
-  {
-    panic_impossible ();
+    octave_value_list retval;
+
+    octave_value fcn = expr.function ();
+
+    octave_value_list args = expr.arguments ();
+
+    int nargout = m_nargout_stack.top ();
+
+    retval = octave::feval (fcn.function_value (), args, nargout);
+
+    if (retval.length () == 1 && retval(0).is_function ())
+      {
+        // The return object is a function.  We may need to re-index it
+        // using the same logic as for identifier.  This is primarily
+        // used for superclass references in classdef.
+
+        octave_value val = retval(0);
+        octave_function *f = val.function_value (true);
+
+        if (f && ! (expr.is_postfix_indexed ()
+                    && f->is_postfix_index_handled (expr.postfix_index ())))
+          {
+            octave_value_list tmp_args;
+
+            retval = val.do_multi_index_op (nargout, tmp_args);
+          }
+      }
+
+    m_value_stack.push (retval);
   }
 
   void
@@ -585,15 +1786,86 @@
   }
 
   void
-  tree_evaluator::visit_postfix_expression (tree_postfix_expression&)
+  tree_evaluator::visit_postfix_expression (tree_postfix_expression& expr)
   {
-    panic_impossible ();
+    octave_value val;
+
+    tree_expression *op = expr.operand ();
+
+    if (op)
+      {
+        octave_value::unary_op etype = expr.op_type ();
+
+        if (etype == octave_value::op_incr || etype == octave_value::op_decr)
+          {
+            octave_lvalue ref = op->lvalue (this);
+
+            val = ref.value ();
+
+            profile_data_accumulator::enter<tree_postfix_expression>
+              block (profiler, expr);
+
+            ref.do_unary_op (etype);
+          }
+        else
+          {
+            octave_value op_val = evaluate (op);
+
+            if (op_val.is_defined ())
+              {
+                profile_data_accumulator::enter<tree_postfix_expression>
+                  block (profiler, expr);
+
+                val = ::do_unary_op (etype, op_val);
+              }
+          }
+      }
+
+    m_value_stack.push (ovl (val));
   }
 
   void
-  tree_evaluator::visit_prefix_expression (tree_prefix_expression&)
+  tree_evaluator::visit_prefix_expression (tree_prefix_expression& expr)
   {
-    panic_impossible ();
+    octave_value val;
+
+    tree_expression *op = expr.operand ();
+
+    if (op)
+      {
+        octave_value::unary_op etype = expr.op_type ();
+
+        if (etype == octave_value::op_incr || etype == octave_value::op_decr)
+          {
+            octave_lvalue op_ref = op->lvalue (this);
+
+            profile_data_accumulator::enter<tree_prefix_expression>
+              block (profiler, expr);
+
+            op_ref.do_unary_op (etype);
+
+            val = op_ref.value ();
+          }
+        else
+          {
+            octave_value op_val = evaluate (op);
+
+            if (op_val.is_defined ())
+              {
+                profile_data_accumulator::enter<tree_prefix_expression>
+                  block (profiler, expr);
+
+                // Attempt to do the operation in-place if it is unshared
+                // (a temporary expression).
+                if (op_val.get_count () == 1)
+                  val = op_val.do_non_const_unary_op (etype);
+                else
+                  val = ::do_unary_op (etype, op_val);
+              }
+          }
+      }
+
+    m_value_stack.push (ovl (val));
   }
 
   void
@@ -623,9 +1895,74 @@
   }
 
   void
-  tree_evaluator::visit_simple_assignment (tree_simple_assignment&)
+  tree_evaluator::visit_simple_assignment (tree_simple_assignment& expr)
   {
-    panic_impossible ();
+    octave_value val;
+
+    tree_expression *rhs = expr.right_hand_side ();
+
+    if (rhs)
+      {
+        octave_value rhs_val = evaluate (rhs);
+
+        if (rhs_val.is_undefined ())
+          error ("value on right hand side of assignment is undefined");
+
+        if (rhs_val.is_cs_list ())
+          {
+            const octave_value_list lst = rhs_val.list_value ();
+
+            if (lst.empty ())
+              error ("invalid number of elements on RHS of assignment");
+
+            rhs_val = lst(0);
+          }
+
+        tree_expression *lhs = expr.left_hand_side ();
+
+        try
+          {
+            octave_lvalue ult = lhs->lvalue (this);
+
+            if (ult.numel () != 1)
+              err_nonbraced_cs_list_assignment ();
+
+            octave_value::assign_op etype = expr.op_type ();
+
+            ult.assign (etype, rhs_val);
+
+            if (etype == octave_value::op_asn_eq)
+              val = rhs_val;
+            else
+              val = ult.value ();
+
+            if (expr.print_result ()
+                && octave::tree_evaluator::statement_printing_enabled ())
+              {
+                // We clear any index here so that we can
+                // get the new value of the referenced
+                // object below, instead of the indexed
+                // value (which should be the same as the
+                // right hand side value).
+
+                ult.clear_index ();
+
+                octave_value lhs_val = ult.value ();
+
+                octave_value_list args = ovl (lhs_val);
+                args.stash_name_tags (string_vector (lhs->name ()));
+                octave::feval ("display", args);
+              }
+          }
+        catch (octave::index_exception& e)
+          {
+            e.set_var (lhs->name ());
+            std::string msg = e.message ();
+            error_with_id (e.err_id (), msg.c_str ());
+          }
+      }
+
+    m_value_stack.push (ovl (val));
   }
 
   void
@@ -668,7 +2005,7 @@
                 // printing the result.
 
                 // FIXME: it seems that we should just have to
-                // call expr->rvalue1 () and that should take care of
+                // evaluate the expression and that should take care of
                 // everything, binding ans as necessary?
 
                 bool do_bind_ans = false;
@@ -682,7 +2019,7 @@
                 else
                   do_bind_ans = (! expr->is_assignment_expression ());
 
-                octave_value tmp_result = expr->rvalue1 (0);
+                octave_value tmp_result = evaluate (expr, 0);
 
                 if (do_bind_ans && tmp_result.is_defined ())
                   bind_ans (tmp_result, expr->print_result ()
@@ -780,7 +2117,7 @@
       error ("missing value in switch command near line %d, column %d",
              cmd.line (), cmd.column ());
 
-    octave_value val = expr->rvalue1 ();
+    octave_value val = evaluate (expr);
 
     tree_switch_case_list *lst = cmd.case_list ();
 
@@ -788,7 +2125,7 @@
       {
         for (tree_switch_case* t : *lst)
           {
-            if (t->is_default_case () || t->label_matches (val))
+            if (t->is_default_case () || switch_case_label_matches (t, val))
               {
                 tree_statement_list *stmt_lst = t->commands ();
 
@@ -854,7 +2191,7 @@
 
             if (expr_id)
               {
-                ult = expr_id->lvalue ();
+                ult = expr_id->lvalue (this);
 
                 octave_scalar_map err;
 
@@ -1010,7 +2347,7 @@
         if (debug_mode)
           do_breakpoint (cmd.is_breakpoint (true));
 
-        if (expr->is_logically_true ("while"))
+        if (is_logically_true (expr, "while"))
           {
             tree_statement_list *loop_body = cmd.body ();
 
@@ -1061,7 +2398,7 @@
 
         octave::call_stack::set_location (until_line, until_column);
 
-        if (expr->is_logically_true ("do-until"))
+        if (is_logically_true (expr, "do-until"))
           break;
       }
   }
@@ -1167,6 +2504,22 @@
   {
     return ::do_keyboard (args);
   }
+
+  bool
+  tree_evaluator::is_logically_true (tree_expression *expr,
+                                     const char *warn_for)
+  {
+    bool expr_value = false;
+
+    octave_value t1 = evaluate (expr);
+
+    if (t1.is_defined ())
+      return t1.is_true ();
+    else
+      error ("%s: undefined value used in conditional expression", warn_for);
+
+    return expr_value;
+  }
 }
 
 DEFUN (max_recursion_depth, args, nargout,
--- a/libinterp/parse-tree/pt-eval.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-eval.h	Fri Apr 21 18:07:40 2017 -0400
@@ -25,15 +25,18 @@
 
 #include "octave-config.h"
 
+#include <list>
 #include <stack>
 #include <string>
 
 #include "comment-list.h"
 #include "ovl.h"
+#include "pt-exp.h"
 #include "pt-walk.h"
 
 namespace octave
 {
+  class tree_decl_elt;
   class tree_expression;
 
   class interpreter;
@@ -44,11 +47,50 @@
   {
   public:
 
+    template <typename T>
+    class value_stack
+    {
+    public:
+
+      value_stack (void) = default;
+
+      value_stack (const value_stack&) = default;
+
+      value_stack& operator = (const value_stack&) = default;
+
+      ~value_stack (void) = default;
+
+      void push (const T& val) { m_stack.push (val); }
+
+      T pop (void)
+      {
+        T retval = m_stack.top ();
+        m_stack.pop ();
+        return retval;
+      }
+
+      T top (void) const
+      {
+        return m_stack.top ();
+      }
+
+      void clear (void)
+      {
+        while (! m_stack.empty ())
+          m_stack.pop ();
+      }
+      
+    private:
+
+      std::stack<T> m_stack;
+    };
+
     typedef void (*decl_elt_init_fcn) (tree_decl_elt&);
 
     tree_evaluator (interpreter *interp_context)
-      : m_interp_context (interp_context)
-      { }
+      : m_value_stack (), m_lvalue_list_stack (), m_nargout_stack (),
+        m_interp_context (interp_context)
+    { }
 
     // No copying!
 
@@ -58,12 +100,18 @@
 
     ~tree_evaluator (void) = default;
 
+    void reset (void);
+
     void visit_anon_fcn_handle (tree_anon_fcn_handle&);
 
     void visit_argument_list (tree_argument_list&);
 
     void visit_binary_expression (tree_binary_expression&);
 
+    void visit_boolean_expression (tree_boolean_expression&);
+
+    void visit_compound_binary_expression (tree_compound_binary_expression&);
+
     void visit_break_command (tree_break_command&);
 
     void visit_colon_expression (tree_colon_expression&);
@@ -179,10 +227,63 @@
     // TRUE means we are evaluating some kind of looping construct.
     static bool in_loop_command;
 
+    octave_value evaluate (tree_expression *expr, int nargout = 1,
+                           const std::list<octave_lvalue> *lvalue_list = 0)
+    {
+      m_nargout_stack.push (nargout);
+      m_lvalue_list_stack.push (lvalue_list);
+
+      expr->accept (*this);
+
+      m_nargout_stack.pop ();
+      m_lvalue_list_stack.pop ();
+
+      octave_value_list tmp = m_value_stack.pop ();
+
+      return tmp.empty () ? octave_value () : tmp(0);
+    }
+
+    octave_value_list
+    evaluate_n (tree_expression *expr, int nargout = 1,
+                const std::list<octave_lvalue> *lvalue_list = 0)
+    {
+      m_nargout_stack.push (nargout);
+      m_lvalue_list_stack.push (lvalue_list);
+
+      expr->accept (*this);
+
+      m_nargout_stack.pop ();
+      m_lvalue_list_stack.pop ();
+
+      return m_value_stack.pop ();
+    }
+
+    octave_value evaluate (tree_decl_elt *);
+
+    void
+    initialize_undefined_parameter_list_elements
+      (tree_parameter_list *param_list, const std::string& warnfor,
+       int nargout, const octave_value& val);
+
+    void define_parameter_list_from_arg_vector
+      (tree_parameter_list *param_list, const octave_value_list& args);
+
+    void undefine_parameter_list (tree_parameter_list *param_list);
+
+    octave_value_list
+    convert_parameter_list_to_const_vector
+      (tree_parameter_list *param_list, int nargout, const Cell& varargout);
+
+    bool eval_decl_elt (tree_decl_elt *elt);
+
+    bool switch_case_label_matches (tree_switch_case *expr,
+                                    const octave_value& val);
+
   private:
 
-    void do_decl_init_list (decl_elt_init_fcn fcn,
-                            tree_decl_init_list *init_list);
+    void do_global_init (octave::tree_decl_elt& elt);
+
+    void do_static_init (octave::tree_decl_elt& elt);
 
     void do_breakpoint (tree_statement& stmt) const;
 
@@ -190,7 +291,15 @@
                         bool is_end_of_fcn_or_script = false) const;
 
     virtual octave_value
-      do_keyboard (const octave_value_list& args = octave_value_list ()) const;
+    do_keyboard (const octave_value_list& args = octave_value_list ()) const;
+
+    bool is_logically_true (tree_expression *expr, const char *warn_for);
+
+    value_stack<octave_value_list> m_value_stack;
+
+    value_stack<const std::list<octave_lvalue>*> m_lvalue_list_stack;
+
+    value_stack<int> m_nargout_stack;
 
     interpreter *m_interp_context;
   };
--- a/libinterp/parse-tree/pt-except.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-except.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -68,12 +68,6 @@
                               line (), column ());
   }
 
-  void
-  tree_try_catch_command::accept (tree_walker& tw)
-  {
-    tw.visit_try_catch_command (*this);
-  }
-
   // Simple exception handling.
 
   tree_unwind_protect_command::~tree_unwind_protect_command (void)
@@ -97,10 +91,4 @@
        trail_comm ? trail_comm->dup () : 0,
        line (), column ());
   }
-
-  void
-  tree_unwind_protect_command::accept (tree_walker& tw)
-  {
-    tw.visit_unwind_protect_command (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-except.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-except.h	Fri Apr 21 18:07:40 2017 -0400
@@ -28,14 +28,13 @@
 #include "comment-list.h"
 #include "pt-cmd.h"
 #include "pt-id.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
   class tree_statement_list;
 
-  class tree_walker;
-
   // Simple exception handling.
 
   class tree_try_catch_command : public tree_command
@@ -78,7 +77,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_try_catch_command (*this);
+    }
 
   private:
 
@@ -142,7 +144,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_unwind_protect_command (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-exp.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-exp.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -37,41 +37,8 @@
 {
   // Expressions.
 
-  bool
-  tree_expression::is_logically_true (const char *warn_for)
-  {
-    bool expr_value = false;
-
-    octave_value t1 = rvalue1 ();
-
-    if (t1.is_defined ())
-      return t1.is_true ();
-    else
-      error ("%s: undefined value used in conditional expression", warn_for);
-
-    return expr_value;
-  }
-
-  octave_value
-  tree_expression::rvalue1 (int)
-  {
-    error ("invalid rvalue function called in expression");
-  }
-
-  octave_value_list
-  tree_expression::rvalue (int)
-  {
-    error ("invalid rvalue function called in expression");
-  }
-
-  octave_value_list
-  tree_expression::rvalue (int nargout, const std::list<octave_lvalue> *)
-  {
-    return rvalue (nargout);
-  }
-
   octave_lvalue
-  tree_expression::lvalue (void)
+  tree_expression::lvalue (tree_evaluator *)
   {
     error ("invalid lvalue function called in expression");
   }
--- a/libinterp/parse-tree/pt-exp.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-exp.h	Fri Apr 21 18:07:40 2017 -0400
@@ -36,6 +36,8 @@
 
 namespace octave
 {
+  class tree_evaluator;
+
   // A base class for expressions.
 
   class tree_expression : public tree
@@ -79,20 +81,11 @@
 
     virtual bool is_boolean_expression (void) const { return false; }
 
-    virtual bool is_logically_true (const char *);
-
     virtual bool lvalue_ok (void) const { return false; }
 
     virtual bool rvalue_ok (void) const { return false; }
 
-    virtual octave_value rvalue1 (int nargout = 1);
-
-    virtual octave_value_list rvalue (int nargout);
-
-    virtual octave_value_list
-    rvalue (int nargout, const std::list<octave_lvalue> *lvalue_list);
-
-    virtual octave_lvalue lvalue (void);
+    virtual octave_lvalue lvalue (tree_evaluator *);
 
     int paren_count (void) const { return num_parens; }
 
--- a/libinterp/parse-tree/pt-fcn-handle.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-fcn-handle.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -52,25 +52,6 @@
     os << ((pr_as_read_syntax || pr_orig_text) ? "@" : "") << nm;
   }
 
-  octave_value
-  tree_fcn_handle::rvalue1 (int)
-  {
-    return make_fcn_handle (nm);
-  }
-
-  octave_value_list
-  tree_fcn_handle::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("invalid number of output arguments for function handle expression");
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
   tree_expression *
   tree_fcn_handle::dup (symbol_table::scope_id,
                         symbol_table::context_id) const
@@ -82,80 +63,6 @@
     return new_fh;
   }
 
-  void
-  tree_fcn_handle::accept (tree_walker& tw)
-  {
-    tw.visit_fcn_handle (*this);
-  }
-
-  octave_value
-  tree_anon_fcn_handle::rvalue1 (int)
-  {
-    // FIXME: should CMD_LIST be limited to a single expression?
-    // I think that is what Matlab does.
-
-    tree_parameter_list *param_list = parameter_list ();
-    tree_parameter_list *ret_list = return_list ();
-    tree_statement_list *cmd_list = body ();
-    symbol_table::scope_id this_scope = scope ();
-
-    symbol_table::scope_id new_scope = symbol_table::dup_scope (this_scope);
-
-    if (new_scope > 0)
-      symbol_table::inherit (new_scope, symbol_table::current_scope (),
-                             symbol_table::current_context ());
-
-    octave_user_function *uf
-      = new octave_user_function (new_scope,
-                                  param_list ? param_list->dup (new_scope, 0) : 0,
-                                  ret_list ? ret_list->dup (new_scope, 0) : 0,
-                                  cmd_list ? cmd_list->dup (new_scope, 0) : 0);
-
-    octave_function *curr_fcn = octave::call_stack::current ();
-
-    if (curr_fcn)
-      {
-        // FIXME: maybe it would be better to just stash curr_fcn
-        // instead of individual bits of info about it?
-
-        uf->stash_parent_fcn_name (curr_fcn->name ());
-        uf->stash_dir_name (curr_fcn->dir_name ());
-
-        symbol_table::scope_id parent_scope = curr_fcn->parent_fcn_scope ();
-
-        if (parent_scope < 0)
-          parent_scope = curr_fcn->scope ();
-
-        uf->stash_parent_fcn_scope (parent_scope);
-
-        if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
-          uf->stash_dispatch_class (curr_fcn->dispatch_class ());
-      }
-
-    uf->mark_as_anonymous_function ();
-    uf->stash_fcn_file_name (file_name);
-    uf->stash_fcn_location (line (), column ());
-
-    octave_value ov_fcn (uf);
-
-    octave_value fh (octave_fcn_binder::maybe_binder (ov_fcn));
-
-    return fh;
-  }
-
-  octave_value_list
-  tree_anon_fcn_handle::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("invalid number of output arguments for anonymous function handle expression");
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
   tree_expression *
   tree_anon_fcn_handle::dup (symbol_table::scope_id,
                              symbol_table::context_id) const
@@ -181,12 +88,6 @@
 
     return new_afh;
   }
-
-  void
-  tree_anon_fcn_handle::accept (tree_walker& tw)
-  {
-    tw.visit_anon_fcn_handle (*this);
-  }
 }
 
 /*
--- a/libinterp/parse-tree/pt-fcn-handle.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-fcn-handle.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,6 +32,7 @@
 #include "pt-exp.h"
 #include "pt-misc.h"
 #include "pt-stmt.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 class octave_value_list;
@@ -42,8 +43,6 @@
 
 namespace octave
 {
-  class tree_walker;
-
   class tree_fcn_handle : public tree_expression
   {
   public:
@@ -74,14 +73,13 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_fcn_handle (*this);
+    }
 
   private:
 
@@ -94,14 +92,14 @@
   public:
 
     tree_anon_fcn_handle (int l = -1, int c = -1)
-      : tree_expression (l, c), fcn (0), file_name () { }
+      : tree_expression (l, c), fcn (0), m_file_name () { }
 
     tree_anon_fcn_handle (tree_parameter_list *pl, tree_parameter_list *rl,
                           tree_statement_list *cl, symbol_table::scope_id sid,
                           int l = -1, int c = -1)
       : tree_expression (l, c),
         fcn (new octave_user_function (sid, pl, rl, cl)),
-        file_name () { }
+        m_file_name () { }
 
     // No copying!
 
@@ -115,10 +113,6 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     tree_parameter_list *parameter_list (void) const
     {
       return fcn ? fcn->parameter_list () : 0;
@@ -142,9 +136,14 @@
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_anon_fcn_handle (*this);
+    }
 
-    void stash_file_name (const std::string& file) { file_name = file; }
+    void stash_file_name (const std::string& file) { m_file_name = file; }
+
+    std::string file_name (void) const { return m_file_name; }
 
   private:
 
@@ -152,7 +151,7 @@
     octave_user_function *fcn;
 
     // Filename where the handle was defined.
-    std::string file_name;
+    std::string m_file_name;
   };
 }
 
--- a/libinterp/parse-tree/pt-funcall.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-funcall.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -76,38 +76,4 @@
 
     return new_fc;
   }
-
-  void
-  tree_funcall::accept (tree_walker& tw)
-  {
-    tw.visit_funcall (*this);
-  }
-
-  octave_value_list
-  tree_funcall::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    retval = octave::feval (fcn.function_value (), args, nargout);
-
-    if (retval.length () == 1 && retval(0).is_function ())
-      {
-        // The return object is a function.  We may need to re-index it using the
-        // same logic as for identifier.  This is primarily used for superclass
-        // references in classdef.
-
-        octave_value val = retval(0);
-        octave_function *f = val.function_value (true);
-
-        if (f && ! (is_postfix_indexed ()
-                    && f->is_postfix_index_handled (postfix_index ())))
-          {
-            octave_value_list tmp_args;
-
-            retval = val.do_multi_index_op (nargout, tmp_args);
-          }
-      }
-
-    return retval;
-  }
 }
--- a/libinterp/parse-tree/pt-funcall.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-funcall.h	Fri Apr 21 18:07:40 2017 -0400
@@ -29,6 +29,7 @@
 #include "ovl.h"
 #include "parse.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 
 namespace octave
 {
@@ -68,25 +69,14 @@
     tree_funcall *dup (symbol_table::scope_id,
                        symbol_table::context_id context) const;
 
-    octave_value rvalue1 (int nargout)
-    {
-      octave_value retval;
-
-      const octave_value_list tmp = rvalue (nargout);
-
-      if (! tmp.empty ())
-        retval = tmp(0);
-
-      return retval;
-    }
-
-    octave_value_list rvalue (int nargout);
-
     octave_value function (void) const { return fcn; }
 
     octave_value_list arguments (void) const { return args; }
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_funcall (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-id.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-id.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -59,77 +59,8 @@
                      name ().c_str (), l, c);
   }
 
-  octave_value_list
-  tree_identifier::rvalue (int nargout,
-                           const std::list<octave_lvalue> *lvalue_list)
-  {
-    octave_value_list retval;
-
-    octave_value val = sym->find ();
-
-    if (val.is_defined ())
-      {
-        // GAGME -- this would be cleaner if we required
-        // parens to indicate function calls.
-        //
-        // If this identifier refers to a function, we need to know
-        // whether it is indexed so that we can do the same thing
-        // for 'f' and 'f()'.  If the index is present and the function
-        // object declares it can handle it, return the function object
-        // and let tree_index_expression::rvalue handle indexing.
-        // Otherwise, arrange to call the function here, so that we don't
-        // return the function definition as a value.
-
-        octave_function *fcn = 0;
-
-        if (val.is_function ())
-          fcn = val.function_value (true);
-
-        if (fcn && ! (is_postfix_indexed ()
-                      && fcn->is_postfix_index_handled (postfix_index ())))
-          {
-            octave_value_list tmp_args;
-
-            retval = (lvalue_list
-                      ? val.do_multi_index_op (nargout, tmp_args, lvalue_list)
-                      : val.do_multi_index_op (nargout, tmp_args));
-          }
-        else
-          {
-            if (print_result () && nargout == 0
-                && octave::tree_evaluator::statement_printing_enabled ())
-              {
-                octave_value_list args = ovl (val);
-                args.stash_name_tags (string_vector (name ()));
-                octave::feval ("display", args);
-              }
-
-            retval = val;
-          }
-      }
-    else if (sym->is_added_static ())
-      static_workspace_error ();
-    else
-      eval_undefined_error ();
-
-    return retval;
-  }
-
-  octave_value
-  tree_identifier::rvalue1 (int nargout)
-  {
-    octave_value retval;
-
-    octave_value_list tmp = rvalue (nargout);
-
-    if (! tmp.empty ())
-      retval = tmp(0);
-
-    return retval;
-  }
-
   octave_lvalue
-  tree_identifier::lvalue (void)
+  tree_identifier::lvalue (tree_evaluator *)
   {
     if (sym->is_added_static ())
       static_workspace_error ();
@@ -155,10 +86,4 @@
 
     return new_id;
   }
-
-  void
-  tree_identifier::accept (tree_walker& tw)
-  {
-    tw.visit_identifier (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-id.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-id.h	Fri Apr 21 18:07:40 2017 -0400
@@ -35,11 +35,12 @@
 #include "oct-lvalue.h"
 #include "pt-bp.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
+  class tree_evaluator;
 
   // Symbols from the symbol table.
 
@@ -111,17 +112,7 @@
 
     bool lvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout)
-    {
-      return rvalue (nargout, 0);
-    }
-
-    octave_value_list rvalue (int nargout,
-                              const std::list<octave_lvalue> *lvalue_list);
-
-    octave_lvalue lvalue (void);
+    octave_lvalue lvalue (tree_evaluator *);
 
     void eval_undefined_error (void);
 
@@ -134,7 +125,10 @@
     tree_identifier *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_identifier (*this);
+    }
 
     symbol_table::symbol_reference symbol (void) const
     {
@@ -165,7 +159,7 @@
       return new tree_black_hole;
     }
 
-    octave_lvalue lvalue (void)
+    octave_lvalue lvalue (tree_evaluator *)
     {
       return octave_lvalue (); // black hole lvalue
     }
--- a/libinterp/parse-tree/pt-idx.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-idx.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -33,6 +33,7 @@
 #include "pager.h"
 #include "pt-arg-list.h"
 #include "pt-bp.h"
+#include "pt-eval.h"
 #include "pt-id.h"
 #include "pt-idx.h"
 #include "pt-walk.h"
@@ -146,34 +147,10 @@
   }
 }
 
-static Cell
-make_subs_cell (octave::tree_argument_list *args, const string_vector& arg_nm)
-{
-  Cell retval;
-
-  octave_value_list arg_values;
-
-  if (args)
-    arg_values = args->convert_to_const_vector ();
-
-  int n = arg_values.length ();
-
-  if (n > 0)
-    {
-      arg_values.stash_name_tags (arg_nm);
-
-      retval.resize (dim_vector (1, n));
-
-      for (int i = 0; i < n; i++)
-        retval(0,i) = arg_values(i);
-    }
-
-  return retval;
-}
-
 static inline octave_value_list
-make_value_list (octave::tree_argument_list *args, const string_vector& arg_nm,
-                 const octave_value *object, bool rvalue = true)
+make_value_list (octave::tree_evaluator *tw, octave::tree_argument_list *args,
+                 const string_vector& arg_nm, const octave_value *object,
+                 bool rvalue = true)
 {
   octave_value_list retval;
 
@@ -182,7 +159,7 @@
       if (rvalue && object && args->has_magic_end () && object->is_undefined ())
         err_invalid_inquiry_subscript ();
 
-      retval = args->convert_to_const_vector (object);
+      retval = args->convert_to_const_vector (tw, object);
     }
 
   octave_idx_type n = retval.length ();
@@ -197,7 +174,8 @@
 {
   std::string
   tree_index_expression::get_struct_index
-  (std::list<string_vector>::const_iterator p_arg_nm,
+  (tree_evaluator *tw,
+   std::list<string_vector>::const_iterator p_arg_nm,
    std::list<tree_expression *>::const_iterator p_dyn_field) const
   {
     std::string fn = (*p_arg_nm)(0);
@@ -208,7 +186,7 @@
 
         if (df)
           {
-            octave_value t = df->rvalue1 ();
+            octave_value t = tw->evaluate (df);
 
             fn = t.xstring_value ("dynamic structure field names must be strings");
           }
@@ -218,57 +196,6 @@
 
     return fn;
   }
-
-  octave_map
-  tree_index_expression::make_arg_struct (void) const
-  {
-    int n = args.size ();
-
-    Cell type_field (n, 1);
-    Cell subs_field (n, 1);
-
-    std::list<tree_argument_list *>::const_iterator p_args = args.begin ();
-    std::list<string_vector>::const_iterator p_arg_nm = arg_nm.begin ();
-    std::list<tree_expression *>::const_iterator p_dyn_field = dyn_field.begin ();
-
-    octave_map m;
-
-    for (int i = 0; i < n; i++)
-      {
-        switch (type[i])
-          {
-          case '(':
-            subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
-            break;
-
-          case '{':
-            subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
-            break;
-
-          case '.':
-            subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field);
-            break;
-
-          default:
-            panic_impossible ();
-          }
-
-        p_args++;
-        p_arg_nm++;
-        p_dyn_field++;
-      }
-
-    m.assign ("type", type_field);
-    m.assign ("subs", subs_field);
-
-    return m;
-  }
-
-  octave_value_list
-  tree_index_expression::rvalue (int nargout)
-  {
-    return tree_index_expression::rvalue (nargout, 0);
-  }
 }
 
 // Final step of processing an indexing error.  Add the name of the
@@ -306,203 +233,8 @@
 
 namespace octave
 {
-  octave_value_list
-  tree_index_expression::rvalue (int nargout,
-                                 const std::list<octave_lvalue> *lvalue_list)
-  {
-    octave_value_list retval;
-
-    octave_value first_expr_val;
-
-    octave_value_list first_args;
-
-    bool have_args = false;
-
-    if (expr->is_identifier () && type[0] == '(')
-      {
-        tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
-
-        if (! (id->is_variable () || args.empty ()))
-          {
-            tree_argument_list *al = *(args.begin ());
-
-            size_t n = al ? al->length () : 0;
-
-            if (n > 0)
-              {
-                string_vector anm = *(arg_nm.begin ());
-                have_args = true;
-                first_args = al -> convert_to_const_vector ();
-                first_args.stash_name_tags (anm);
-
-                first_expr_val = id->do_lookup  (first_args);
-              }
-          }
-      }
-
-    if (first_expr_val.is_undefined ())
-      first_expr_val = expr->rvalue1 ();
-
-    octave_value tmp = first_expr_val;
-    octave_idx_type tmpi = 0;
-
-    std::list<octave_value_list> idx;
-
-    int n = args.size ();
-
-    std::list<tree_argument_list *>::iterator p_args = args.begin ();
-    std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
-    std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
-
-    for (int i = 0; i < n; i++)
-      {
-        if (i > 0)
-          {
-            tree_argument_list *al = *p_args;
-
-            // In Matlab, () can only be followed by '.'.  In Octave, we
-            // do not enforce this for rvalue expressions, but we'll
-            // split the evaluation at this point.  This will,
-            // hopefully, allow Octave's looser rules apply smoothly for
-            // Matlab overloaded subsref codes.
-
-            // We might have an expression like
-            //
-            //   x{end}.a(end)
-            //
-            // and we are looking at the argument list that contains the
-            // second (or third, etc.) "end" token, so we must evaluate
-            // everything up to the point of that argument list so we
-            // can pass the appropriate value to the built-in end
-            // function.
-
-            // An expression like
-            //
-            //    s.a (f (1:end))
-            //
-            // can mean a lot of different things depending on the types
-            // of s, a, and f.  Let's just say it's complicated and that
-            // the following code is definitely not correct in all
-            // cases.  That it is already so complex makes me think that
-            // there must be a better way.
-
-            bool split = ((type[i-1] == '(' && type[i] != '.')
-                          || (al && al->has_magic_end ()
-                              && ! tmp.is_classdef_object ()));
-
-            if (split)
-              {
-                try
-                  {
-                    octave_value_list tmp_list
-                      =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout);
-
-                    tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
-                    tmpi = i;
-                    idx.clear ();
-
-                    if (tmp.is_cs_list ())
-                      err_indexed_cs_list ();
-
-                    if (tmp.is_function ())
-                      {
-                        octave_function *fcn = tmp.function_value (true);
-
-                        if (fcn && ! fcn->is_postfix_index_handled (type[i]))
-                          {
-                            octave_value_list empty_args;
-
-                            tmp_list = tmp.do_multi_index_op (1, empty_args);
-                            tmp = (tmp_list.length ()
-                                   ? tmp_list(0) : octave_value ());
-
-                            if (tmp.is_cs_list ())
-                              err_indexed_cs_list ();
-                          }
-                      }
-                  }
-                catch (octave::index_exception& e)  // problems with index range, type etc.
-                  {
-                    final_index_error (e, expr);
-                  }
-              }
-          }
-
-        switch (type[i])
-          {
-          case '(':
-            if (have_args)
-              {
-                idx.push_back (first_args);
-                have_args = false;
-              }
-            else
-              idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
-            break;
-
-          case '{':
-            idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
-            break;
-
-          case '.':
-            idx.push_back (octave_value (get_struct_index (p_arg_nm,
-                                                           p_dyn_field)));
-            break;
-
-          default:
-            panic_impossible ();
-          }
-
-        p_args++;
-        p_arg_nm++;
-        p_dyn_field++;
-      }
-
-    try
-      {
-        retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
-                              lvalue_list);
-      }
-    catch (octave::index_exception& e)  // range problems, bad index type, etc.
-      {
-        final_index_error (e, expr);
-      }
-
-    octave_value val = retval.length () ? retval(0) : octave_value ();
-
-    if (val.is_function ())
-      {
-        octave_function *fcn = val.function_value (true);
-
-        if (fcn)
-          {
-            octave_value_list empty_args;
-
-            retval = (lvalue_list
-                      ? val.do_multi_index_op (nargout, empty_args,
-                                               lvalue_list)
-                      : val.do_multi_index_op (nargout, empty_args));
-          }
-      }
-
-    return retval;
-  }
-
-  octave_value
-  tree_index_expression::rvalue1 (int nargout)
-  {
-    octave_value retval;
-
-    const octave_value_list tmp = rvalue (nargout);
-
-    if (! tmp.empty ())
-      retval = tmp(0);
-
-    return retval;
-  }
-
   octave_lvalue
-  tree_index_expression::lvalue (void)
+  tree_index_expression::lvalue (tree_evaluator *tw)
   {
     octave_lvalue retval;
 
@@ -515,7 +247,7 @@
     std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
     std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
 
-    retval = expr->lvalue ();
+    retval = expr->lvalue (tw);
 
     octave_value tmp = retval.value ();
 
@@ -546,7 +278,7 @@
           case '(':
             {
               octave_value_list tidx
-                = make_value_list (*p_args, *p_arg_nm, &tmp, false);
+                = make_value_list (tw, *p_args, *p_arg_nm, &tmp, false);
 
               idx.push_back (tidx);
 
@@ -564,7 +296,7 @@
           case '{':
             {
               octave_value_list tidx
-                = make_value_list (*p_args, *p_arg_nm, &tmp, false);
+                = make_value_list (tw, *p_args, *p_arg_nm, &tmp, false);
 
               if (tmp.is_undefined ())
                 {
@@ -589,7 +321,7 @@
 
           case '.':
             {
-              octave_value tidx = get_struct_index (p_arg_nm, p_dyn_field);
+              octave_value tidx = get_struct_index (tw, p_arg_nm, p_dyn_field);
 
               bool autoconv = (tmp.is_zero_by_zero ()
                                && (tmp.is_matrix_type () || tmp.is_string ()
@@ -684,12 +416,6 @@
 
     return new_idx_expr;
   }
-
-  void
-  tree_index_expression::accept (tree_walker& tw)
-  {
-    tw.visit_index_expression (*this);
-  }
 }
 
 /*
--- a/libinterp/parse-tree/pt-idx.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-idx.h	Fri Apr 21 18:07:40 2017 -0400
@@ -35,13 +35,13 @@
 #include "str-vec.h"
 
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
   class tree_argument_list;
-
-  class tree_walker;
+  class tree_evaluator;
 
   // Index expressions.
 
@@ -86,23 +86,26 @@
 
     std::list<string_vector> arg_names (void) { return arg_nm; }
 
+    std::list<tree_expression *> dyn_fields (void) { return dyn_field; }
+
     bool lvalue_ok (void) const { return expr->lvalue_ok (); }
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
-    octave_value_list rvalue (int nargout,
-                              const std::list<octave_lvalue> *lvalue_list);
-
-    octave_lvalue lvalue (void);
+    octave_lvalue lvalue (tree_evaluator *tw);
 
     tree_index_expression *dup (symbol_table::scope_id scope,
                                 symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_index_expression (*this);
+    }
+
+    std::string
+    get_struct_index
+    (tree_evaluator *tw, std::list<string_vector>::const_iterator p_arg_nm,
+     std::list<tree_expression *>::const_iterator p_dyn_field) const;
 
   private:
 
@@ -125,11 +128,6 @@
     tree_index_expression (int l, int c);
 
     octave_map make_arg_struct (void) const;
-
-    std::string
-    get_struct_index
-    (std::list<string_vector>::const_iterator p_arg_nm,
-     std::list<tree_expression *>::const_iterator p_dyn_field) const;
   };
 }
 
--- a/libinterp/parse-tree/pt-jit.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-jit.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -668,7 +668,8 @@
 void
 jit_convert::visit_constant (tree_constant& tc)
 {
-  octave_value v = tc.rvalue1 ();
+  octave_value v = tc.value ();
+
   jit_type *ty = jit_typeinfo::type_of (v);
 
   if (ty == jit_typeinfo::get_scalar ())
--- a/libinterp/parse-tree/pt-jump.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-jump.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -46,12 +46,6 @@
     return new tree_break_command (line (), column ());
   }
 
-  void
-  tree_break_command::accept (tree_walker& tw)
-  {
-    tw.visit_break_command (*this);
-  }
-
   // Continue.
 
   // Nonzero means we're jumping to the end of a loop.
@@ -64,12 +58,6 @@
     return new tree_continue_command (line (), column ());
   }
 
-  void
-  tree_continue_command::accept (tree_walker& tw)
-  {
-    tw.visit_continue_command (*this);
-  }
-
   // Return.
 
   // Nonzero means we're returning from a function.
@@ -81,10 +69,4 @@
   {
     return new tree_return_command (line (), column ());
   }
-
-  void
-  tree_return_command::accept (tree_walker& tw)
-  {
-    tw.visit_return_command (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-jump.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-jump.h	Fri Apr 21 18:07:40 2017 -0400
@@ -26,12 +26,11 @@
 #include "octave-config.h"
 
 #include "pt-cmd.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // Break.
 
   class tree_break_command : public tree_command
@@ -52,7 +51,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_break_command (*this);
+    }
 
     static int breaking;
   };
@@ -77,7 +79,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_continue_command (*this);
+    }
 
     static int continuing;
   };
@@ -102,7 +107,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_return_command (*this);
+    }
 
     static int returning;
   };
--- a/libinterp/parse-tree/pt-loop.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-loop.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -68,12 +68,6 @@
                                    line (), column ());
   }
 
-  void
-  tree_while_command::accept (tree_walker& tw)
-  {
-    tw.visit_while_command (*this);
-  }
-
   // Do-Until
 
   tree_command *
@@ -87,12 +81,6 @@
                                       line (), column ());
   }
 
-  void
-  tree_do_until_command::accept (tree_walker& tw)
-  {
-    tw.visit_do_until_command (*this);
-  }
-
   // For.
 
   tree_simple_for_command::~tree_simple_for_command (void)
@@ -121,12 +109,6 @@
        trail_comm ? trail_comm->dup () : 0, line (), column ());
   }
 
-  void
-  tree_simple_for_command::accept (tree_walker& tw)
-  {
-    tw.visit_simple_for_command (*this);
-  }
-
   tree_complex_for_command::~tree_complex_for_command (void)
   {
     delete lhs;
@@ -147,10 +129,4 @@
                                          trail_comm ? trail_comm->dup () : 0,
                                          line (), column ());
   }
-
-  void
-  tree_complex_for_command::accept (tree_walker& tw)
-  {
-    tw.visit_complex_for_command (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-loop.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-loop.h	Fri Apr 21 18:07:40 2017 -0400
@@ -30,6 +30,7 @@
 
 #include "comment-list.h"
 #include "pt-cmd.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 class jit_info;
@@ -40,8 +41,6 @@
   class tree_expression;
   class tree_statement_list;
 
-  class tree_walker;
-
   // While.
 
   class tree_while_command : public tree_command
@@ -97,7 +96,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_while_command (*this);
+    }
 
 #if defined (HAVE_LLVM)
     // some functions use by tree_jit
@@ -166,7 +168,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_do_until_command (*this);
+    }
   };
 
   // For.
@@ -223,7 +228,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_simple_for_command (*this);
+    }
 
 #if defined (HAVE_LLVM)
     // some functions use by tree_jit
@@ -305,7 +313,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_complex_for_command (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-mat.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-mat.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -39,6 +39,7 @@
 #include "pt-bp.h"
 #include "pt-exp.h"
 #include "pt-mat.h"
+#include "pt-tm-const.h"
 #include "pt-walk.h"
 #include "utils.h"
 #include "ov.h"
@@ -54,155 +55,6 @@
 
 namespace octave
 {
-  // General matrices.  This list type is much more work to handle than
-  // constant matrices, but it allows us to construct matrices from
-  // other matrices, variables, and functions.
-
-  // But first, some internal classes that make our job much easier.
-
-  class
-  tm_row_const
-  {
-  private:
-
-    class
-    tm_row_const_rep : public octave::base_list<octave_value>
-    {
-    public:
-
-      tm_row_const_rep (void)
-        : count (1), dv (0, 0), all_str (false),
-          all_sq_str (false), all_dq_str (false),
-          some_str (false), all_real (false), all_cmplx (false),
-          all_mt (true), any_cell (false), any_sparse (false),
-          any_class (false), all_1x1 (false),
-          first_elem_is_struct (false), class_nm (), ok (false)
-      { }
-
-      tm_row_const_rep (const tree_argument_list& row)
-        : count (1), dv (0, 0), all_str (false), all_sq_str (false),
-          some_str (false), all_real (false), all_cmplx (false),
-          all_mt (true), any_cell (false), any_sparse (false),
-          any_class (false), all_1x1 (! row.empty ()),
-          first_elem_is_struct (false), class_nm (), ok (false)
-      { init (row); }
-
-      ~tm_row_const_rep (void) = default;
-
-      octave::refcount<int> count;
-
-      dim_vector dv;
-
-      bool all_str;
-      bool all_sq_str;
-      bool all_dq_str;
-      bool some_str;
-      bool all_real;
-      bool all_cmplx;
-      bool all_mt;
-      bool any_cell;
-      bool any_sparse;
-      bool any_class;
-      bool all_1x1;
-      bool first_elem_is_struct;
-
-      std::string class_nm;
-
-      bool ok;
-
-      void do_init_element (const octave_value&, bool&);
-
-      void init (const tree_argument_list&);
-
-      void cellify (void);
-
-    private:
-
-      tm_row_const_rep (const tm_row_const_rep&);
-
-      tm_row_const_rep& operator = (const tm_row_const_rep&);
-
-    };
-
-  public:
-
-    typedef tm_row_const_rep::iterator iterator;
-    typedef tm_row_const_rep::const_iterator const_iterator;
-
-    tm_row_const (void)
-      : rep (0) { }
-
-    tm_row_const (const tree_argument_list& row)
-      : rep (new tm_row_const_rep (row)) { }
-
-    tm_row_const (const tm_row_const& x)
-      : rep (x.rep)
-    {
-      if (rep)
-        rep->count++;
-    }
-
-    tm_row_const& operator = (const tm_row_const& x)
-    {
-      if (this != &x && rep != x.rep)
-        {
-          if (rep && --rep->count == 0)
-            delete rep;
-
-          rep = x.rep;
-
-          if (rep)
-            rep->count++;
-        }
-
-      return *this;
-    }
-
-    ~tm_row_const (void)
-    {
-      if (rep && --rep->count == 0)
-        delete rep;
-    }
-
-    octave_idx_type rows (void) { return rep->dv(0); }
-    octave_idx_type cols (void) { return rep->dv(1); }
-
-    bool empty (void) const { return rep->empty (); }
-
-    size_t length (void) const { return rep->length (); }
-
-    dim_vector dims (void) { return rep->dv; }
-
-    bool all_strings_p (void) const { return rep->all_str; }
-    bool all_sq_strings_p (void) const { return rep->all_sq_str; }
-    bool all_dq_strings_p (void) const { return rep->all_dq_str; }
-    bool some_strings_p (void) const { return rep->some_str; }
-    bool all_real_p (void) const { return rep->all_real; }
-    bool all_complex_p (void) const { return rep->all_cmplx; }
-    bool all_empty_p (void) const { return rep->all_mt; }
-    bool any_cell_p (void) const { return rep->any_cell; }
-    bool any_sparse_p (void) const { return rep->any_sparse; }
-    bool any_class_p (void) const { return rep->any_class; }
-    bool all_1x1_p (void) const { return rep->all_1x1; }
-    bool first_elem_struct_p (void) const { return rep->first_elem_is_struct; }
-
-    std::string class_name (void) const { return rep->class_nm; }
-
-    void cellify (void) { rep->cellify (); }
-
-    operator bool () const { return (rep && rep->ok); }
-
-    iterator begin (void) { return rep->begin (); }
-    const_iterator begin (void) const { return rep->begin (); }
-
-    iterator end (void) { return rep->end (); }
-    const_iterator end (void) const { return rep->end (); }
-
-  private:
-
-    tm_row_const_rep *rep;
-  };
-
   std::string
   get_concat_class (const std::string& c1, const std::string& c2)
   {
@@ -275,381 +127,6 @@
 
     return retval;
   }
-}
-
-OCTAVE_NORETURN static
-void
-eval_error (const char *msg, const dim_vector& x, const dim_vector& y)
-{
-  error ("%s (%s vs %s)", msg, x.str ().c_str (), y.str ().c_str ());
-}
-
-namespace octave
-{
-  void
-  tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val,
-                                                   bool& first_elem)
-  {
-    std::string this_elt_class_nm
-      = val.is_object () ? std::string ("class") : val.class_name ();
-
-    class_nm = get_concat_class (class_nm, this_elt_class_nm);
-
-    dim_vector this_elt_dv = val.dims ();
-
-    if (! this_elt_dv.zero_by_zero ())
-      {
-        all_mt = false;
-
-        if (first_elem)
-          {
-            if (val.is_map ())
-              first_elem_is_struct = true;
-
-            first_elem = false;
-          }
-      }
-
-    append (val);
-
-    if (all_str && ! val.is_string ())
-      all_str = false;
-
-    if (all_sq_str && ! val.is_sq_string ())
-      all_sq_str = false;
-
-    if (all_dq_str && ! val.is_dq_string ())
-      all_dq_str = false;
-
-    if (! some_str && val.is_string ())
-      some_str = true;
-
-    if (all_real && ! val.is_real_type ())
-      all_real = false;
-
-    if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ()))
-      all_cmplx = false;
-
-    if (! any_cell && val.is_cell ())
-      any_cell = true;
-
-    if (! any_sparse && val.is_sparse_type ())
-      any_sparse = true;
-
-    if (! any_class && val.is_object ())
-      any_class = true;
-
-    // Special treatment of sparse matrices to avoid out-of-memory error
-    all_1x1 = all_1x1 && ! val.is_sparse_type () && val.numel () == 1;
-  }
-
-  void
-  tm_row_const::tm_row_const_rep::init (const tree_argument_list& row)
-  {
-    all_str = true;
-    all_sq_str = true;
-    all_dq_str = true;
-    all_real = true;
-    all_cmplx = true;
-    any_cell = false;
-    any_sparse = false;
-    any_class = false;
-
-    bool first_elem = true;
-
-    for (tree_expression* elt : row)
-      {
-        octave_quit ();
-
-        octave_value tmp = elt->rvalue1 ();
-
-        if (tmp.is_undefined ())
-          {
-            ok = true;
-            return;
-          }
-        else
-          {
-            if (tmp.is_cs_list ())
-              {
-                octave_value_list tlst = tmp.list_value ();
-
-                for (octave_idx_type i = 0; i < tlst.length (); i++)
-                  {
-                    octave_quit ();
-
-                    do_init_element (tlst(i), first_elem);
-                  }
-              }
-            else
-              do_init_element (tmp, first_elem);
-          }
-      }
-
-    if (any_cell && ! any_class && ! first_elem_is_struct)
-      cellify ();
-
-    first_elem = true;
-
-    for (const octave_value& val : *this)
-      {
-        octave_quit ();
-
-        dim_vector this_elt_dv = val.dims ();
-
-        if (! this_elt_dv.zero_by_zero ())
-          {
-            all_mt = false;
-
-            if (first_elem)
-              {
-                first_elem = false;
-                dv = this_elt_dv;
-              }
-            else if ((! any_class) && (! dv.hvcat (this_elt_dv, 1)))
-              eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
-          }
-      }
-
-    ok = true;
-  }
-
-  void
-  tm_row_const::tm_row_const_rep::cellify (void)
-  {
-    bool elt_changed = false;
-
-    for (auto& elt : *this)
-      {
-        octave_quit ();
-
-        if (! elt.is_cell ())
-          {
-            elt_changed = true;
-
-            if (elt.is_empty ())
-              elt = Cell ();
-            else
-              elt = Cell (elt);
-          }
-      }
-
-    if (elt_changed)
-      {
-        bool first_elem = true;
-
-        for (const octave_value& val : *this)
-          {
-            octave_quit ();
-
-            dim_vector this_elt_dv = val.dims ();
-
-            if (! this_elt_dv.zero_by_zero ())
-              {
-                if (first_elem)
-                  {
-                    first_elem = false;
-                    dv = this_elt_dv;
-                  }
-                else if (! dv.hvcat (this_elt_dv, 1))
-                  eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
-              }
-          }
-      }
-  }
-
-  class
-  tm_const : public octave::base_list<tm_row_const>
-  {
-  public:
-
-    tm_const (const tree_matrix& tm)
-      : dv (0, 0), all_str (false), all_sq_str (false), all_dq_str (false),
-        some_str (false), all_real (false), all_cmplx (false),
-        all_mt (true), any_cell (false), any_sparse (false),
-        any_class (false), class_nm (), ok (false)
-    { init (tm); }
-
-    ~tm_const (void) = default;
-
-    octave_idx_type rows (void) const { return dv.elem (0); }
-    octave_idx_type cols (void) const { return dv.elem (1); }
-
-    dim_vector dims (void) const { return dv; }
-
-    bool all_strings_p (void) const { return all_str; }
-    bool all_sq_strings_p (void) const { return all_sq_str; }
-    bool all_dq_strings_p (void) const { return all_dq_str; }
-    bool some_strings_p (void) const { return some_str; }
-    bool all_real_p (void) const { return all_real; }
-    bool all_complex_p (void) const { return all_cmplx; }
-    bool all_empty_p (void) const { return all_mt; }
-    bool any_cell_p (void) const { return any_cell; }
-    bool any_sparse_p (void) const { return any_sparse; }
-    bool any_class_p (void) const { return any_class; }
-    bool all_1x1_p (void) const { return all_1x1; }
-
-    std::string class_name (void) const { return class_nm; }
-
-    operator bool () const { return ok; }
-
-  private:
-
-    dim_vector dv;
-
-    bool all_str;
-    bool all_sq_str;
-    bool all_dq_str;
-    bool some_str;
-    bool all_real;
-    bool all_cmplx;
-    bool all_mt;
-    bool any_cell;
-    bool any_sparse;
-    bool any_class;
-    bool all_1x1;
-
-    std::string class_nm;
-
-    bool ok;
-
-    tm_const (void);
-
-    tm_const (const tm_const&);
-
-    tm_const& operator = (const tm_const&);
-
-    void init (const tree_matrix& tm);
-  };
-
-  void
-  tm_const::init (const tree_matrix& tm)
-  {
-    all_str = true;
-    all_sq_str = true;
-    all_dq_str = true;
-    all_real = true;
-    all_cmplx = true;
-    any_cell = false;
-    any_sparse = false;
-    any_class = false;
-    all_1x1 = ! tm.empty ();
-
-    bool first_elem = true;
-    bool first_elem_is_struct = false;
-
-    // Just eval and figure out if what we have is complex or all strings.
-    // We can't check columns until we know that this is a numeric matrix --
-    // collections of strings can have elements of different lengths.
-    for (const tree_argument_list* elt : tm)
-      {
-        octave_quit ();
-
-        tm_row_const tmp (*elt);
-
-        if (first_elem)
-          {
-            first_elem_is_struct = tmp.first_elem_struct_p ();
-
-            first_elem = false;
-          }
-
-        if (tmp && ! tmp.empty ())
-          {
-            if (all_str && ! tmp.all_strings_p ())
-              all_str = false;
-
-            if (all_sq_str && ! tmp.all_sq_strings_p ())
-              all_sq_str = false;
-
-            if (all_dq_str && ! tmp.all_dq_strings_p ())
-              all_dq_str = false;
-
-            if (! some_str && tmp.some_strings_p ())
-              some_str = true;
-
-            if (all_real && ! tmp.all_real_p ())
-              all_real = false;
-
-            if (all_cmplx && ! tmp.all_complex_p ())
-              all_cmplx = false;
-
-            if (all_mt && ! tmp.all_empty_p ())
-              all_mt = false;
-
-            if (! any_cell && tmp.any_cell_p ())
-              any_cell = true;
-
-            if (! any_sparse && tmp.any_sparse_p ())
-              any_sparse = true;
-
-            if (! any_class && tmp.any_class_p ())
-              any_class = true;
-
-            all_1x1 = all_1x1 && tmp.all_1x1_p ();
-
-            append (tmp);
-          }
-        else
-          break;
-      }
-
-    if (any_cell && ! any_class && ! first_elem_is_struct)
-      {
-        for (auto& elt : *this)
-          {
-            octave_quit ();
-
-            elt.cellify ();
-          }
-      }
-
-    first_elem = true;
-
-    for (tm_row_const& elt : *this)
-      {
-        octave_quit ();
-
-        octave_idx_type this_elt_nr = elt.rows ();
-        octave_idx_type this_elt_nc = elt.cols ();
-
-        std::string this_elt_class_nm = elt.class_name ();
-        class_nm = get_concat_class (class_nm, this_elt_class_nm);
-
-        dim_vector this_elt_dv = elt.dims ();
-
-        all_mt = false;
-
-        if (first_elem)
-          {
-            first_elem = false;
-
-            dv = this_elt_dv;
-          }
-        else if (all_str && dv.ndims () == 2
-                 && this_elt_dv.ndims () == 2)
-          {
-            // FIXME: this is Octave's specialty.
-            // Character matrices allow rows of unequal length.
-            if (this_elt_nc > cols ())
-              dv(1) = this_elt_nc;
-            dv(0) += this_elt_nr;
-          }
-        else if ((! any_class) && (! dv.hvcat (this_elt_dv, 0)))
-          eval_error ("vertical dimensions mismatch", dv, this_elt_dv);
-      }
-
-    ok = true;
-  }
-
-  octave_value_list
-  tree_matrix::rvalue (int nargout)
-  {
-    if (nargout > 1)
-      error ("invalid number of output arguments for matrix list");
-
-    return rvalue1 (nargout);
-  }
 
   void
   maybe_warn_string_concat (bool all_dq_strings_p, bool all_sq_strings_p)
@@ -658,423 +135,6 @@
       warning_with_id ("Octave:mixed-string-concat",
                        "concatenation of different character string types may have unintended consequences");
   }
-}
-
-template <typename TYPE, typename T>
-static void
-single_type_concat (Array<T>& result, octave::tm_const& tmp)
-{
-  octave_idx_type r = 0;
-  octave_idx_type c = 0;
-
-  for (octave::tm_row_const& row : tmp)
-    {
-      // Skip empty arrays to allow looser rules.
-      if (row.dims ().any_zero ())
-        continue;
-
-      for (auto& elt : row)
-        {
-          octave_quit ();
-
-          TYPE ra = octave_value_extract<TYPE> (elt);
-
-          // Skip empty arrays to allow looser rules.
-
-          if (! ra.is_empty ())
-            {
-              result.insert (ra, r, c);
-
-              c += ra.columns ();
-            }
-        }
-
-      r += row.rows ();
-      c = 0;
-    }
-}
-
-template <typename TYPE, typename T>
-static void
-single_type_concat (Array<T>& result, const dim_vector& dv,
-                    octave::tm_const& tmp)
-{
-  if (dv.any_zero ())
-    {
-      result = Array<T> (dv);
-      return;
-    }
-
-  if (tmp.length () == 1)
-    {
-      // If possible, forward the operation to liboctave.
-      // Single row.
-      octave::tm_row_const& row = tmp.front ();
-      if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value)
-          && row.all_1x1_p ())
-        {
-          // Optimize all scalars case.
-          result.clear (dv);
-          assert (static_cast<size_t> (result.numel ()) == row.length ());
-          octave_idx_type i = 0;
-          for (const auto& elt : row)
-            result(i++) = octave_value_extract<T> (elt);
-
-          return;
-        }
-
-      octave_idx_type ncols = row.length ();
-      octave_idx_type i = 0;
-      OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
-
-      for (const auto& elt : row)
-        {
-          octave_quit ();
-
-          array_list[i++] = octave_value_extract<TYPE> (elt);
-        }
-
-      result = Array<T>::cat (-2, ncols, array_list);
-    }
-  else
-    {
-      result = Array<T> (dv);
-      single_type_concat<TYPE> (result, tmp);
-    }
-}
-
-template <typename TYPE, typename T>
-static void
-single_type_concat (Sparse<T>& result, const dim_vector& dv,
-                    octave::tm_const& tmp)
-{
-  if (dv.any_zero ())
-    {
-      result = Sparse<T> (dv);
-      return;
-    }
-
-  // Sparse matrices require preallocation for efficient indexing; besides,
-  // only horizontal concatenation can be efficiently handled by indexing.
-  // So we just cat all rows through liboctave, then cat the final column.
-  octave_idx_type nrows = tmp.length ();
-  octave_idx_type j = 0;
-  OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows);
-  for (octave::tm_row_const& row : tmp)
-    {
-      octave_idx_type ncols = row.length ();
-      octave_idx_type i = 0;
-      OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols);
-
-      for (auto& elt : row)
-        {
-          octave_quit ();
-
-          sparse_list[i] = octave_value_extract<TYPE> (elt);
-          i++;
-        }
-
-      Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list);
-      sparse_row_list[j] = stmp;
-      j++;
-    }
-
-  result = Sparse<T>::cat (-1, nrows, sparse_row_list);
-}
-
-template <typename MAP>
-static void
-single_type_concat (octave_map& result, const dim_vector& dv,
-                    octave::tm_const& tmp)
-{
-  if (dv.any_zero ())
-    {
-      result = octave_map (dv);
-      return;
-    }
-
-  octave_idx_type nrows = tmp.length ();
-  octave_idx_type j = 0;
-  OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
-  for (octave::tm_row_const& row : tmp)
-    {
-      octave_idx_type ncols = row.length ();
-      octave_idx_type i = 0;
-      OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
-
-      for (auto& elt : row)
-        {
-          octave_quit ();
-
-          map_list[i] = octave_value_extract<MAP> (elt);
-          i++;
-        }
-
-      octave_map mtmp = octave_map::cat (-2, ncols, map_list);
-      map_row_list[j] = mtmp;
-      j++;
-    }
-
-  result = octave_map::cat (-1, nrows, map_row_list);
-}
-
-template <typename TYPE>
-static octave_value
-do_single_type_concat (const dim_vector& dv, octave::tm_const& tmp)
-{
-  TYPE result;
-
-  single_type_concat<TYPE> (result, dv, tmp);
-
-  return result;
-}
-
-template <>
-octave_value
-do_single_type_concat<octave_map> (const dim_vector& dv, octave::tm_const& tmp)
-{
-  octave_map result;
-
-  if (tmp.all_1x1_p ())
-    single_type_concat<octave_scalar_map> (result, dv, tmp);
-  else
-    single_type_concat<octave_map> (result, dv, tmp);
-
-  return result;
-}
-
-static octave_value
-do_class_concat (octave::tm_const& tmc)
-{
-  octave_value retval;
-
-  octave_value_list rows (tmc.length (), octave_value ());
-
-  octave_idx_type j = 0;
-  for (octave::tm_row_const& tmrc : tmc)
-    {
-      octave_quit ();
-
-      if (tmrc.length () == 1)
-        rows(j++) = *(tmrc.begin ());
-      else
-        {
-          octave_value_list row (tmrc.length (), octave_value ());
-
-          octave_idx_type i = 0;
-          for (auto& elt : tmrc)
-            row(i++) = elt;
-
-          rows(j++) = do_class_concat (row, "horzcat", 1);
-        }
-    }
-
-  if (rows.length () == 1)
-    retval = rows(0);
-  else
-    retval = do_class_concat (rows, "vertcat", 0);
-
-  return retval;
-}
-
-namespace octave
-{
-  octave_value
-  tree_matrix::rvalue1 (int)
-  {
-    octave_value retval = Matrix ();
-
-    bool all_strings_p = false;
-    bool all_sq_strings_p = false;
-    bool all_dq_strings_p = false;
-    bool all_empty_p = false;
-    bool all_real_p = false;
-    bool any_sparse_p = false;
-    bool any_class_p = false;
-    bool frc_str_conv = false;
-
-    tm_const tmp (*this);
-
-    if (tmp && ! tmp.empty ())
-      {
-        dim_vector dv = tmp.dims ();
-        all_strings_p = tmp.all_strings_p ();
-        all_sq_strings_p = tmp.all_sq_strings_p ();
-        all_dq_strings_p = tmp.all_dq_strings_p ();
-        all_empty_p = tmp.all_empty_p ();
-        all_real_p = tmp.all_real_p ();
-        any_sparse_p = tmp.any_sparse_p ();
-        any_class_p = tmp.any_class_p ();
-        frc_str_conv = tmp.some_strings_p ();
-
-        // Try to speed up the common cases.
-
-        std::string result_type = tmp.class_name ();
-
-        if (any_class_p)
-          {
-            retval = do_class_concat (tmp);
-          }
-        else if (result_type == "double")
-          {
-            if (any_sparse_p)
-              {
-                if (all_real_p)
-                  retval = do_single_type_concat<SparseMatrix> (dv, tmp);
-                else
-                  retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp);
-              }
-            else
-              {
-                if (all_real_p)
-                  retval = do_single_type_concat<NDArray> (dv, tmp);
-                else
-                  retval = do_single_type_concat<ComplexNDArray> (dv, tmp);
-              }
-          }
-        else if (result_type == "single")
-          {
-            if (all_real_p)
-              retval = do_single_type_concat<FloatNDArray> (dv, tmp);
-            else
-              retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp);
-          }
-        else if (result_type == "char")
-          {
-            char type = all_dq_strings_p ? '"' : '\'';
-
-            if (! all_strings_p)
-              warn_implicit_conversion ("Octave:num-to-str",
-                                        "numeric", result_type);
-            else
-              maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p);
-
-            charNDArray result (dv, Vstring_fill_char);
-
-            single_type_concat<charNDArray> (result, tmp);
-
-            retval = octave_value (result, type);
-          }
-        else if (result_type == "logical")
-          {
-            if (any_sparse_p)
-              retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp);
-            else
-              retval = do_single_type_concat<boolNDArray> (dv, tmp);
-          }
-        else if (result_type == "int8")
-          retval = do_single_type_concat<int8NDArray> (dv, tmp);
-        else if (result_type == "int16")
-          retval = do_single_type_concat<int16NDArray> (dv, tmp);
-        else if (result_type == "int32")
-          retval = do_single_type_concat<int32NDArray> (dv, tmp);
-        else if (result_type == "int64")
-          retval = do_single_type_concat<int64NDArray> (dv, tmp);
-        else if (result_type == "uint8")
-          retval = do_single_type_concat<uint8NDArray> (dv, tmp);
-        else if (result_type == "uint16")
-          retval = do_single_type_concat<uint16NDArray> (dv, tmp);
-        else if (result_type == "uint32")
-          retval = do_single_type_concat<uint32NDArray> (dv, tmp);
-        else if (result_type == "uint64")
-          retval = do_single_type_concat<uint64NDArray> (dv, tmp);
-        else if (result_type == "cell")
-          retval = do_single_type_concat<Cell> (dv, tmp);
-        else if (result_type == "struct")
-          retval = do_single_type_concat<octave_map> (dv, tmp);
-        else
-          {
-            // The line below might seem crazy, since we take a copy of
-            // the first argument, resize it to be empty and then resize
-            // it to be full.  This is done since it means that there is
-            // no recopying of data, as would happen if we used a single
-            // resize.  It should be noted that resize operation is also
-            // significantly slower than the do_cat_op function, so it
-            // makes sense to have an empty matrix and copy all data.
-            //
-            // We might also start with a empty octave_value using
-            //
-            //    ctmp = octave_value_typeinfo::lookup_type
-            //          (tmp.begin() -> begin() -> type_name());
-            //
-            // and then directly resize.  However, for some types there
-            // might be some additional setup needed, and so this should
-            // be avoided.
-
-            octave_value ctmp;
-
-            // Find the first non-empty object
-
-            if (any_sparse_p)
-              {
-                // Start with sparse matrix to avoid issues memory issues
-                // with things like [ones(1,4),sprandn(1e8,4,1e-4)]
-                if (all_real_p)
-                  ctmp = octave_sparse_matrix ().resize (dv);
-                else
-                  ctmp = octave_sparse_complex_matrix ().resize (dv);
-              }
-            else
-              {
-                for (tm_row_const& row : tmp)
-                  {
-                    octave_quit ();
-
-                    for (auto& elt : row)
-                      {
-                        octave_quit ();
-
-                        ctmp = elt;
-
-                        if (! ctmp.all_zero_dims ())
-                          goto found_non_empty;
-                      }
-                  }
-
-                ctmp = (*(tmp.begin () -> begin ()));
-
-              found_non_empty:
-
-                if (! all_empty_p)
-                  ctmp = ctmp.resize (dim_vector (0,0)).resize (dv);
-              }
-
-            // Now, extract the values from the individual elements and
-            // insert them in the result matrix.
-
-            int dv_len = dv.ndims ();
-            octave_idx_type ntmp = dv_len > 1 ? dv_len : 2;
-            Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
-
-            for (tm_row_const& row : tmp)
-              {
-                octave_quit ();
-
-                for (auto& elt : row)
-                  {
-                    octave_quit ();
-
-                    if (elt.is_empty ())
-                      continue;
-
-                    ctmp = do_cat_op (ctmp, elt, ra_idx);
-
-                    ra_idx (1) += elt.columns ();
-                  }
-
-                ra_idx (0) += row.rows ();
-                ra_idx (1) = 0;
-              }
-
-            retval = ctmp;
-
-            if (frc_str_conv && ! retval.is_string ())
-              retval = retval.convert_to_str ();
-          }
-      }
-
-    return retval;
-  }
 
   tree_expression *
   tree_matrix::dup (symbol_table::scope_id scope,
@@ -1086,12 +146,6 @@
 
     return new_matrix;
   }
-
-  void
-  tree_matrix::accept (tree_walker& tw)
-  {
-    tw.visit_matrix (*this);
-  }
 }
 
 
--- a/libinterp/parse-tree/pt-mat.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-mat.h	Fri Apr 21 18:07:40 2017 -0400
@@ -33,6 +33,7 @@
 #include "base-list.h"
 #include "pt-array-list.h"
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 // The character to fill with when creating string arrays.
@@ -42,8 +43,6 @@
 {
   class tree_argument_list;
 
-  class tree_walker;
-
   // General matrices.  This allows us to construct matrices from
   // other matrices, variables, and functions.
 
@@ -67,14 +66,13 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_matrix (*this);
+    }
   };
 
   extern std::string
--- a/libinterp/parse-tree/pt-misc.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-misc.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -112,106 +112,6 @@
     return retval;
   }
 
-  void
-  tree_parameter_list::initialize_undefined_elements (const std::string& warnfor,
-                                                      int nargout,
-                                                      const octave_value& val)
-  {
-    bool warned = false;
-
-    int count = 0;
-
-    octave_value tmp = symbol_table::varval (".ignored.");
-    const Matrix ignored = tmp.is_defined () ? tmp.matrix_value () : Matrix ();
-
-    octave_idx_type k = 0;
-
-    for (tree_decl_elt* elt : *this)
-      {
-        if (++count > nargout)
-          break;
-
-        if (! elt->is_variable ())
-          {
-            if (! warned)
-              {
-                warned = true;
-
-                while (k < ignored.numel ())
-                  {
-                    octave_idx_type l = ignored (k);
-                    if (l == count)
-                      {
-                        warned = false;
-                        break;
-                      }
-                    else if (l > count)
-                      break;
-                    else
-                      k++;
-                  }
-
-                if (warned)
-                  {
-                    warning_with_id
-                      ("Octave:undefined-return-values",
-                       "%s: some elements in list of return values are undefined",
-                       warnfor.c_str ());
-                  }
-              }
-
-            octave_lvalue lval = elt->lvalue ();
-
-            lval.assign (octave_value::op_asn_eq, val);
-          }
-      }
-  }
-
-  void
-  tree_parameter_list::define_from_arg_vector (const octave_value_list& args)
-  {
-    int expected_nargin = length ();
-
-    iterator p = begin ();
-
-    for (int i = 0; i < expected_nargin; i++)
-      {
-        tree_decl_elt *elt = *p++;
-
-        octave_lvalue ref = elt->lvalue ();
-
-        if (i < args.length ())
-          {
-            if (args(i).is_defined () && args(i).is_magic_colon ())
-              {
-                if (! elt->eval ())
-                  error ("no default value for argument %d", i+1);
-              }
-            else
-              ref.define (args(i));
-          }
-        else
-          elt->eval ();
-      }
-  }
-
-  void
-  tree_parameter_list::undefine (void)
-  {
-    int len = length ();
-
-    iterator p = begin ();
-
-    for (int i = 0; i < len; i++)
-      {
-        tree_decl_elt *elt = *p++;
-
-        octave_lvalue ref = elt->lvalue ();
-
-        ref.assign (octave_value::op_asn_eq, octave_value ());
-      }
-  }
-
   std::list<std::string>
   tree_parameter_list::variable_names (void) const
   {
@@ -223,48 +123,6 @@
     return retval;
   }
 
-  octave_value_list
-  tree_parameter_list::convert_to_const_vector (int nargout,
-                                                const Cell& varargout)
-  {
-    octave_idx_type vlen = varargout.numel ();
-    int len = length ();
-
-    // Special case.  Will do a shallow copy.
-    if (len == 0)
-      return varargout;
-    else if (nargout <= len)
-      {
-        octave_value_list retval (nargout);
-
-        int i = 0;
-
-        for (tree_decl_elt* elt : *this)
-          {
-            if (elt->is_defined ())
-              retval(i++) = elt->rvalue1 ();
-            else
-              break;
-          }
-
-        return retval;
-      }
-    else
-      {
-        octave_value_list retval (len + vlen);
-
-        int i = 0;
-
-        for (tree_decl_elt* elt : *this)
-          retval(i++) = elt->rvalue1 ();
-
-        for (octave_idx_type j = 0; j < vlen; j++)
-          retval(i++) = varargout(j);
-
-        return retval;
-      }
-  }
-
   bool
   tree_parameter_list::is_defined (void)
   {
@@ -297,12 +155,6 @@
     return new_list;
   }
 
-  void
-  tree_parameter_list::accept (tree_walker& tw)
-  {
-    tw.visit_parameter_list (*this);
-  }
-
   // Return lists.
 
   tree_return_list::~tree_return_list (void)
@@ -326,10 +178,4 @@
 
     return new_list;
   }
-
-  void
-  tree_return_list::accept (tree_walker& tw)
-  {
-    tw.visit_return_list (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-misc.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-misc.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,6 +32,7 @@
 
 #include "base-list.h"
 #include "pt-decl.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
@@ -40,8 +41,6 @@
   class tree_index_expression;
   class tree_va_return_list;
 
-  class tree_walker;
-
   // Parameter lists.  Used to hold the list of input and output
   // parameters in a function definition.  Elements are identifiers
   // only.
@@ -81,24 +80,17 @@
 
     bool varargs_only (void) { return (marked_for_varargs < 0); }
 
-    void initialize_undefined_elements (const std::string& warnfor,
-                                        int nargout, const octave_value& val);
-
-    void define_from_arg_vector (const octave_value_list& args);
-
-    void undefine (void);
-
     bool is_defined (void);
 
     std::list<std::string> variable_names (void) const;
 
-    octave_value_list convert_to_const_vector (int nargout,
-                                               const Cell& varargout);
-
     tree_parameter_list *dup (symbol_table::scope_id scope,
                               symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_parameter_list (*this);
+    }
 
   private:
 
@@ -131,7 +123,10 @@
     tree_return_list *dup (symbol_table::scope_id scope,
                            symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_return_list (*this);
+    }
   };
 
   class tree_va_return_list : public octave::base_list<octave_value>
--- a/libinterp/parse-tree/pt-select.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-select.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -55,12 +55,6 @@
                                lead_comm ? lead_comm->dup () : 0);
   }
 
-  void
-  tree_if_clause::accept (tree_walker& tw)
-  {
-    tw.visit_if_clause (*this);
-  }
-
   // List of if commands.
 
   tree_if_command_list *
@@ -75,12 +69,6 @@
     return new_icl;
   }
 
-  void
-  tree_if_command_list::accept (tree_walker& tw)
-  {
-    tw.visit_if_command_list (*this);
-  }
-
   // If.
 
   tree_if_command::~tree_if_command (void)
@@ -100,12 +88,6 @@
                                 line (), column ());
   }
 
-  void
-  tree_if_command::accept (tree_walker& tw)
-  {
-    tw.visit_if_command (*this);
-  }
-
   // Switch cases.
 
   tree_switch_case::~tree_switch_case (void)
@@ -115,35 +97,6 @@
     delete lead_comm;
   }
 
-  bool
-  tree_switch_case::label_matches (const octave_value& val)
-  {
-    octave_value label_value = label->rvalue1 ();
-
-    if (label_value.is_defined ())
-      {
-        if (label_value.is_cell ())
-          {
-            Cell cell (label_value.cell_value ());
-
-            for (octave_idx_type i = 0; i < cell.rows (); i++)
-              {
-                for (octave_idx_type j = 0; j < cell.columns (); j++)
-                  {
-                    bool match = val.is_equal (cell(i,j));
-
-                    if (match)
-                      return true;
-                  }
-              }
-          }
-        else
-          return val.is_equal (label_value);
-      }
-
-    return false;
-  }
-
   tree_switch_case *
   tree_switch_case::dup (symbol_table::scope_id scope,
                          symbol_table::context_id context) const
@@ -153,12 +106,6 @@
                                  lead_comm ? lead_comm->dup () : 0);
   }
 
-  void
-  tree_switch_case::accept (tree_walker& tw)
-  {
-    tw.visit_switch_case (*this);
-  }
-
   // List of switch cases.
 
   tree_switch_case_list *
@@ -173,12 +120,6 @@
     return new_scl;
   }
 
-  void
-  tree_switch_case_list::accept (tree_walker& tw)
-  {
-    tw.visit_switch_case_list (*this);
-  }
-
   // Switch.
 
   tree_switch_command::~tree_switch_command (void)
@@ -199,10 +140,4 @@
                                     trail_comm ? trail_comm->dup () : 0,
                                     line (), column ());
   }
-
-  void
-  tree_switch_command::accept (tree_walker& tw)
-  {
-    tw.visit_switch_command (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-select.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-select.h	Fri Apr 21 18:07:40 2017 -0400
@@ -28,6 +28,7 @@
 #include "base-list.h"
 #include "comment-list.h"
 #include "pt-cmd.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
@@ -35,8 +36,6 @@
   class tree_expression;
   class tree_statement_list;
 
-  class tree_walker;
-
   // If.
 
   class tree_if_clause : public tree
@@ -74,7 +73,10 @@
     tree_if_clause *dup (symbol_table::scope_id scope,
                          symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_if_clause (*this);
+    }
 
   private:
 
@@ -115,7 +117,10 @@
     tree_if_command_list *dup (symbol_table::scope_id scope,
                                symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_if_command_list (*this);
+    }
   };
 
   class tree_if_command : public tree_command
@@ -146,7 +151,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_if_command (*this);
+    }
 
   private:
 
@@ -188,8 +196,6 @@
 
     bool is_default_case (void) { return ! label; }
 
-    bool label_matches (const octave_value& val);
-
     tree_expression *case_label (void) { return label; }
 
     tree_statement_list *commands (void) { return list; }
@@ -199,7 +205,10 @@
     tree_switch_case *dup (symbol_table::scope_id scope,
                            symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_switch_case (*this);
+    }
 
   private:
 
@@ -240,7 +249,10 @@
     tree_switch_case_list *dup (symbol_table::scope_id scope,
                                 symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_switch_case_list (*this);
+    }
   };
 
   class tree_switch_command : public tree_command
@@ -276,7 +288,10 @@
     tree_command *dup (symbol_table::scope_id scope,
                        symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_switch_command (*this);
+    }
 
   private:
 
--- a/libinterp/parse-tree/pt-stmt.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-stmt.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -182,12 +182,6 @@
     return new_stmt;
   }
 
-  void
-  tree_statement::accept (tree_walker& tw)
-  {
-    tw.visit_statement (*this);
-  }
-
   // Create a "breakpoint" tree-walker, and get it to "walk" this statement list
   // (FIXME: What does that do???)
   int
@@ -316,10 +310,4 @@
 
     return new_list;
   }
-
-  void
-  tree_statement_list::accept (tree_walker& tw)
-  {
-    tw.visit_statement_list (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-stmt.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-stmt.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,16 +32,15 @@
 #include "base-list.h"
 #include "bp-table.h"
 #include "comment-list.h"
+#include "pt.h"
+#include "pt-walk.h"
 #include "symtab.h"
-#include "pt.h"
 
 namespace octave
 {
   class tree_command;
   class tree_expression;
 
-  class tree_walker;
-
   // A statement is either a command to execute or an expression to
   // evaluate.
 
@@ -111,7 +110,10 @@
     tree_statement *dup (symbol_table::scope_id scope,
                          symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_statement (*this);
+    }
 
   private:
 
@@ -186,7 +188,10 @@
     tree_statement_list *dup (symbol_table::scope_id scope,
                               symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_statement_list (*this);
+    }
 
   private:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-tm-const.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -0,0 +1,402 @@
+/*
+
+Copyright (C) 1996-2017 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/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <iostream>
+
+#include "oct-locbuf.h"
+#include "quit.h"
+
+#include "data.h"
+#include "defun.h"
+#include "error.h"
+#include "errwarn.h"
+#include "oct-map.h"
+#include "ovl.h"
+#include "pt-arg-list.h"
+#include "pt-bp.h"
+#include "pt-eval.h"
+#include "pt-exp.h"
+#include "pt-mat.h"
+#include "pt-tm-const.h"
+#include "utils.h"
+#include "ov.h"
+#include "variables.h"
+
+#include "ov-cx-mat.h"
+#include "ov-flt-cx-mat.h"
+#include "ov-re-sparse.h"
+#include "ov-cx-sparse.h"
+
+OCTAVE_NORETURN static
+void
+eval_error (const char *msg, const dim_vector& x, const dim_vector& y)
+{
+  error ("%s (%s vs %s)", msg, x.str ().c_str (), y.str ().c_str ());
+}
+
+namespace octave
+{
+  void
+  tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val,
+                                                   bool& first_elem)
+  {
+    std::string this_elt_class_nm
+      = val.is_object () ? std::string ("class") : val.class_name ();
+
+    class_nm = get_concat_class (class_nm, this_elt_class_nm);
+
+    dim_vector this_elt_dv = val.dims ();
+
+    if (! this_elt_dv.zero_by_zero ())
+      {
+        all_mt = false;
+
+        if (first_elem)
+          {
+            if (val.is_map ())
+              first_elem_is_struct = true;
+
+            first_elem = false;
+          }
+      }
+
+    append (val);
+
+    if (all_str && ! val.is_string ())
+      all_str = false;
+
+    if (all_sq_str && ! val.is_sq_string ())
+      all_sq_str = false;
+
+    if (all_dq_str && ! val.is_dq_string ())
+      all_dq_str = false;
+
+    if (! some_str && val.is_string ())
+      some_str = true;
+
+    if (all_real && ! val.is_real_type ())
+      all_real = false;
+
+    if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ()))
+      all_cmplx = false;
+
+    if (! any_cell && val.is_cell ())
+      any_cell = true;
+
+    if (! any_sparse && val.is_sparse_type ())
+      any_sparse = true;
+
+    if (! any_class && val.is_object ())
+      any_class = true;
+
+    // Special treatment of sparse matrices to avoid out-of-memory error
+    all_1x1 = all_1x1 && ! val.is_sparse_type () && val.numel () == 1;
+  }
+
+  void
+  tm_row_const::tm_row_const_rep::init (const tree_argument_list& row,
+                                        tree_evaluator *tw)
+  {
+    all_str = true;
+    all_sq_str = true;
+    all_dq_str = true;
+    all_real = true;
+    all_cmplx = true;
+    any_cell = false;
+    any_sparse = false;
+    any_class = false;
+
+    bool first_elem = true;
+
+    for (tree_expression* elt : row)
+      {
+        octave_quit ();
+
+        octave_value tmp = tw->evaluate (elt);
+
+        if (tmp.is_undefined ())
+          {
+            ok = true;
+            return;
+          }
+        else
+          {
+            if (tmp.is_cs_list ())
+              {
+                octave_value_list tlst = tmp.list_value ();
+
+                for (octave_idx_type i = 0; i < tlst.length (); i++)
+                  {
+                    octave_quit ();
+
+                    do_init_element (tlst(i), first_elem);
+                  }
+              }
+            else
+              do_init_element (tmp, first_elem);
+          }
+      }
+
+    if (any_cell && ! any_class && ! first_elem_is_struct)
+      cellify ();
+
+    first_elem = true;
+
+    for (const octave_value& val : *this)
+      {
+        octave_quit ();
+
+        dim_vector this_elt_dv = val.dims ();
+
+        if (! this_elt_dv.zero_by_zero ())
+          {
+            all_mt = false;
+
+            if (first_elem)
+              {
+                first_elem = false;
+                dv = this_elt_dv;
+              }
+            else if ((! any_class) && (! dv.hvcat (this_elt_dv, 1)))
+              eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
+          }
+      }
+
+    ok = true;
+  }
+
+  void
+  tm_row_const::tm_row_const_rep::cellify (void)
+  {
+    bool elt_changed = false;
+
+    for (auto& elt : *this)
+      {
+        octave_quit ();
+
+        if (! elt.is_cell ())
+          {
+            elt_changed = true;
+
+            if (elt.is_empty ())
+              elt = Cell ();
+            else
+              elt = Cell (elt);
+          }
+      }
+
+    if (elt_changed)
+      {
+        bool first_elem = true;
+
+        for (const octave_value& val : *this)
+          {
+            octave_quit ();
+
+            dim_vector this_elt_dv = val.dims ();
+
+            if (! this_elt_dv.zero_by_zero ())
+              {
+                if (first_elem)
+                  {
+                    first_elem = false;
+                    dv = this_elt_dv;
+                  }
+                else if (! dv.hvcat (this_elt_dv, 1))
+                  eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
+              }
+          }
+      }
+  }
+
+  void
+  tm_const::init (const tree_matrix& tm, tree_evaluator *tw)
+  {
+    all_str = true;
+    all_sq_str = true;
+    all_dq_str = true;
+    all_real = true;
+    all_cmplx = true;
+    any_cell = false;
+    any_sparse = false;
+    any_class = false;
+    all_1x1 = ! tm.empty ();
+
+    bool first_elem = true;
+    bool first_elem_is_struct = false;
+
+    // Just eval and figure out if what we have is complex or all strings.
+    // We can't check columns until we know that this is a numeric matrix --
+    // collections of strings can have elements of different lengths.
+    for (const tree_argument_list* elt : tm)
+      {
+        octave_quit ();
+
+        tm_row_const tmp (*elt, tw);
+
+        if (first_elem)
+          {
+            first_elem_is_struct = tmp.first_elem_struct_p ();
+
+            first_elem = false;
+          }
+
+        if (tmp && ! tmp.empty ())
+          {
+            if (all_str && ! tmp.all_strings_p ())
+              all_str = false;
+
+            if (all_sq_str && ! tmp.all_sq_strings_p ())
+              all_sq_str = false;
+
+            if (all_dq_str && ! tmp.all_dq_strings_p ())
+              all_dq_str = false;
+
+            if (! some_str && tmp.some_strings_p ())
+              some_str = true;
+
+            if (all_real && ! tmp.all_real_p ())
+              all_real = false;
+
+            if (all_cmplx && ! tmp.all_complex_p ())
+              all_cmplx = false;
+
+            if (all_mt && ! tmp.all_empty_p ())
+              all_mt = false;
+
+            if (! any_cell && tmp.any_cell_p ())
+              any_cell = true;
+
+            if (! any_sparse && tmp.any_sparse_p ())
+              any_sparse = true;
+
+            if (! any_class && tmp.any_class_p ())
+              any_class = true;
+
+            all_1x1 = all_1x1 && tmp.all_1x1_p ();
+
+            append (tmp);
+          }
+        else
+          break;
+      }
+
+    if (any_cell && ! any_class && ! first_elem_is_struct)
+      {
+        for (auto& elt : *this)
+          {
+            octave_quit ();
+
+            elt.cellify ();
+          }
+      }
+
+    first_elem = true;
+
+    for (tm_row_const& elt : *this)
+      {
+        octave_quit ();
+
+        octave_idx_type this_elt_nr = elt.rows ();
+        octave_idx_type this_elt_nc = elt.cols ();
+
+        std::string this_elt_class_nm = elt.class_name ();
+        class_nm = get_concat_class (class_nm, this_elt_class_nm);
+
+        dim_vector this_elt_dv = elt.dims ();
+
+        all_mt = false;
+
+        if (first_elem)
+          {
+            first_elem = false;
+
+            dv = this_elt_dv;
+          }
+        else if (all_str && dv.ndims () == 2
+                 && this_elt_dv.ndims () == 2)
+          {
+            // FIXME: this is Octave's specialty.
+            // Character matrices allow rows of unequal length.
+            if (this_elt_nc > cols ())
+              dv(1) = this_elt_nc;
+            dv(0) += this_elt_nr;
+          }
+        else if ((! any_class) && (! dv.hvcat (this_elt_dv, 0)))
+          eval_error ("vertical dimensions mismatch", dv, this_elt_dv);
+      }
+
+    ok = true;
+  }
+
+  template <>
+  octave_value
+  do_single_type_concat<octave_map> (const dim_vector& dv,
+                                     octave::tm_const& tmp)
+  {
+    octave_map result;
+
+    if (tmp.all_1x1_p ())
+      single_type_concat<octave_scalar_map> (result, dv, tmp);
+    else
+      single_type_concat<octave_map> (result, dv, tmp);
+
+    return result;
+  }
+
+  octave_value do_class_concat (octave::tm_const& tmc)
+  {
+    octave_value retval;
+
+    octave_value_list rows (tmc.length (), octave_value ());
+
+    octave_idx_type j = 0;
+    for (octave::tm_row_const& tmrc : tmc)
+      {
+        octave_quit ();
+
+        if (tmrc.length () == 1)
+          rows(j++) = *(tmrc.begin ());
+        else
+          {
+            octave_value_list row (tmrc.length (), octave_value ());
+
+            octave_idx_type i = 0;
+            for (auto& elt : tmrc)
+              row(i++) = elt;
+
+            rows(j++) = do_class_concat (row, "horzcat", 1);
+          }
+      }
+
+    if (rows.length () == 1)
+      retval = rows(0);
+    else
+      retval = do_class_concat (rows, "vertcat", 0);
+
+    return retval;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/parse-tree/pt-tm-const.h	Fri Apr 21 18:07:40 2017 -0400
@@ -0,0 +1,435 @@
+/*
+
+Copyright (C) 1996-2017 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/>.
+
+*/
+
+#if ! defined (octave_pt_tm_const_h)
+#define octave_pt_tm_const_h 1
+
+#include "octave-config.h"
+
+#include <string>
+
+#include "Array.h"
+#include "Sparse.h"
+#include "base-list.h"
+
+#include "data.h"
+#include "dim-vector.h"
+#include "oct-map.h"
+#include "ov.h"
+#include "ovl.h"
+
+namespace octave
+{
+  class tree_evaluator;
+
+  // General matrices.  This list type is much more work to handle than
+  // constant matrices, but it allows us to construct matrices from
+  // other matrices, variables, and functions.
+
+  // But first, some internal classes that make our job much easier.
+
+  class
+  tm_row_const
+  {
+  private:
+
+    class
+    tm_row_const_rep : public octave::base_list<octave_value>
+    {
+    public:
+
+      tm_row_const_rep (void)
+        : count (1), dv (0, 0), all_str (false),
+          all_sq_str (false), all_dq_str (false),
+          some_str (false), all_real (false), all_cmplx (false),
+          all_mt (true), any_cell (false), any_sparse (false),
+          any_class (false), all_1x1 (false),
+          first_elem_is_struct (false), class_nm (), ok (false)
+      { }
+
+      tm_row_const_rep (const tree_argument_list& row, tree_evaluator *tw)
+        : count (1), dv (0, 0), all_str (false), all_sq_str (false),
+          some_str (false), all_real (false), all_cmplx (false),
+          all_mt (true), any_cell (false), any_sparse (false),
+          any_class (false), all_1x1 (! row.empty ()),
+          first_elem_is_struct (false), class_nm (), ok (false)
+      { init (row, tw); }
+
+      ~tm_row_const_rep (void) = default;
+
+      octave::refcount<int> count;
+
+      dim_vector dv;
+
+      bool all_str;
+      bool all_sq_str;
+      bool all_dq_str;
+      bool some_str;
+      bool all_real;
+      bool all_cmplx;
+      bool all_mt;
+      bool any_cell;
+      bool any_sparse;
+      bool any_class;
+      bool all_1x1;
+      bool first_elem_is_struct;
+
+      std::string class_nm;
+
+      bool ok;
+
+      void do_init_element (const octave_value&, bool&);
+
+      void init (const tree_argument_list&, tree_evaluator *tw);
+
+      void cellify (void);
+
+    private:
+
+      tm_row_const_rep (const tm_row_const_rep&);
+
+      tm_row_const_rep& operator = (const tm_row_const_rep&);
+
+    };
+
+  public:
+
+    typedef tm_row_const_rep::iterator iterator;
+    typedef tm_row_const_rep::const_iterator const_iterator;
+
+    tm_row_const (void)
+      : rep (0) { }
+
+    tm_row_const (const tree_argument_list& row, tree_evaluator *tw)
+      : rep (new tm_row_const_rep (row, tw)) { }
+
+    tm_row_const (const tm_row_const& x)
+      : rep (x.rep)
+    {
+      if (rep)
+        rep->count++;
+    }
+
+    tm_row_const& operator = (const tm_row_const& x)
+    {
+      if (this != &x && rep != x.rep)
+        {
+          if (rep && --rep->count == 0)
+            delete rep;
+
+          rep = x.rep;
+
+          if (rep)
+            rep->count++;
+        }
+
+      return *this;
+    }
+
+    ~tm_row_const (void)
+    {
+      if (rep && --rep->count == 0)
+        delete rep;
+    }
+
+    octave_idx_type rows (void) { return rep->dv(0); }
+    octave_idx_type cols (void) { return rep->dv(1); }
+
+    bool empty (void) const { return rep->empty (); }
+
+    size_t length (void) const { return rep->length (); }
+
+    dim_vector dims (void) { return rep->dv; }
+
+    bool all_strings_p (void) const { return rep->all_str; }
+    bool all_sq_strings_p (void) const { return rep->all_sq_str; }
+    bool all_dq_strings_p (void) const { return rep->all_dq_str; }
+    bool some_strings_p (void) const { return rep->some_str; }
+    bool all_real_p (void) const { return rep->all_real; }
+    bool all_complex_p (void) const { return rep->all_cmplx; }
+    bool all_empty_p (void) const { return rep->all_mt; }
+    bool any_cell_p (void) const { return rep->any_cell; }
+    bool any_sparse_p (void) const { return rep->any_sparse; }
+    bool any_class_p (void) const { return rep->any_class; }
+    bool all_1x1_p (void) const { return rep->all_1x1; }
+    bool first_elem_struct_p (void) const { return rep->first_elem_is_struct; }
+
+    std::string class_name (void) const { return rep->class_nm; }
+
+    void cellify (void) { rep->cellify (); }
+
+    operator bool () const { return (rep && rep->ok); }
+
+    iterator begin (void) { return rep->begin (); }
+    const_iterator begin (void) const { return rep->begin (); }
+
+    iterator end (void) { return rep->end (); }
+    const_iterator end (void) const { return rep->end (); }
+
+  private:
+
+    tm_row_const_rep *rep;
+  };
+
+  class
+  tm_const : public octave::base_list<tm_row_const>
+  {
+  public:
+
+    tm_const (const tree_matrix& tm, tree_evaluator *tw = 0)
+      : dv (0, 0), all_str (false), all_sq_str (false),
+        all_dq_str (false),
+        some_str (false), all_real (false), all_cmplx (false),
+        all_mt (true), any_cell (false), any_sparse (false),
+        any_class (false), class_nm (), ok (false)
+    { init (tm, tw); }
+
+    ~tm_const (void) = default;
+
+    octave_idx_type rows (void) const { return dv.elem (0); }
+    octave_idx_type cols (void) const { return dv.elem (1); }
+
+    dim_vector dims (void) const { return dv; }
+
+    bool all_strings_p (void) const { return all_str; }
+    bool all_sq_strings_p (void) const { return all_sq_str; }
+    bool all_dq_strings_p (void) const { return all_dq_str; }
+    bool some_strings_p (void) const { return some_str; }
+    bool all_real_p (void) const { return all_real; }
+    bool all_complex_p (void) const { return all_cmplx; }
+    bool all_empty_p (void) const { return all_mt; }
+    bool any_cell_p (void) const { return any_cell; }
+    bool any_sparse_p (void) const { return any_sparse; }
+    bool any_class_p (void) const { return any_class; }
+    bool all_1x1_p (void) const { return all_1x1; }
+
+    std::string class_name (void) const { return class_nm; }
+
+    operator bool () const { return ok; }
+
+  private:
+
+    dim_vector dv;
+
+    bool all_str;
+    bool all_sq_str;
+    bool all_dq_str;
+    bool some_str;
+    bool all_real;
+    bool all_cmplx;
+    bool all_mt;
+    bool any_cell;
+    bool any_sparse;
+    bool any_class;
+    bool all_1x1;
+
+    std::string class_nm;
+
+    bool ok;
+
+    tm_const (void);
+
+    tm_const (const tm_const&);
+
+    tm_const& operator = (const tm_const&);
+
+    void init (const tree_matrix& tm, tree_evaluator *tw);
+  };
+
+  template <typename TYPE, typename T>
+  void
+  single_type_concat (Array<T>& result, octave::tm_const& tmp)
+  {
+    octave_idx_type r = 0;
+    octave_idx_type c = 0;
+
+    for (octave::tm_row_const& row : tmp)
+      {
+        // Skip empty arrays to allow looser rules.
+        if (row.dims ().any_zero ())
+          continue;
+
+        for (auto& elt : row)
+          {
+            octave_quit ();
+
+            TYPE ra = octave_value_extract<TYPE> (elt);
+
+            // Skip empty arrays to allow looser rules.
+
+            if (! ra.is_empty ())
+              {
+                result.insert (ra, r, c);
+
+                c += ra.columns ();
+              }
+          }
+
+        r += row.rows ();
+        c = 0;
+      }
+  }
+
+  template <typename TYPE, typename T>
+  void
+  single_type_concat (Array<T>& result, const dim_vector& dv,
+                      octave::tm_const& tmp)
+  {
+    if (dv.any_zero ())
+      {
+        result = Array<T> (dv);
+        return;
+      }
+
+    if (tmp.length () == 1)
+      {
+        // If possible, forward the operation to liboctave.
+        // Single row.
+        octave::tm_row_const& row = tmp.front ();
+        if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value)
+            && row.all_1x1_p ())
+          {
+            // Optimize all scalars case.
+            result.clear (dv);
+            assert (static_cast<size_t> (result.numel ()) == row.length ());
+            octave_idx_type i = 0;
+            for (const auto& elt : row)
+              result(i++) = octave_value_extract<T> (elt);
+
+            return;
+          }
+
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
+
+        for (const auto& elt : row)
+          {
+            octave_quit ();
+
+            array_list[i++] = octave_value_extract<TYPE> (elt);
+          }
+
+        result = Array<T>::cat (-2, ncols, array_list);
+      }
+    else
+      {
+        result = Array<T> (dv);
+        single_type_concat<TYPE> (result, tmp);
+      }
+  }
+
+  template <typename TYPE, typename T>
+  void
+  single_type_concat (Sparse<T>& result, const dim_vector& dv,
+                      octave::tm_const& tmp)
+  {
+    if (dv.any_zero ())
+      {
+        result = Sparse<T> (dv);
+        return;
+      }
+
+    // Sparse matrices require preallocation for efficient indexing; besides,
+    // only horizontal concatenation can be efficiently handled by indexing.
+    // So we just cat all rows through liboctave, then cat the final column.
+    octave_idx_type nrows = tmp.length ();
+    octave_idx_type j = 0;
+    OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows);
+    for (octave::tm_row_const& row : tmp)
+      {
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols);
+
+        for (auto& elt : row)
+          {
+            octave_quit ();
+
+            sparse_list[i] = octave_value_extract<TYPE> (elt);
+            i++;
+          }
+
+        Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list);
+        sparse_row_list[j] = stmp;
+        j++;
+      }
+
+    result = Sparse<T>::cat (-1, nrows, sparse_row_list);
+  }
+
+  template <typename MAP>
+  void
+  single_type_concat (octave_map& result, const dim_vector& dv,
+                      octave::tm_const& tmp)
+  {
+    if (dv.any_zero ())
+      {
+        result = octave_map (dv);
+        return;
+      }
+
+    octave_idx_type nrows = tmp.length ();
+    octave_idx_type j = 0;
+    OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
+    for (octave::tm_row_const& row : tmp)
+      {
+        octave_idx_type ncols = row.length ();
+        octave_idx_type i = 0;
+        OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
+
+        for (auto& elt : row)
+          {
+            octave_quit ();
+
+            map_list[i] = octave_value_extract<MAP> (elt);
+            i++;
+          }
+
+        octave_map mtmp = octave_map::cat (-2, ncols, map_list);
+        map_row_list[j] = mtmp;
+        j++;
+      }
+
+    result = octave_map::cat (-1, nrows, map_row_list);
+  }
+
+  template <typename TYPE>
+  octave_value
+  do_single_type_concat (const dim_vector& dv, octave::tm_const& tmp)
+  {
+    TYPE result;
+
+    single_type_concat<TYPE> (result, dv, tmp);
+
+    return result;
+  }
+
+  template <>
+  octave_value
+  do_single_type_concat<octave_map> (const dim_vector& dv,
+                                     octave::tm_const& tmp);
+
+  extern octave_value do_class_concat (octave::tm_const& tmc);
+}
+
+#endif
--- a/libinterp/parse-tree/pt-unop.cc	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-unop.cc	Fri Apr 21 18:07:40 2017 -0400
@@ -45,62 +45,6 @@
 
   // Prefix expressions.
 
-  octave_value_list
-  tree_prefix_expression::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("prefix operator '%s': invalid number of output arguments",
-             oper ().c_str ());
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
-  octave_value
-  tree_prefix_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (op)
-      {
-        if (etype == octave_value::op_incr || etype == octave_value::op_decr)
-          {
-            octave_lvalue ref = op->lvalue ();
-
-            BEGIN_PROFILER_BLOCK (tree_prefix_expression)
-
-              ref.do_unary_op (etype);
-
-            retval = ref.value ();
-
-            END_PROFILER_BLOCK
-              }
-        else
-          {
-            octave_value val = op->rvalue1 ();
-
-            if (val.is_defined ())
-              {
-                BEGIN_PROFILER_BLOCK (tree_prefix_expression)
-
-                  // Attempt to do the operation in-place if it is unshared
-                  // (a temporary expression).
-                  if (val.get_count () == 1)
-                    retval = val.do_non_const_unary_op (etype);
-                  else
-                    retval = ::do_unary_op (etype, val);
-
-                END_PROFILER_BLOCK
-                  }
-          }
-      }
-
-    return retval;
-  }
-
   tree_expression *
   tree_prefix_expression::dup (symbol_table::scope_id scope,
                                symbol_table::context_id context) const
@@ -114,65 +58,8 @@
     return new_pe;
   }
 
-  void
-  tree_prefix_expression::accept (tree_walker& tw)
-  {
-    tw.visit_prefix_expression (*this);
-  }
-
   // Postfix expressions.
 
-  octave_value_list
-  tree_postfix_expression::rvalue (int nargout)
-  {
-    octave_value_list retval;
-
-    if (nargout > 1)
-      error ("postfix operator '%s': invalid number of output arguments",
-             oper ().c_str ());
-
-    retval = rvalue1 (nargout);
-
-    return retval;
-  }
-
-  octave_value
-  tree_postfix_expression::rvalue1 (int)
-  {
-    octave_value retval;
-
-    if (op)
-      {
-        if (etype == octave_value::op_incr || etype == octave_value::op_decr)
-          {
-            octave_lvalue ref = op->lvalue ();
-
-            retval = ref.value ();
-
-            BEGIN_PROFILER_BLOCK (tree_postfix_expression)
-
-              ref.do_unary_op (etype);
-
-            END_PROFILER_BLOCK
-              }
-        else
-          {
-            octave_value val = op->rvalue1 ();
-
-            if (val.is_defined ())
-              {
-                BEGIN_PROFILER_BLOCK (tree_postfix_expression)
-
-                  retval = ::do_unary_op (etype, val);
-
-                END_PROFILER_BLOCK
-                  }
-          }
-      }
-
-    return retval;
-  }
-
   tree_expression *
   tree_postfix_expression::dup (symbol_table::scope_id scope,
                                 symbol_table::context_id context) const
@@ -185,10 +72,4 @@
 
     return new_pe;
   }
-
-  void
-  tree_postfix_expression::accept (tree_walker& tw)
-  {
-    tw.visit_postfix_expression (*this);
-  }
 }
--- a/libinterp/parse-tree/pt-unop.h	Mon Apr 24 21:03:38 2017 -0700
+++ b/libinterp/parse-tree/pt-unop.h	Fri Apr 21 18:07:40 2017 -0400
@@ -32,12 +32,11 @@
 class octave_lvalue;
 
 #include "pt-exp.h"
+#include "pt-walk.h"
 #include "symtab.h"
 
 namespace octave
 {
-  class tree_walker;
-
   // Unary expressions.
 
   class tree_unary_expression : public tree_expression
@@ -107,14 +106,13 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_prefix_expression (*this);
+    }
 
     std::string profiler_name (void) const { return "prefix " + oper (); }
   };
@@ -143,14 +141,13 @@
 
     bool rvalue_ok (void) const { return true; }
 
-    octave_value rvalue1 (int nargout = 1);
-
-    octave_value_list rvalue (int nargout);
-
     tree_expression *dup (symbol_table::scope_id scope,
                           symbol_table::context_id context) const;
 
-    void accept (tree_walker& tw);
+    void accept (tree_walker& tw)
+    {
+      tw.visit_postfix_expression (*this);
+    }
 
     std::string profiler_name (void) const { return "postfix " + oper (); }
   };