diff libinterp/parse-tree/pt-idx.cc @ 28804:3719f5d452d4 stable

refactor implementation of END indexing in interpreter (bug #58953) * oct-lvalue.h, oct-lvalue.cc (octave_lvalue::eval_for_numel): New function. (octave_lvalue::m_nel): Delete data member. (octave_lvalue::numel (octave_idx_type)): Delete. (octave_lvalue::numel (void) const): Compute result instead of returning cached value. * pt-eval.h, pt-eval.cc (tree_evaluator::convert_to_const_vector): Simplify. (Fend): Call tree_evaluator::evaluate_end_expression to do the real work. (tree_evaluator::make_value_list): Don't check for magic_end here. (end_value, tree_evaluator::evaluate_end_expression): New functions. (tree_evaluator::m_index_list, tree_evaluator::m_index_type): New data members. (tree_evaluator::set_indexed_object, tree_evaluator::index_list, tree_evaluator::set_index_list, tree_evaluator::clear_index_list, tree_evaluator::append_index_list, tree_evaluator::index_type): New functions. * pt-idx.cc (make_value_list): Delete. (tree_index_expression::lvalue, tree_index_expression::evaluate_n): Refactor to avoid evaluating partial expressions to obtain values for the END function. Instead, cache info necessary to do that job as needed and inside the END function itself.
author John W. Eaton <jwe@octave.org> and Fernando Alvarruiz
date Mon, 21 Sep 2020 10:45:18 -0400
parents 0a4dcea2987a
children 2219b0ed8754
line wrap: on
line diff
--- a/libinterp/parse-tree/pt-idx.cc	Sun Sep 27 12:24:24 2020 -0400
+++ b/libinterp/parse-tree/pt-idx.cc	Mon Sep 21 10:45:18 2020 -0400
@@ -147,40 +147,6 @@
     return m_expr->name ();
   }
 
