changeset 30919:4ed7dfe28584

move eval of anon fcn handles and built-in and mex functions to pt-eval.cc For consistency with the evaluation of user-defined functions and scripts, move the evaluation of anonymous function handles and built-in and mex functions to the tree_evaluator class in pt-eval.cc. * pt-eval.h, pt-eval.cc (tree_evaluator::evaluate_anon_fcn_handle, tree_evaluator::execute_builtin_function, tree_evaluator::execute_mex_function): New functions extracted from tree_anon_fcn_handle::evalueate, octave_builtin::execute and octave_mex_function::execute, respectively. * ov-builtin.cc (octave_builtin::execute): Forward to tree_evaluator::execute_builtin_function. * ov-mex-fcn.cc (octave_mex_function::execute): Forward to tree_evaluator::execute_mex_function. * pt-fcn-handle.cc (tree_anon_fcn_handle::evaluate): Forward to tree_evaluator::evaluate_anon_fcn_handle. * mex.cc: Move call_mex inside octave namespace. * mex-private.h: New file. * libinterp/corefcn/module.mk: Update.
author John W. Eaton <jwe@octave.org>
date Fri, 08 Apr 2022 14:11:05 -0400
parents 297f32524dd8
children 47cbc69e66cd
files libinterp/corefcn/mex.cc libinterp/corefcn/module.mk libinterp/octave-value/ov-builtin.cc libinterp/octave-value/ov-mex-fcn.cc libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h libinterp/parse-tree/pt-fcn-handle.cc
diffstat 7 files changed, 187 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/mex.cc	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/corefcn/mex.cc	Fri Apr 08 14:11:05 2022 -0400
@@ -4777,6 +4777,8 @@
 typedef F77_RET_T (*fmex_fptr) (F77_INT& nlhs, mxArray **plhs,
                                 F77_INT& nrhs, mxArray **prhs);
 
+OCTAVE_NAMESPACE_BEGIN
+
 octave_value_list
 call_mex (octave_mex_function& mex_fcn, const octave_value_list& args,
           int nargout_arg)
@@ -4848,6 +4850,8 @@
   return retval;
 }
 
+OCTAVE_NAMESPACE_END
+
 // C interface to mex functions:
 
 const char *
--- a/libinterp/corefcn/module.mk	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/corefcn/module.mk	Fri Apr 08 14:11:05 2022 -0400
@@ -58,7 +58,6 @@
   %reldir%/ls-oct-text.h \
   %reldir%/ls-oct-binary.h \
   %reldir%/ls-utils.h \
-  %reldir%/mex.h \
   %reldir%/mexproto.h \
   %reldir%/mx-type-traits.h \
   %reldir%/mxarray.h \
@@ -103,6 +102,7 @@
 
 NOINSTALL_COREFCN_INC = \
   %reldir%/interpreter-private.h \
+  %reldir%/mex-private.h \
   %reldir%/oct-hdf5.h \
   %reldir%/oct-opengl.h
 
--- a/libinterp/octave-value/ov-builtin.cc	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/octave-value/ov-builtin.cc	Fri Apr 08 14:11:05 2022 -0400
@@ -46,45 +46,7 @@
 octave_builtin::execute (octave::tree_evaluator& tw, int nargout,
                          const octave_value_list& args)
 {
-  octave_value_list retval;
-
-  if (args.has_magic_colon ())
-    error ("invalid use of colon in function argument list");
-
-  octave::profiler& profiler = tw.get_profiler ();
-
-  octave::profiler::enter<octave_builtin> block (profiler, *this);
-
-  if (m_fcn)
-    retval = (*m_fcn) (args, nargout);
-  else
-    {
-      octave::interpreter& interp
-        = octave::__get_interpreter__ ("octave_builtin::call");
-
-      retval = (*m_meth) (interp, args, nargout);
-    }
-
-  // Do not allow null values to be returned from functions.
-  // FIXME: perhaps true builtins should be allowed?
-
-  retval.make_storable_values ();
-
-  // Fix the case of a single undefined value.
-  // This happens when a compiled function uses
-  //
-  //   octave_value retval;
-  //
-  // instead of
-  //
-  //   octave_value_list retval;
-  //
-  // the idiom is very common, so we solve that here.
-
-  if (retval.length () == 1 && retval.xelem (0).is_undefined ())
-    retval.clear ();
-
-  return retval;
+  return tw.execute_builtin_function (*this, nargout, args);
 }
 
 octave_builtin::fcn
--- a/libinterp/octave-value/ov-mex-fcn.cc	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/octave-value/ov-mex-fcn.cc	Fri Apr 08 14:11:05 2022 -0400
@@ -91,25 +91,9 @@
   return m_sh_lib.time_loaded ();
 }
 
