comparison libinterp/parse-tree/pt-eval.cc @ 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 c9788d7f6e65
children 344e1152ed88 e88a07dec498
comparison
equal deleted inserted replaced
30918:297f32524dd8 30919:4ed7dfe28584
51 #include "errwarn.h" 51 #include "errwarn.h"
52 #include "event-manager.h" 52 #include "event-manager.h"
53 #include "input.h" 53 #include "input.h"
54 #include "interpreter-private.h" 54 #include "interpreter-private.h"
55 #include "interpreter.h" 55 #include "interpreter.h"
56 #include "mex-private.h"
56 #include "octave.h" 57 #include "octave.h"
57 #include "ov-classdef.h" 58 #include "ov-classdef.h"
58 #include "ov-fcn-handle.h" 59 #include "ov-fcn-handle.h"
60 #include "ov-mex-fcn.h"
59 #include "ov-usr-fcn.h" 61 #include "ov-usr-fcn.h"
60 #include "ov-re-sparse.h" 62 #include "ov-re-sparse.h"
61 #include "ov-cx-sparse.h" 63 #include "ov-cx-sparse.h"
62 #include "parse.h" 64 #include "parse.h"
63 #include "profiler.h" 65 #include "profiler.h"
3321 3323
3322 if (body) 3324 if (body)
3323 body->accept (*this); 3325 body->accept (*this);
3324 } 3326 }
3325 3327
3326 void 3328 octave_value
3327 tree_evaluator::visit_octave_user_script (octave_user_script&) 3329 tree_evaluator::evaluate_anon_fcn_handle (tree_anon_fcn_handle& afh)
3328 { 3330 {
3329 // ?? 3331 // FIXME: should CMD_LIST be limited to a single expression?
3330 panic_impossible (); 3332 // I think that is what Matlab does.
3333
3334 symbol_scope new_scope;
3335 symbol_scope scope = afh.scope ();
3336 if (scope)
3337 new_scope = scope.dup ();
3338
3339 tree_parameter_list *param_list = afh.parameter_list ();
3340 tree_parameter_list *param_list_dup
3341 = param_list ? param_list->dup (new_scope) : nullptr;
3342
3343 tree_parameter_list *ret_list = nullptr;
3344
3345 tree_statement_list *stmt_list = nullptr;
3346
3347 symbol_scope parent_scope = get_current_scope ();
3348
3349 new_scope.set_parent (parent_scope);
3350 new_scope.set_primary_parent (parent_scope);
3351
3352 tree_expression *expr = afh.expression ();
3353 if (expr)
3354 {
3355 tree_expression *expr_dup = expr->dup (new_scope);
3356 tree_statement *stmt = new tree_statement (expr_dup, nullptr);
3357 stmt_list = new tree_statement_list (stmt);
3358 }
3359
3360 tree_anon_scopes anon_fcn_ctx (afh);
3361
3362 std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
3363
3364 stack_frame::local_vars_map local_vars;
3365
3366 std::shared_ptr<stack_frame> frame
3367 = m_call_stack.get_current_stack_frame ();
3368
3369 for (auto& name : free_vars)
3370 {
3371 octave_value val = frame->varval (name);
3372
3373 if (val.is_defined ())
3374 local_vars[name] = val;
3375 }
3376
3377 octave_user_function *af
3378 = new octave_user_function (new_scope, param_list_dup, ret_list,
3379 stmt_list);
3380
3381 octave_function *curr_fcn = m_call_stack.current_function ();
3382
3383 bool is_nested = false;
3384
3385 if (curr_fcn)
3386 {
3387 // FIXME: maybe it would be better to just stash curr_fcn
3388 // instead of individual bits of info about it?
3389
3390 // An anonymous function defined inside another nested function
3391 // or parent of a nested function also behaves like a nested
3392 // function.
3393
3394 if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
3395 {
3396 is_nested = true;
3397 af->mark_as_nested_function ();
3398 new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
3399 }
3400
3401 af->stash_dir_name (curr_fcn->dir_name ());
3402
3403 new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
3404 new_scope.cache_dir_name (curr_fcn->dir_name ());
3405
3406 // The following is needed so that class method dispatch works
3407 // properly for anonymous functions that wrap class methods.
3408
3409 if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
3410 af->stash_dispatch_class (curr_fcn->dispatch_class ());
3411
3412 af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
3413 }
3414
3415 af->mark_as_anonymous_function ();
3416
3417 octave_value ov_fcn (af);
3418
3419 return (is_nested
3420 ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
3421 : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
3422 }
3423
3424 octave_value_list
3425 tree_evaluator::execute_builtin_function (octave_builtin& builtin_function,
3426 int nargout,
3427 const octave_value_list& args)
3428 {
3429 octave_value_list retval;
3430
3431 if (args.has_magic_colon ())
3432 error ("invalid use of colon in function argument list");
3433
3434 profiler::enter<octave_builtin> block (m_profiler, builtin_function);
3435
3436 octave_builtin::fcn fcn = builtin_function.function ();
3437
3438 if (fcn)
3439 retval = (*fcn) (args, nargout);
3440 else
3441 {
3442 octave_builtin::meth meth = builtin_function.method ();
3443
3444 retval = (*meth) (m_interpreter, args, nargout);
3445 }
3446
3447 // Do not allow null values to be returned from functions.
3448 // FIXME: perhaps true builtins should be allowed?
3449
3450 retval.make_storable_values ();
3451
3452 // Fix the case of a single undefined value.
3453 // This happens when a compiled function uses
3454 //
3455 // octave_value retval;
3456 //
3457 // instead of
3458 //
3459 // octave_value_list retval;
3460 //
3461 // the idiom is very common, so we solve that here.
3462
3463 if (retval.length () == 1 && retval.xelem (0).is_undefined ())
3464 retval.clear ();
3465
3466 return retval;
3467 }
3468
3469 octave_value_list
3470 tree_evaluator::execute_mex_function (octave_mex_function& mex_function,
3471 int nargout,
3472 const octave_value_list& args)
3473 {
3474 octave_value_list retval;
3475
3476 if (args.has_magic_colon ())
3477 error ("invalid use of colon in function argument list");
3478
3479 profiler::enter<octave_mex_function> block (m_profiler, mex_function);
3480
3481 retval = call_mex (mex_function, args, nargout);
3482
3483 return retval;
3331 } 3484 }
3332 3485
3333 octave_value_list 3486 octave_value_list
3334 tree_evaluator::execute_user_script (octave_user_script& user_script, 3487 tree_evaluator::execute_user_script (octave_user_script& user_script,
3335 int nargout, 3488 int nargout,
3372 3525
3373 return retval; 3526 return retval;
3374 } 3527 }
3375 3528
3376 void 3529 void
3377 tree_evaluator::visit_octave_user_function (octave_user_function&) 3530 tree_evaluator::visit_octave_user_script (octave_user_script&)
3378 { 3531 {
3379 // ?? 3532 // ??
3380 panic_impossible (); 3533 panic_impossible ();
3381 } 3534 }
3382 3535
3535 ignored_outputs, 3688 ignored_outputs,
3536 varargout); 3689 varargout);
3537 } 3690 }
3538 3691
3539 return retval; 3692 return retval;
3693 }
3694
3695 void
3696 tree_evaluator::visit_octave_user_function (octave_user_function&)
3697 {
3698 // ??
3699 panic_impossible ();
3540 } 3700 }
3541 3701
3542 void 3702 void
3543 tree_evaluator::visit_octave_user_function_header (octave_user_function&) 3703 tree_evaluator::visit_octave_user_function_header (octave_user_function&)
3544 { 3704 {