# HG changeset patch # User John W. Eaton # Date 1649441465 14400 # Node ID 4ed7dfe2858468da09df48a7f357e1d70d819fcd # Parent 297f32524dd86596b997d58c9bceb9358a7b0451 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. diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/corefcn/mex.cc --- 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 * diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/corefcn/module.mk --- 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 diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/octave-value/ov-builtin.cc --- 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 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 diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/octave-value/ov-mex-fcn.cc --- 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 block (profiler, *this); - - retval = call_mex (*this, args, nargout); - - return retval; + return tw.execute_mex_function (*this, nargout, args); } diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/parse-tree/pt-eval.cc --- 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 free_vars = anon_fcn_ctx.free_variables (); + + stack_frame::local_vars_map local_vars; + + std::shared_ptr 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 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 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 (); diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/parse-tree/pt-eval.h --- 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 diff -r 297f32524dd8 -r 4ed7dfe28584 libinterp/parse-tree/pt-fcn-handle.cc --- 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 free_vars = anon_fcn_ctx.free_variables (); - - stack_frame::local_vars_map local_vars; - - call_stack& cs = tw.get_call_stack (); - - std::shared_ptr 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); } }