-// FIXME: shouldn't this declaration be a header file somewhere?
-extern octave_value_list
-call_mex (octave_mex_function& curr_mex_fcn, const octave_value_list& args,
-          int nargout);
-
 octave_value_list
 octave_mex_function::execute (octave::tree_evaluator& tw, int nargout,
                               const octave_value_list& args)
 {
-  octave_value_list retval;
-
-  if (args.has_magic_colon ())
-    error ("invalid use of colon in function argument list");
-
-  octave::profiler& profiler = tw.get_profiler ();
-
-  octave::profiler::enter<octave_mex_function> block (profiler, *this);
-
-  retval = call_mex (*this, args, nargout);
-
-  return retval;
+  return tw.execute_mex_function (*this, nargout, args);
 }
--- a/libinterp/parse-tree/pt-eval.cc	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/parse-tree/pt-eval.cc	Fri Apr 08 14:11:05 2022 -0400
@@ -53,9 +53,11 @@
 #include "input.h"
 #include "interpreter-private.h"
 #include "interpreter.h"
+#include "mex-private.h"
 #include "octave.h"
 #include "ov-classdef.h"
 #include "ov-fcn-handle.h"
+#include "ov-mex-fcn.h"
 #include "ov-usr-fcn.h"
 #include "ov-re-sparse.h"
 #include "ov-cx-sparse.h"
@@ -3323,11 +3325,162 @@
       body->accept (*this);
   }
 
-  void
-  tree_evaluator::visit_octave_user_script (octave_user_script&)
-  {
-    // ??
-    panic_impossible ();
+  octave_value
+  tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh)
+  {
+    // FIXME: should CMD_LIST be limited to a single expression?
+    // I think that is what Matlab does.
+
+    symbol_scope new_scope;
+    symbol_scope scope = afh.scope ();
+    if (scope)
+      new_scope = scope.dup ();
+
+    tree_parameter_list *param_list = afh.parameter_list ();
+    tree_parameter_list *param_list_dup
+      = param_list ? param_list->dup (new_scope) : nullptr;
+
+    tree_parameter_list *ret_list = nullptr;
+
+    tree_statement_list *stmt_list = nullptr;
+
+    symbol_scope parent_scope = get_current_scope ();
+
+    new_scope.set_parent (parent_scope);
+    new_scope.set_primary_parent (parent_scope);
+
+    tree_expression *expr = afh.expression ();
+    if (expr)
+      {
+        tree_expression *expr_dup = expr->dup (new_scope);
+        tree_statement *stmt = new tree_statement (expr_dup, nullptr);
+        stmt_list = new tree_statement_list (stmt);
+      }
+
+    tree_anon_scopes anon_fcn_ctx (afh);
+
+    std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
+
+    stack_frame::local_vars_map local_vars;
+
+    std::shared_ptr<stack_frame> frame
+      = m_call_stack.get_current_stack_frame ();
+
+    for (auto& name : free_vars)
+      {
+        octave_value val = frame->varval (name);
+
+        if (val.is_defined ())
+          local_vars[name] = val;
+      }
+
+    octave_user_function *af
+      = new octave_user_function (new_scope, param_list_dup, ret_list,
+                                  stmt_list);
+
+    octave_function *curr_fcn = m_call_stack.current_function ();
+
+    bool is_nested = false;
+
+    if (curr_fcn)
+      {
+        // FIXME: maybe it would be better to just stash curr_fcn
+        // instead of individual bits of info about it?
+
+        // An anonymous function defined inside another nested function
+        // or parent of a nested function also behaves like a nested
+        // function.
+
+        if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
+          {
+            is_nested = true;
+            af->mark_as_nested_function ();
+            new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
+          }
+
+        af->stash_dir_name (curr_fcn->dir_name ());
+
+        new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
+        new_scope.cache_dir_name (curr_fcn->dir_name ());
+
+        // The following is needed so that class method dispatch works
+        // properly for anonymous functions that wrap class methods.
+
+        if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
+          af->stash_dispatch_class (curr_fcn->dispatch_class ());
+
+        af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
+      }
+
+    af->mark_as_anonymous_function ();
+
+    octave_value ov_fcn (af);
+
+    return (is_nested
+            ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
+            : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
+  }
+
+  octave_value_list
+  tree_evaluator::execute_builtin_function (octave_builtin& builtin_function,
+                                            int nargout,
+                                            const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    if (args.has_magic_colon ())
+      error ("invalid use of colon in function argument list");
+
+    profiler::enter<octave_builtin> block (m_profiler, builtin_function);
+
+    octave_builtin::fcn fcn = builtin_function.function ();
+
+    if (fcn)
+      retval = (*fcn) (args, nargout);
+    else
+      {
+        octave_builtin::meth meth = builtin_function.method ();
+
+        retval = (*meth) (m_interpreter, args, nargout);
+      }
+
+    // Do not allow null values to be returned from functions.
+    // FIXME: perhaps true builtins should be allowed?
+
+    retval.make_storable_values ();
+
+    // Fix the case of a single undefined value.
+    // This happens when a compiled function uses
+    //
+    //   octave_value retval;
+    //
+    // instead of
+    //
+    //   octave_value_list retval;
+    //
+    // the idiom is very common, so we solve that here.
+
+    if (retval.length () == 1 && retval.xelem (0).is_undefined ())
+      retval.clear ();
+
+    return retval;
+  }
+
+  octave_value_list
+  tree_evaluator::execute_mex_function (octave_mex_function& mex_function,
+                                        int nargout,
+                                        const octave_value_list& args)
+  {
+    octave_value_list retval;
+
+    if (args.has_magic_colon ())
+      error ("invalid use of colon in function argument list");
+
+    profiler::enter<octave_mex_function> block (m_profiler, mex_function);
+
+    retval = call_mex (mex_function, args, nargout);
+
+    return retval;
   }
 
   octave_value_list
@@ -3374,7 +3527,7 @@
   }
 
   void
