changeset 28433:d05a4194f1ad stable

move make_fcn_handle to tree_evaluator class * pt-eval.h, pt-eval.cc (tree_evaluator::make_fcn_handle): New function. Change all uses of global make_fcn_handle to use this member function instead. (get_operator_function_name): New function. * ov-fcn-handle.h, ov-fcn-handle.cc (make_fcn_handle): Deprecate. Now a wrapper for tree_evaluator::make_fcn_handle. (octave_fcn_handle::octave_fcn_handle (const std::string& name)): New constructor. * interpreter.h, interpreter.cc (interpreter::make_function_handle): New function.
author John W. Eaton <jwe@octave.org>
date Wed, 15 Apr 2020 23:14:06 -0400
parents 71c34141cc2d
children 48c1e8d88ea2
files libinterp/corefcn/interpreter.cc libinterp/corefcn/interpreter.h libinterp/corefcn/ls-mat5.cc libinterp/octave-value/ov-fcn-handle.cc libinterp/octave-value/ov-fcn-handle.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h libinterp/parse-tree/pt-fcn-handle.cc
diffstat 8 files changed, 271 insertions(+), 192 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/interpreter.cc	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/corefcn/interpreter.cc	Wed Apr 15 23:14:06 2020 -0400
@@ -1577,6 +1577,11 @@
     return feval (f_arg, tmp_args, nargout);
   }
 