-  static inline octave_value_list
-  make_value_list (tree_evaluator& tw,
-                   tree_argument_list *m_args,
-                   const string_vector& m_arg_nm, const octave_value& object,
-                   bool rvalue = true)
-  {
-    // FIXME: This function duplicates tree_evaluator::make_value_list.
-    // See also the way convert_to_const_vector is used in
-    // tree_index_expression::evaluate_n.
-
-    octave_value_list retval;
-
-    if (m_args)
-      {
-        unwind_action act ([&tw] (const std::list<octave_lvalue> *lvl)
-                           {
-                             tw.set_lvalue_list (lvl);
-                           }, tw.lvalue_list ());
-        tw.set_lvalue_list (nullptr);
-
-        if (rvalue && m_args->has_magic_end () && object.is_undefined ())
-          err_invalid_inquiry_subscript ();
-
-        retval = tw.convert_to_const_vector (m_args, object);
-      }
-
-    octave_idx_type n = retval.length ();
-
-    if (n > 0)
-      retval.stash_name_tags (m_arg_nm);
-
-    return retval;
-  }
-
   std::string
   tree_index_expression::get_struct_index
   (tree_evaluator& tw,
@@ -210,7 +176,6 @@
   tree_index_expression::lvalue (tree_evaluator& tw)
   {
     std::list<octave_value_list> idx;
-    std::string tmp_type;
 
     int n = m_args.size ();
 
@@ -220,73 +185,37 @@
 
     octave_lvalue retval = m_expr->lvalue (tw);
 
-    octave_value tmp = retval.value ();
+    unwind_action
+      act ([&tw] (const octave_value& val,
+                  const std::string& index_type,
+                  const std::list<octave_value_list>& index_list)
+           {
+             tw.set_indexed_object (val);
+             tw.set_index_list (index_type, index_list);
+           }, tw.indexed_object (), tw.index_type (), tw.index_list ());
 
-    octave_idx_type tmpi = 0;
-    std::list<octave_value_list> tmpidx;
+    tw.set_indexed_object (retval.value ());
+    tw.clear_index_list ();
 
     for (int i = 0; i < n; i++)
       {
-        if (retval.numel () != 1)
-          err_indexed_cs_list ();
-
-        if (tmpi < i)
-          {
-            try
-              {
-                tmp = tmp.subsref (m_type.substr (tmpi, i-tmpi), tmpidx, true);
-              }
-            catch (index_exception& e)  // problems with range, invalid type etc.
-              {
-                tw.final_index_error (e, m_expr);
-              }
-
-            tmpidx.clear ();
-          }
-
         switch (m_type[i])
           {
           case '(':
             {
-              octave_value_list tidx
-                = make_value_list (tw, *p_args, *p_arg_nm, tmp, false);
-
-              idx.push_back (tidx);
+              octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
 
-              if (i < n - 1)
-                {
-                  if (m_type[i+1] != '.')
-                    error ("() must be followed by . or close the index chain");
-
-                  tmpidx.push_back (tidx);
-                  tmpi = i+1;
-                }
+              tw.append_index_list ('(', tidx);
+              idx.push_back (tidx);
             }
             break;
 
           case '{':
             {
-              octave_value_list tidx
-                = make_value_list (tw, *p_args, *p_arg_nm, tmp, false);
-
-              if (tmp.is_undefined ())
-                {
-                  if (tidx.has_magic_colon ())
-                    err_invalid_inquiry_subscript ();
+              octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
 
-                  tmp = Cell ();
-                }
-              else if (tmp.is_zero_by_zero ()
-                       && (tmp.is_matrix_type () || tmp.is_string ()))
-                {
-                  tmp = Cell ();
-                }
-
-              retval.numel (tmp.xnumel (tidx));
-
+              tw.append_index_list ('{', tidx);
               idx.push_back (tidx);
-              tmpidx.push_back (tidx);
-              tmpi = i;
             }
             break;
 
@@ -294,47 +223,7 @@
             {
               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 ()
-                                   || tmp.iscell ()));
-
-              if (i > 0 && m_type[i-1] == '(')
-                {
-                  octave_value_list pidx = idx.back ();
-
-                  // Use octave_map, not octave_scalar_map so that the
-                  // dimensions are 0x0, not 1x1.
-                  if (tmp.is_undefined ())
-                    {
-                      if (pidx.has_magic_colon ())
-                        err_invalid_inquiry_subscript ();
-
-                      tmp = octave_map ();
-                    }
-                  else if (autoconv)
-                    tmp = octave_map ();
-
-                  retval.numel (tmp.xnumel (pidx));
-
-                  tmpi = i-1;
-                  tmpidx.push_back (tidx);
-                }
-              else
-                {
-                  if (tmp.is_undefined () || autoconv)
-                    {
-                      tmpi = i+1;
-                      tmp = octave_value ();
-                    }
-                  else
-                    {
-                      retval.numel (tmp.xnumel (octave_value_list ()));
-
-                      tmpi = i;
-                      tmpidx.push_back (tidx);
-                    }
-                }
-
+              tw.append_index_list ('.', tidx);
               idx.push_back (tidx);
             }
             break;
@@ -573,102 +462,127 @@
     // files in a +packagename folder, they will also be an
     // octave_classdef_meta object, but we don't want to index them.
 
-    bool indexing_object = (base_expr_val.isobject ()
-                            || base_expr_val.isjava ()
-                            || (base_expr_val.is_classdef_meta ()
-                                && ! base_expr_val.is_package ()));
-
     std::list<octave_value_list> idx_list;
 
-    octave_value partial_expr_val = base_expr_val;
-
-    for (int i = beg; i < n; i++)
-      {
-        if (i > beg)
-          {
-            tree_argument_list *al = *p_args;
+    {
+      // Note: need new scope so that the following unwind action will
+      // happen before we perform the final indexing for objects (for
+      // example).
 
-            if (! indexing_object || (al && al->has_magic_end ()))
-              {
-                // Evaluate what we have so far to find the value to
-                // pass to the END function.
+      unwind_action
+        act ([&tw] (const octave_value& val,
+                    const std::string& index_type,
+                    const std::list<octave_value_list>& index_list)
+             {
+               tw.set_indexed_object (val);
+               tw.set_index_list (index_type, index_list);
+             },
+             tw.indexed_object (),
+             tw.index_type (), tw.index_list ());
 
-                try
-                  {
-                    // Silently ignore extra output values.
+      tw.set_indexed_object ();
+      tw.clear_index_list ();
 
-                    octave_value_list tmp_list
-                      = base_expr_val.subsref (m_type.substr (beg, i-beg),
-                                               idx_list, nargout);
+      bool indexing_object = (base_expr_val.isobject ()
+                              || base_expr_val.isjava ()
+                              || (base_expr_val.is_classdef_meta ()
+                                  && ! base_expr_val.is_package ()));
+
+      octave_value partial_expr_val = base_expr_val;
 
-                    partial_expr_val
-                      = tmp_list.length () ? tmp_list(0) : octave_value ();
+      for (int i = beg; i < n; i++)
+        {
+          if (i > beg)
+            {
+              if (! indexing_object)
+                {
+                  // Evaluate what we have so far.
 
-                    if (! indexing_object)
-                      {
-                        base_expr_val = partial_expr_val;
-
-                        if (partial_expr_val.is_cs_list ())
-                          err_indexed_cs_list ();
-
-                        retval = partial_expr_val;
+                  try
+                    {
+                      // Silently ignore extra output values.
 
-                        beg = i;
-                        idx_list.clear ();
+                      octave_value_list tmp_list
+                        = base_expr_val.subsref (m_type.substr (beg, i-beg),
+                                                 idx_list, nargout);
+
+                      partial_expr_val
+                        = tmp_list.length () ? tmp_list(0) : octave_value ();
+
+                      base_expr_val = partial_expr_val;
 
-                        if (partial_expr_val.isobject ()
-                            || partial_expr_val.isjava ()
-                            || (partial_expr_val.is_classdef_meta ()
-                                && ! partial_expr_val.is_package ()))
-                          {
-                            // Found an object, so now we'll build up
-                            // complete index list for one big subsref
-                            // call from this point on.
+                      if (partial_expr_val.is_cs_list ())
+                        err_indexed_cs_list ();
+
+                      retval = partial_expr_val;
+
+                      beg = i;
+                      idx_list.clear ();
+                      tw.clear_index_list ();
 
-                            // FIXME: is is also possible to have a
-                            // static method call buried somewhere in
-                            // the depths of a complex indexing
-                            // expression so that we would also need to
-                            // check for an octave_classdef_meta object
-                            // here?
+                      if (partial_expr_val.isobject ()
+                          || partial_expr_val.isjava ()
+                          || (partial_expr_val.is_classdef_meta ()
+                              && ! partial_expr_val.is_package ()))
+                        {
+                          // Found an object, so now we'll build up
+                          // complete index list for one big subsref
+                          // call from this point on.
 
-                            indexing_object = true;
-                          }
-                      }
-                  }
-                catch (index_exception& e)
-                  {
-                    tw.final_index_error (e, m_expr);
-                  }
-              }
-          }
+                          // FIXME: is is also possible to have a
+                          // static method call buried somewhere in
+                          // the depths of a complex indexing
+                          // expression so that we would also need to
+                          // check for an octave_classdef_meta object
+                          // here?
+
+                          indexing_object = true;
+                        }
+                    }
+                  catch (index_exception& e)
+                    {
+                      tw.final_index_error (e, m_expr);
+                    }
+                }
+            }
+
+          tw.set_indexed_object (partial_expr_val);
 
-        switch (m_type[i])
-          {
-          case '(':
-            idx_list.push_back (make_value_list (tw, *p_args, *p_arg_nm,
-                                                 partial_expr_val));
-            break;
+          switch (m_type[i])
+            {
+            case '(':
+              {
+                octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
+                tw.append_index_list ('(', tmp);
+                idx_list.push_back (tmp);
+              }
+              break;
 
-          case '{':
-            idx_list.push_back (make_value_list (tw, *p_args, *p_arg_nm,
-                                                 partial_expr_val));
-            break;
+            case '{':
+              {
+                octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
+                tw.append_index_list ('{', tmp);
+                idx_list.push_back (tmp);
+              }
+              break;
 
-          case '.':
-            idx_list.push_back (octave_value
-                                (get_struct_index (tw, p_arg_nm, p_dyn_field)));
-            break;
+            case '.':
+              {
+                octave_value tmp = get_struct_index (tw, p_arg_nm, p_dyn_field);
+                tw.append_index_list ('.', tmp);
+                idx_list.push_back (tmp);
+              }
+              break;
 
-          default:
-            panic_impossible ();
-          }
+            default:
+              panic_impossible ();
+            }
 
-        p_args++;
-        p_arg_nm++;
-        p_dyn_field++;
-      }
-
+          p_args++;
+          p_arg_nm++;
+          p_dyn_field++;
+        }
+    }
 
     // If ! idx_list.empty () that means we still have stuff to index
     // otherwise they would have been dealt with and idx_list would have
@@ -760,16 +674,11 @@
           }
       }
 
-    // Delete any temporary values prior to pushing the result and
-    // returning so that destructors for any temporary classdef handle
-    // objects will be called before we return.  Otherwise, the
-    // destructor may push result values that will wipe out the result
-    // that we push below.  Although the method name is "push_result"
-    // there is only a single register (either an octave_value or an
-    // octave_value_list) not a stack.
+    // Delete any temporary values prior to returning so that
+    // destructors for any temporary classdef handle objects will be
+    // called before we return.
 
     idx_list.clear ();
-    partial_expr_val = octave_value ();
     base_expr_val = octave_value ();
     val = octave_value ();