Mercurial > octave
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.
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 (); } };