+  octave_value interpreter::make_function_handle (const std::string& name)
+  {
+    return m_evaluator.make_fcn_handle (name);
+  }
+
   void interpreter::install_variable (const std::string& name,
                                       const octave_value& value, bool global)
   {
--- a/libinterp/corefcn/interpreter.h	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/corefcn/interpreter.h	Wed Apr 15 23:14:06 2020 -0400
@@ -361,6 +361,8 @@
 
     octave_value_list feval (const octave_value_list& args, int nargout = 0);
 
+    octave_value make_function_handle (const std::string& name);
+
     void install_variable (const std::string& name, const octave_value& value,
                            bool global);
 
--- a/libinterp/corefcn/ls-mat5.cc	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/corefcn/ls-mat5.cc	Wed Apr 15 23:14:06 2020 -0400
@@ -860,8 +860,13 @@
         if (ftype == "simple" || ftype == "scopedfunction")
           {
             if (fpath.empty ())
-              // We have a builtin function
-              tc = make_fcn_handle (interp, fname);
+              {
+                octave::tree_evaluator& tw = interp.get_evaluator ();
+
+                // We have a builtin function
+                // XXX FCN_HANDLE: SIMPLE/SCOPED
+                tc = tw.make_fcn_handle (fname);
+              }
             else
               {
                 std::string mroot = m0.contents ("matlabroot").string_value ();
--- a/libinterp/octave-value/ov-fcn-handle.cc	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Wed Apr 15 23:14:06 2020 -0400
@@ -83,6 +83,38 @@
 
 const std::string octave_fcn_handle::anonymous ("@<anonymous>");
 
+octave_fcn_handle::octave_fcn_handle (const std::string& n)
+  : m_fcn (), m_obj (), m_name (n), m_scope (), m_is_nested (false),
+    m_closure_frames (), m_local_vars (nullptr), m_dispatch_class ()
+{
+  if (! m_name.empty () && m_name[0] == '@')
+    m_name = m_name.substr (1);
+
+  size_t pos = m_name.find ('.');
+
+  if (pos != std::string::npos)
+    {
+      // If we are looking at
+      //
+      //   obj . meth
+      //
+      // Store the object so that calling METH for OBJ will work even if
+      // it is done outside of the scope whre OBJ was initially defined
+      // or if OBJ is cleared before the method call is made through the
+      // function handle.
+
+      std::string obj_name = m_name.substr (0, pos);
+
+      octave::interpreter& interp
+        = octave::__get_interpreter__ ("octave_fcn_handle::octave_fcn_handle");
+
+      octave_value val = interp.varval (obj_name);
+
+      if (val.is_classdef_object ())
+        m_obj = val;
+    }
+}
+
 octave_fcn_handle::octave_fcn_handle (const octave::symbol_scope& scope,
                                       const std::string& n)
   : m_fcn (), m_obj (), m_name (n), m_scope (scope), m_is_nested (false),
@@ -1673,193 +1705,17 @@
 
 namespace octave
 {
-  // Hmm, should this function be a member of the interpreter class,
-  // possibly forwarded to an actual implementation in the
-  // tree_evaluator class?
+  // DEPRECATED in Octave 6.
 
   octave_value
   make_fcn_handle (interpreter& interp, const std::string& nm)
   {
-    octave_value retval;
-
-    // Bow to the god of compatibility.
-
-    // FIXME: it seems ugly to put this here, but there is no single
-    // function in the parser that converts from the operator name to
-    // the corresponding function name.  At least try to do it without N
-    // string compares.
-
-    std::string tnm = nm;
-
-    size_t len = nm.length ();
-
-    if (len == 3 && nm == ".**")
-      tnm = "power";
-    else if (len == 2)
-      {
-        if (nm[0] == '.')
-          {
-            switch (nm[1])
-              {
-              case '\'':
-                tnm = "transpose";
-                break;
-
-              case '+':
-                tnm = "plus";
-                break;
-
-              case '-':
-                tnm = "minus";
-                break;
-
-              case '*':
-                tnm = "times";
-                break;
-
-              case '/':
-                tnm = "rdivide";
-                break;
-
-              case '^':
-                tnm = "power";
-                break;
-
-              case '\\':
-                tnm = "ldivide";
-                break;
-              }
-          }
-        else if (nm[1] == '=')
-          {
-            switch (nm[0])
-              {
-              case '<':
-                tnm = "le";
-                break;
-
-              case '=':
-                tnm = "eq";
-                break;
-
-              case '>':
-                tnm = "ge";
-                break;
-
-              case '~':
-              case '!':
-                tnm = "ne";
-                break;
-              }
-          }
-        else if (nm == "**")
-          tnm = "mpower";
-      }
-    else if (len == 1)
-      {
-        switch (nm[0])
-          {
-          case '~':
-          case '!':
-            tnm = "not";
-            break;
-
-          case '\'':
-            tnm = "ctranspose";
-            break;
-
-          case '+':
-            tnm = "plus";
-            break;
-
-          case '-':
-            tnm = "minus";
-            break;
-
-          case '*':
-            tnm = "mtimes";
-            break;
-
-          case '/':
-            tnm = "mrdivide";
-            break;
-
-          case '^':
-            tnm = "mpower";
-            break;
-
-          case '\\':
-            tnm = "mldivide";
-            break;
-
-          case '<':
-            tnm = "lt";
-            break;
-
-          case '>':
-            tnm = "gt";
-            break;
-
-          case '&':
-            tnm = "and";
-            break;
-
-          case '|':
-            tnm = "or";
-            break;
-          }
-      }
-
     tree_evaluator& tw = interp.get_evaluator ();
 
-    symbol_scope curr_scope = tw.get_current_scope ();
-
-    octave_fcn_handle *fh = new octave_fcn_handle (curr_scope, tnm);
-
-    std::string dispatch_class;
-
-    if (tw.is_class_method_executing (dispatch_class)
-        || tw.is_class_constructor_executing (dispatch_class))
-      fh->set_dispatch_class (dispatch_class);
-
-    return octave_value (fh);
+    return tw.make_fcn_handle (nm);
   }
 }
 
-/*
-%!test
-%! x = {".**", "power";
-%!      ".'", "transpose";
-%!      ".+", "plus";
-%!      ".-", "minus";
-%!      ".*", "times";
-%!      "./", "rdivide";
-%!      ".^", "power";
-%!      ".\\", "ldivide";
-%!      "<=", "le";
-%!      "==", "eq";
-%!      ">=", "ge";
-%!      "!=", "ne";
-%!      "~=", "ne";
-%!      "**", "mpower";
-%!      "~", "not";
-%!      "!", "not";
-%!      "\'", "ctranspose";
-%!      "+", "plus";
-%!      "-", "minus";
-%!      "*", "mtimes";
-%!      "/", "mrdivide";
-%!      "^", "mpower";
-%!      "\\", "mldivide";
-%!      "<", "lt";
-%!      ">", "gt";
-%!      "&", "and";
-%!      "|", "or"};
-%! for i = 1:rows (x)
-%!   assert (functions (str2func (x{i,1})).function, x{i,2});
-%! endfor
-*/
-
 DEFUN (functions, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn {} {@var{s} =} functions (@var{fcn_handle})
@@ -2024,18 +1880,31 @@
   if (nargin < 1 || nargin > 2)
     print_usage ();
 
-  std::string nm = args(0).xstring_value ("str2func: FCN_NAME must be a string");
+  std::string nm
+    = args(0).xstring_value ("str2func: FCN_NAME must be a string");
 
-  octave_value retval;
+  if (nm.empty ())
+    error ("str2func: invalid function name");
 
   if (nm[0] == '@')
     {
+      // Unlike the anon_fcn_handle::parse method, don't set up
+      // temporary scope to use for evaluating the text that defines
+      // the anonymous function.  Here we want
+      //
+      //   str2fun ("@(args) expr")
+      //
+      // to behave the same as if
+      //
+      //   @(args) expr
+      //
+      // were evaluated in the current scope.
+
       int parse_status;
-      octave_value anon_fcn_handle
-        = interp.eval_string (nm, true, parse_status);
+      octave_value afh = interp.eval_string (nm, true, parse_status);
 
       if (parse_status == 0)
-        retval = anon_fcn_handle;
+        return afh;
     }
   else
     {
@@ -2043,10 +1912,12 @@
         warning_with_id ("Octave:str2func-global-argument",
                          "str2func: second argument ignored");
 
-      retval = octave::make_fcn_handle (interp, nm);
+      octave::tree_evaluator& tw = interp.get_evaluator ();
+
+      return tw.make_fcn_handle (nm);
     }
 
-  return retval;
+  return ovl ();
 }
 
 /*
--- a/libinterp/octave-value/ov-fcn-handle.h	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/octave-value/ov-fcn-handle.h	Wed Apr 15 23:14:06 2020 -0400
@@ -59,16 +59,29 @@
       m_closure_frames (), m_local_vars (nullptr), m_dispatch_class ()
   { }
 
-  octave_fcn_handle (const octave::symbol_scope& scope, const std::string& n);
+  // OCTAVE_DEPRECATED (6, "foobar-1")
+  octave_fcn_handle (const std::string& name);
 
+  // OCTAVE_DEPRECATED (6, "foobar-2")
+  octave_fcn_handle (const octave::symbol_scope& scope,
+                     const std::string& name);
+
+  // OCTAVE_DEPRECATED (6, "foobar-3")
   octave_fcn_handle (const octave::symbol_scope& scope,
-                     const octave_value& f, const std::string& n);
+                     const octave_value& f, const std::string& name);
+
+  // OCTAVE_DEPRECATED (6, "foobar-4")
+  octave_fcn_handle (const octave_value& f, const std::string& name);
 
-  octave_fcn_handle (const octave_value& f, const std::string& n);
+  // OCTAVE_DEPRECATED (6, "foobar-5")
+  octave_fcn_handle (const octave_value& fcn, const std::string& name,
+                     const std::list<std::string>& parentage);
 
-  octave_fcn_handle (const octave_value& f,
+  // OCTAVE_DEPRECATED (6, "foobar-6")
+  octave_fcn_handle (const octave_value& fcn,
                      const octave::stack_frame::local_vars_map& local_vars);
 
+  // OCTAVE_DEPRECATED (6, "foobar-7")
   octave_fcn_handle (const octave_fcn_handle& fh);
 
   ~octave_fcn_handle (void);
@@ -202,6 +215,7 @@
 
 namespace octave
 {
+  OCTAVE_DEPRECATED (6, "use 'tree_evaluator::make_fcn_handle' instead")
   extern octave_value
   make_fcn_handle (interpreter& interp, const std::string& name);
 }
--- a/libinterp/parse-tree/pt-eval.cc	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Apr 15 23:14:06 2020 -0400
@@ -882,6 +882,185 @@
     return retval;
   }
 
+  // If NAME is an operator (like "+", "-", ...), convert it to the
+  // corresponding function name ("plus", "minus", ...).
+
+  static std::string
+  get_operator_function_name (const std::string& name)
+  {
+    // Bow to the god of compatibility.
+
+    // FIXME: it seems ugly to put this here, but there is no single
+    // function in the parser that converts from the operator name to
+    // the corresponding function name.  At least try to do it without N
+    // string compares.
+
+    size_t len = name.length ();
+
+    if (len == 3 && name == ".**")
+      return "power";
+    else if (len == 2)
+      {
+        if (name[0] == '.')
+          {
+            switch (name[1])
+              {
+              case '\'':
+                return "transpose";
+
+              case '+':
+                return "plus";
+
+              case '-':
+                return "minus";
+
+              case '*':
+                return "times";
+
+              case '/':
+                return "rdivide";
+
+              case '^':
+                return "power";
+
+              case '\\':
+                return "ldivide";
+
+              default:
+                break;
+              }
+          }
+        else if (name[1] == '=')
+          {
+            switch (name[0])
+              {
+              case '<':
+                return "le";
+
+              case '=':
+                return "eq";
+
+              case '>':
+                return "ge";
+
+              case '~':
+              case '!':
+                return "ne";
+
+              default:
+                break;
+              }
+          }
+        else if (name == "**")
+          return "mpower";
+      }
+    else if (len == 1)
+      {
+        switch (name[0])
+          {
+          case '~':
+          case '!':
+            return "not";
+
+          case '\'':
+            return "ctranspose";
+
+          case '+':
+            return "plus";
+
+          case '-':
+            return "minus";
+
+          case '*':
+            return "mtimes";
+
+          case '/':
+            return "mrdivide";
+
+          case '^':
+            return "mpower";
+
+          case '\\':
+            return "mldivide";
+
+          case '<':
+            return "lt";
+
+          case '>':
+            return "gt";
+
+          case '&':
+            return "and";
+
+          case '|':
+            return "or";
+
+          default:
+            break;
+          }
+      }
+
+    return name;
+  }
+
+  octave_value
+  tree_evaluator::make_fcn_handle (const std::string& name)
+  {
+    octave_value retval;
+
+    std::string fcn_name = get_operator_function_name (name);
+
+    if (fcn_name != name)
+      return octave_value (new octave_fcn_handle (fcn_name));
+
+    symbol_scope curr_scope = get_current_scope ();
+
+    // FCN_HANDLE: CONTEXT DEPENDENT
+    octave_fcn_handle *fh = new octave_fcn_handle (curr_scope, name);
+
+    std::string dispatch_class;
+
+    if (is_class_method_executing (dispatch_class)
+        || is_class_constructor_executing (dispatch_class))
+      fh->set_dispatch_class (dispatch_class);
+
+    return octave_value (fh);
+  }
+
+/*
+%!test
+%! x = {".**", "power";
+%!      ".'", "transpose";
+%!      ".+", "plus";
+%!      ".-", "minus";
+%!      ".*", "times";
+%!      "./", "rdivide";
+%!      ".^", "power";
+%!      ".\\", "ldivide";
+%!      "<=", "le";
+%!      "==", "eq";
+%!      ">=", "ge";
+%!      "!=", "ne";
+%!      "~=", "ne";
+%!      "**", "mpower";
+%!      "~", "not";
+%!      "!", "not";
+%!      "\'", "ctranspose";
+%!      "+", "plus";
+%!      "-", "minus";
+%!      "*", "mtimes";
+%!      "/", "mrdivide";
+%!      "^", "mpower";
+%!      "\\", "mldivide";
+%!      "<", "lt";
+%!      ">", "gt";
+%!      "&", "and";
+%!      "|", "or"};
+%! for i = 1:rows (x)
+%!   assert (functions (str2func (x{i,1})).function, x{i,2});
+%! endfor
+*/
+
   octave_value
   tree_evaluator::evaluate (tree_decl_elt *elt)
   {
--- a/libinterp/parse-tree/pt-eval.h	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/parse-tree/pt-eval.h	Wed Apr 15 23:14:06 2020 -0400
@@ -298,6 +298,8 @@
 
     Matrix ignored_fcn_outputs (void) const;
 
+    octave_value make_fcn_handle (const std::string& nm);
+
     octave_value evaluate (tree_decl_elt *);
 
     void install_variable (const std::string& name,
--- a/libinterp/parse-tree/pt-fcn-handle.cc	Fri Apr 03 22:00:06 2020 -0400
+++ b/libinterp/parse-tree/pt-fcn-handle.cc	Wed Apr 15 23:14:06 2020 -0400
@@ -63,7 +63,8 @@
   octave_value
   tree_fcn_handle::evaluate (tree_evaluator& tw, int)
   {
-    return make_fcn_handle (tw.get_interpreter (), m_name);
+    // XXX FCN_HANDLE: CONTEXT DEPENDENT
+    return tw.make_fcn_handle (m_name);
   }
 
   tree_anon_fcn_handle::~tree_anon_fcn_handle (void)