-  tree_evaluator::visit_octave_user_function (octave_user_function&)
+  tree_evaluator::visit_octave_user_script (octave_user_script&)
   {
     // ??
     panic_impossible ();
@@ -3540,6 +3693,13 @@
   }
 
   void
+  tree_evaluator::visit_octave_user_function (octave_user_function&)
+  {
+    // ??
+    panic_impossible ();
+  }
+
+  void
   tree_evaluator::visit_octave_user_function_header (octave_user_function&)
   {
     panic_impossible ();
--- a/libinterp/parse-tree/pt-eval.h	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/parse-tree/pt-eval.h	Fri Apr 08 14:11:05 2022 -0400
@@ -44,7 +44,11 @@
 #include "pt-walk.h"
 #include "stack-frame.h"
 
+class octave_builtin;
+class octave_mex_function;
 class octave_user_code;
+class octave_user_function;
+class octave_user_script;
 
 OCTAVE_NAMESPACE_BEGIN
 
@@ -246,6 +250,15 @@
 
     void visit_spmd_command (tree_spmd_command&);
 
+    octave_value evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh);
+
+    octave_value_list
+    execute_builtin_function (octave_builtin& builtin_function, int nargout,
+                              const octave_value_list& args);
+    octave_value_list
+    execute_mex_function (octave_mex_function& mex_function, int nargout,
+                          const octave_value_list& args);
+
     void visit_octave_user_script (octave_user_script&);
 
     octave_value_list
--- a/libinterp/parse-tree/pt-fcn-handle.cc	Fri Apr 08 20:08:10 2022 +0200
+++ b/libinterp/parse-tree/pt-fcn-handle.cc	Fri Apr 08 14:11:05 2022 -0400
@@ -101,95 +101,7 @@
   octave_value
   tree_anon_fcn_handle::evaluate (tree_evaluator& tw, int)
   {
-    // FIXME: should CMD_LIST be limited to a single expression?
-    // I think that is what Matlab does.
-
-    symbol_scope new_scope;
-    if (m_scope)
-      new_scope = m_scope.dup ();
-
-    tree_parameter_list *param_list_dup
-      = m_parameter_list ? m_parameter_list->dup (new_scope) : nullptr;
-
-    tree_parameter_list *ret_list = nullptr;
-
-    tree_statement_list *stmt_list = nullptr;
-
-    symbol_scope parent_scope = tw.get_current_scope ();
-
-    new_scope.set_parent (parent_scope);
-    new_scope.set_primary_parent (parent_scope);
-
-    if (m_expression)
-      {
-        tree_expression *expr_dup = m_expression->dup (new_scope);
-        tree_statement *stmt = new tree_statement (expr_dup, nullptr);
-        stmt_list = new tree_statement_list (stmt);
-      }
-
-    tree_anon_scopes anon_fcn_ctx (*this);
-
-    std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
-
-    stack_frame::local_vars_map local_vars;
-
-    call_stack& cs = tw.get_call_stack ();
-
-    std::shared_ptr<stack_frame> frame = cs.get_current_stack_frame ();
-
-    for (auto& name : free_vars)
-      {
-        octave_value val = frame->varval (name);
-
-        if (val.is_defined ())
-          local_vars[name] = val;
-      }
-
-    octave_user_function *af
-      = new octave_user_function (new_scope, param_list_dup, ret_list,
-                                  stmt_list);
-
-    octave_function *curr_fcn = cs.current_function ();
-
-    bool is_nested = false;
-
-    if (curr_fcn)
-      {
-        // FIXME: maybe it would be better to just stash curr_fcn
-        // instead of individual bits of info about it?
-
-        // An anonymous function defined inside another nested function
-        // or parent of a nested function also behaves like a nested
-        // function.
-
-        if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
-          {
-            is_nested = true;
-            af->mark_as_nested_function ();
-            new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
-          }
-
-        af->stash_dir_name (curr_fcn->dir_name ());
-
-        new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
-        new_scope.cache_dir_name (curr_fcn->dir_name ());
-
-        // The following is needed so that class method dispatch works
-        // properly for anonymous functions that wrap class methods.
-
-        if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
-          af->stash_dispatch_class (curr_fcn->dispatch_class ());
-
-        af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
-      }
-
-    af->mark_as_anonymous_function ();
-
-    octave_value ov_fcn (af);
-
-    return (is_nested
-            ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
-            : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
+    return tw.evaluate_anon_fcn_handle (*this);
   }
 }