1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2009-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <cctype> 31 32 #include <iostream> 33 #include <list> 34 #include <string> 35 36 #include "cmd-edit.h" 37 #include "file-ops.h" 38 #include "file-stat.h" 39 #include "lo-array-errwarn.h" 40 #include "lo-ieee.h" 41 #include "oct-env.h" 42 43 #include "bp-table.h" 44 #include "call-stack.h" 45 #include "cdef-manager.h" 46 #include "defun.h" 47 #include "error.h" 48 #include "errwarn.h" 49 #include "event-manager.h" 50 #include "input.h" 51 #include "interpreter-private.h" 52 #include "interpreter.h" 53 #include "octave.h" 54 #include "ov-classdef.h" 55 #include "ov-fcn-handle.h" 56 #include "ov-usr-fcn.h" 57 #include "ov-re-sparse.h" 58 #include "ov-cx-sparse.h" 59 #include "parse.h" 60 #include "profiler.h" 61 #include "pt-all.h" 62 #include "pt-anon-scopes.h" 63 #include "pt-eval.h" 64 #include "pt-tm-const.h" 65 #include "stack-frame.h" 66 #include "symtab.h" 67 #include "unwind-prot.h" 68 #include "utils.h" 69 #include "variables.h" 70 71 //FIXME: This should be part of tree_evaluator 72 #include "pt-jit.h" 73 74 namespace octave 75 { 76 // Normal evaluator. 77 78 class quit_debug_exception 79 { 80 public: 81 quit_debug_exception(bool all=false)82 quit_debug_exception (bool all = false) : m_all (all) { } 83 84 quit_debug_exception (const quit_debug_exception&) = default; 85 86 quit_debug_exception& operator = (const quit_debug_exception&) = default; 87 88 ~quit_debug_exception (void) = default; 89 all(void) const90 bool all (void) const { return m_all; } 91 92 private: 93 94 bool m_all; 95 }; 96 97 class debugger 98 { 99 public: 100 101 enum execution_mode 102 { 103 EX_NORMAL = 0, 104 EX_CONTINUE = 1, 105 EX_QUIT = 2, 106 EX_QUIT_ALL = 3 107 }; 108 debugger(interpreter & interp,std::size_t level)109 debugger (interpreter& interp, std::size_t level) 110 : m_interpreter (interp), m_level (level), m_debug_frame (0), 111 m_execution_mode (EX_NORMAL), m_in_debug_repl (false) 112 { } 113 114 void repl (const std::string& prompt = "debug> "); 115 in_debug_repl(void) const116 bool in_debug_repl (void) const { return m_in_debug_repl; } 117 dbcont(void)118 void dbcont (void) 119 { 120 m_execution_mode = EX_CONTINUE; 121 } 122 dbquit(bool all=false)123 void dbquit (bool all = false) 124 { 125 if (all) 126 m_execution_mode = EX_QUIT_ALL; 127 else 128 m_execution_mode = EX_QUIT; 129 } 130 131 bool quitting_debugger (void) const; 132 133 private: 134 135 interpreter& m_interpreter; 136 137 std::size_t m_level; 138 std::size_t m_debug_frame; 139 execution_mode m_execution_mode; 140 bool m_in_debug_repl; 141 }; 142 repl(const std::string & prompt_arg)143 void debugger::repl (const std::string& prompt_arg) 144 { 145 unwind_protect frame; 146 147 frame.protect_var (m_in_debug_repl); 148 frame.protect_var (m_execution_mode); 149 150 m_in_debug_repl = true; 151 152 tree_evaluator& tw = m_interpreter.get_evaluator (); 153 154 bool silent = tw.quiet_breakpoint_flag (false); 155 156 frame.add_method (tw, &tree_evaluator::restore_frame, 157 tw.current_call_stack_frame_number ()); 158 159 tw.goto_frame (tw.debug_frame ()); 160 161 octave_user_code *caller = tw.current_user_code (); 162 std::string fcn_file_nm, fcn_nm; 163 164 if (caller) 165 { 166 fcn_file_nm = caller->fcn_file_name (); 167 fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm; 168 } 169 170 int curr_debug_line = tw.current_line (); 171 172 std::ostringstream buf; 173 174 input_system& input_sys = m_interpreter.get_input_system (); 175 176 if (! fcn_nm.empty ()) 177 { 178 if (input_sys.gud_mode ()) 179 { 180 static char ctrl_z = 'Z' & 0x1f; 181 182 buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line; 183 } 184 else 185 { 186 // FIXME: we should come up with a clean way to detect 187 // that we are stopped on the no-op command that marks the 188 // end of a function or script. 189 190 if (! silent) 191 { 192 std::shared_ptr<stack_frame> frm = tw.current_user_frame (); 193 194 frm->display_stopped_in_message (buf); 195 } 196 197 event_manager& evmgr = m_interpreter.get_event_manager (); 198 199 evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line); 200 201 evmgr.set_workspace (); 202 203 frame.add ([&evmgr, fcn_nm, curr_debug_line] (void) { 204 evmgr.execute_in_debugger_event (fcn_nm, 205 curr_debug_line); 206 }); 207 208 if (! silent) 209 { 210 std::string line_buf; 211 212 if (caller) 213 line_buf = caller->get_code_line (curr_debug_line); 214 215 if (! line_buf.empty ()) 216 buf << curr_debug_line << ": " << line_buf; 217 } 218 } 219 } 220 221 if (silent) 222 command_editor::erase_empty_line (true); 223 224 std::string stopped_in_msg = buf.str (); 225 226 if (! stopped_in_msg.empty ()) 227 std::cerr << stopped_in_msg << std::endl; 228 229 std::string tmp_prompt = prompt_arg; 230 if (m_level > 0) 231 tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg; 232 233 frame.add_method (input_sys, &input_system::set_PS1, input_sys.PS1 ()); 234 input_sys.PS1 (tmp_prompt); 235 236 if (! m_interpreter.interactive ()) 237 { 238 239 frame.add_method (m_interpreter, &interpreter::interactive, 240 m_interpreter.interactive ()); 241 242 m_interpreter.interactive (true); 243 244 // FIXME: should debugging be possible in an embedded 245 // interpreter? 246 247 application *app = application::app (); 248 249 if (app) 250 { 251 frame.add_method (app, &application::forced_interactive, 252 app->forced_interactive ()); 253 254 app->forced_interactive (true); 255 } 256 } 257 258 #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) 259 260 input_reader reader (m_interpreter); 261 262 push_parser debug_parser (m_interpreter); 263 264 #else 265 266 parser debug_parser (m_interpreter); 267 268 #endif 269 270 error_system& es = m_interpreter.get_error_system (); 271 272 while (m_in_debug_repl) 273 { 274 if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ()) 275 break; 276 277 if (quitting_debugger ()) 278 break; 279 280 try 281 { 282 debug_parser.reset (); 283 284 #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) 285 286 int retval = 0; 287 288 std::string prompt 289 = command_editor::decode_prompt_string (tmp_prompt); 290 291 do 292 { 293 bool eof = false; 294 std::string input_line = reader.get_input (prompt, eof); 295 296 if (eof) 297 { 298 retval = EOF; 299 break; 300 } 301 302 retval = debug_parser.run (input_line, false); 303 304 prompt = command_editor::decode_prompt_string (input_sys.PS2 ()); 305 } 306 while (retval < 0); 307 308 #else 309 310 int retval = debug_parser.run (); 311 312 #endif 313 if (command_editor::interrupt (false)) 314 { 315 // Break regardless of m_execution_mode value. 316 317 quitting_debugger (); 318 319 break; 320 } 321 else 322 { 323 if (retval == 0) 324 { 325 std::shared_ptr<tree_statement_list> stmt_list 326 = debug_parser.statement_list (); 327 328 if (stmt_list) 329 stmt_list->accept (tw); 330 331 if (octave_completion_matches_called) 332 octave_completion_matches_called = false; 333 334 // FIXME: the following statement is here because 335 // the last command may have been a dbup, dbdown, or 336 // dbstep command that changed the current debug 337 // frame. If so, we need to reset the current frame 338 // for the call stack. But is this right way to do 339 // this job? What if the statement list was 340 // something like "dbup; dbstack"? Will the call to 341 // dbstack use the right frame? If not, how can we 342 // fix this problem? 343 tw.goto_frame (tw.debug_frame ()); 344 } 345 346 octave_quit (); 347 } 348 } 349 catch (const execution_exception& ee) 350 { 351 es.save_exception (ee); 352 es.display_exception (ee, std::cerr); 353 354 // Ignore errors when in debugging mode; 355 m_interpreter.recover_from_exception (); 356 } 357 catch (const quit_debug_exception& qde) 358 { 359 if (qde.all ()) 360 throw; 361 362 // Continue in this debug level. 363 } 364 } 365 } 366 quitting_debugger(void) const367 bool debugger::quitting_debugger (void) const 368 { 369 if (m_execution_mode == EX_QUIT) 370 { 371 // If there is no enclosing debug level or the top-level 372 // repl is not active, handle dbquit the same as dbcont. 373 374 if (m_level > 0 || m_interpreter.in_top_level_repl ()) 375 throw quit_debug_exception (); 376 else 377 return true; 378 } 379 380 if (m_execution_mode == EX_QUIT_ALL) 381 { 382 // If the top-level repl is not active, handle "dbquit all" 383 // the same as dbcont. 384 385 if (m_interpreter.in_top_level_repl ()) 386 throw quit_debug_exception (true); 387 else 388 return true; 389 } 390 391 return false; 392 } 393 at_top_level(void) const394 bool tree_evaluator::at_top_level (void) const 395 { 396 return m_call_stack.at_top_level (); 397 } 398 eval(std::shared_ptr<tree_statement_list> & stmt_list,bool interactive)399 void tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list, 400 bool interactive) 401 { 402 try 403 { 404 stmt_list->accept (*this); 405 406 octave_quit (); 407 408 if (! interactive) 409 { 410 bool quit = (m_returning || m_breaking); 411 412 if (m_returning) 413 m_returning = 0; 414 415 if (m_breaking) 416 m_breaking--; 417 418 if (quit) 419 return; 420 } 421 422 if (octave_completion_matches_called) 423 octave_completion_matches_called = false; 424 } 425 catch (const quit_debug_exception&) 426 { 427 m_interpreter.recover_from_exception (); 428 } 429 } 430 431 std::string mfilename(const std::string & opt) const432 tree_evaluator::mfilename (const std::string& opt) const 433 { 434 std::string fname; 435 436 octave_user_code *fcn = m_call_stack.current_user_code (); 437 438 if (fcn) 439 { 440 fname = fcn->fcn_file_name (); 441 442 if (fname.empty ()) 443 fname = fcn->name (); 444 } 445 446 if (opt == "fullpathext") 447 return fname; 448 449 std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ()); 450 std::size_t epos = fname.rfind ('.'); 451 452 if (epos <= dpos+1) 453 epos = std::string::npos; 454 455 if (epos != std::string::npos) 456 fname = fname.substr (0, epos); 457 458 if (opt == "fullpath") 459 return fname; 460 461 if (dpos != std::string::npos) 462 fname = fname.substr (dpos+1); 463 464 return fname; 465 } 466 repl(void)467 int tree_evaluator::repl (void) 468 { 469 // The big loop. Read, Eval, Print, Loop. Normally user 470 // interaction at the command line in a terminal session, but we may 471 // also end up here when reading from a pipe or when stdin is 472 // connected to a file by the magic of input redirection. 473 474 int exit_status = 0; 475 476 // FIXME: should this choice be a command-line option? Note that we 477 // intend that the push parser interface only be used for 478 // interactive sessions. 479 480 #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER) 481 static bool use_command_line_push_parser = true; 482 #else 483 static bool use_command_line_push_parser = false; 484 #endif 485 486 // The following logic is written as it is to allow easy transition 487 // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to 488 // simplify the logic of the main loop below by using the same 489 // base_parser::run interface for both push and pull parsers. 490 491 std::shared_ptr<base_parser> repl_parser; 492 493 if (m_interpreter.interactive ()) 494 { 495 if (use_command_line_push_parser) 496 { 497 push_parser *pp = new push_parser (m_interpreter, 498 new input_reader (m_interpreter)); 499 repl_parser = std::shared_ptr<base_parser> (pp); 500 } 501 else 502 { 503 parser *pp = new parser (new lexer (m_interpreter)); 504 repl_parser = std::shared_ptr<base_parser> (pp); 505 } 506 } 507 else 508 { 509 parser *pp = new parser (new lexer (stdin, m_interpreter)); 510 repl_parser = std::shared_ptr<base_parser> (pp); 511 } 512 513 do 514 { 515 try 516 { 517 unwind_protect_var<bool> upv (m_in_top_level_repl, true); 518 519 repl_parser->reset (); 520 521 if (at_top_level ()) 522 { 523 dbstep_flag (0); 524 reset_debug_state (); 525 } 526 527 exit_status = repl_parser->run (); 528 529 if (exit_status == 0) 530 { 531 std::shared_ptr<tree_statement_list> 532 stmt_list = repl_parser->statement_list (); 533 534 if (stmt_list) 535 { 536 command_editor::increment_current_command_number (); 537 538 eval (stmt_list, m_interpreter.interactive ()); 539 } 540 else if (repl_parser->at_end_of_input ()) 541 { 542 exit_status = EOF; 543 break; 544 } 545 } 546 } 547 catch (const interrupt_exception&) 548 { 549 m_interpreter.recover_from_exception (); 550 551 // Required newline when the user does Ctrl+C at the prompt. 552 if (m_interpreter.interactive ()) 553 octave_stdout << "\n"; 554 } 555 catch (const index_exception& e) 556 { 557 m_interpreter.recover_from_exception (); 558 559 std::cerr << "error: unhandled index exception: " 560 << e.message () << " -- trying to return to prompt" 561 << std::endl; 562 } 563 catch (const execution_exception& ee) 564 { 565 error_system& es = m_interpreter.get_error_system (); 566 567 es.save_exception (ee); 568 es.display_exception (ee, std::cerr); 569 570 if (m_interpreter.interactive ()) 571 m_interpreter.recover_from_exception (); 572 else 573 { 574 // We should exit with a nonzero status. 575 exit_status = 1; 576 break; 577 } 578 } 579 catch (const quit_debug_exception&) 580 { 581 m_interpreter.recover_from_exception (); 582 583 // FIXME: Does anything else need to happen here? 584 } 585 catch (const std::bad_alloc&) 586 { 587 m_interpreter.recover_from_exception (); 588 589 std::cerr << "error: out of memory -- trying to return to prompt" 590 << std::endl; 591 } 592 } 593 while (exit_status == 0); 594 595 if (exit_status == EOF) 596 { 597 if (m_interpreter.interactive ()) 598 octave_stdout << "\n"; 599 600 exit_status = 0; 601 } 602 603 return exit_status; 604 } 605 606 octave_value_list eval_string(const std::string & eval_str,bool silent,int & parse_status,int nargout)607 tree_evaluator::eval_string (const std::string& eval_str, bool silent, 608 int& parse_status, int nargout) 609 { 610 octave_value_list retval; 611 612 parser eval_parser (eval_str, m_interpreter); 613 614 do 615 { 616 eval_parser.reset (); 617 618 // If we are looking at 619 // 620 // val = eval ("code"); 621 // 622 // then don't allow code to be parsed as a command. 623 624 if (nargout > 0) 625 eval_parser.disallow_command_syntax (); 626 627 parse_status = eval_parser.run (); 628 629 if (parse_status == 0) 630 { 631 std::shared_ptr<tree_statement_list> stmt_list 632 = eval_parser.statement_list (); 633 634 if (stmt_list) 635 { 636 tree_statement *stmt = nullptr; 637 638 if (stmt_list->length () == 1 639 && (stmt = stmt_list->front ()) 640 && stmt->is_expression ()) 641 { 642 tree_expression *expr = stmt->expression (); 643 644 if (silent) 645 expr->set_print_flag (false); 646 647 retval = expr->evaluate_n (*this, nargout); 648 649 bool do_bind_ans = false; 650 651 if (expr->is_identifier ()) 652 do_bind_ans = ! is_variable (expr); 653 else 654 do_bind_ans = ! expr->is_assignment_expression (); 655 656 if (do_bind_ans && ! retval.empty ()) 657 bind_ans (retval(0), expr->print_result ()); 658 659 if (nargout == 0) 660 retval = octave_value_list (); 661 } 662 else if (nargout == 0) 663 stmt_list->accept (*this); 664 else 665 error ("eval: invalid use of statement list"); 666 667 if (returning () || breaking () || continuing ()) 668 break; 669 } 670 else if (eval_parser.at_end_of_input ()) 671 break; 672 } 673 } 674 while (parse_status == 0); 675 676 return retval; 677 } 678 eval_string(const std::string & eval_str,bool silent,int & parse_status)679 octave_value tree_evaluator::eval_string (const std::string& eval_str, 680 bool silent, int& parse_status) 681 { 682 octave_value retval; 683 684 octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1); 685 686 if (! tmp.empty ()) 687 retval = tmp(0); 688 689 return retval; 690 } 691 eval_string(const octave_value & arg,bool silent,int & parse_status,int nargout)692 octave_value_list tree_evaluator::eval_string (const octave_value& arg, 693 bool silent, int& parse_status, 694 int nargout) 695 { 696 std::string s = arg.xstring_value ("eval: expecting string argument"); 697 698 return eval_string (s, silent, parse_status, nargout); 699 } 700 eval(const std::string & try_code,int nargout)701 octave_value_list tree_evaluator::eval (const std::string& try_code, 702 int nargout) 703 { 704 int parse_status = 0; 705 706 return eval_string (try_code, nargout > 0, parse_status, nargout); 707 } 708 eval(const std::string & try_code,const std::string & catch_code,int nargout)709 octave_value_list tree_evaluator::eval (const std::string& try_code, 710 const std::string& catch_code, 711 int nargout) 712 { 713 octave_value_list retval; 714 715 error_system& es = m_interpreter.get_error_system (); 716 717 int parse_status = 0; 718 719 bool execution_error = false; 720 721 octave_value_list tmp; 722 723 try 724 { 725 tmp = eval_string (try_code, nargout > 0, parse_status, nargout); 726 } 727 catch (const execution_exception& ee) 728 { 729 es.save_exception (ee); 730 m_interpreter.recover_from_exception (); 731 732 execution_error = true; 733 } 734 735 if (parse_status != 0 || execution_error) 736 { 737 tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); 738 739 retval = (nargout > 0) ? tmp : octave_value_list (); 740 } 741 else 742 { 743 if (nargout > 0) 744 retval = tmp; 745 746 // FIXME: we should really be rethrowing whatever 747 // exception occurred, not just throwing an 748 // execution exception. 749 if (execution_error) 750 throw execution_exception (); 751 } 752 753 return retval; 754 } 755 evalin(const std::string & context,const std::string & try_code,int nargout)756 octave_value_list tree_evaluator::evalin (const std::string& context, 757 const std::string& try_code, 758 int nargout) 759 { 760 unwind_action act ([this] (std::size_t frm) 761 { 762 m_call_stack.restore_frame (frm); 763 }, m_call_stack.current_frame ()); 764 765 if (context == "caller") 766 m_call_stack.goto_caller_frame (); 767 else if (context == "base") 768 m_call_stack.goto_base_frame (); 769 else 770 error ("evalin: CONTEXT must be \"caller\" or \"base\""); 771 772 int parse_status = 0; 773 774 return eval_string (try_code, nargout > 0, parse_status, nargout); 775 } 776 evalin(const std::string & context,const std::string & try_code,const std::string & catch_code,int nargout)777 octave_value_list tree_evaluator::evalin (const std::string& context, 778 const std::string& try_code, 779 const std::string& catch_code, 780 int nargout) 781 { 782 octave_value_list retval; 783 784 unwind_action act1 ([this] (std::size_t frm) 785 { 786 m_call_stack.restore_frame (frm); 787 }, m_call_stack.current_frame ()); 788 789 if (context == "caller") 790 m_call_stack.goto_caller_frame (); 791 else if (context == "base") 792 m_call_stack.goto_base_frame (); 793 else 794 error ("evalin: CONTEXT must be \"caller\" or \"base\""); 795 796 error_system& es = m_interpreter.get_error_system (); 797 798 int parse_status = 0; 799 800 bool execution_error = false; 801 802 octave_value_list tmp; 803 804 try 805 { 806 tmp = eval_string (try_code, nargout > 0, parse_status, nargout); 807 } 808 catch (const execution_exception& ee) 809 { 810 es.save_exception (ee); 811 m_interpreter.recover_from_exception (); 812 813 execution_error = true; 814 } 815 816 if (parse_status != 0 || execution_error) 817 { 818 tmp = eval_string (catch_code, nargout > 0, parse_status, nargout); 819 820 retval = (nargout > 0) ? tmp : octave_value_list (); 821 } 822 else 823 { 824 if (nargout > 0) 825 retval = tmp; 826 827 // FIXME: we should really be rethrowing whatever 828 // exception occurred, not just throwing an 829 // execution exception. 830 if (execution_error) 831 throw execution_exception (); 832 } 833 834 return retval; 835 } 836 837 void visit_anon_fcn_handle(tree_anon_fcn_handle &)838 tree_evaluator::visit_anon_fcn_handle (tree_anon_fcn_handle&) 839 { 840 panic_impossible (); 841 } 842 843 void visit_argument_list(tree_argument_list &)844 tree_evaluator::visit_argument_list (tree_argument_list&) 845 { 846 panic_impossible (); 847 } 848 849 void visit_binary_expression(tree_binary_expression &)850 tree_evaluator::visit_binary_expression (tree_binary_expression&) 851 { 852 panic_impossible (); 853 } 854 855 void visit_boolean_expression(tree_boolean_expression &)856 tree_evaluator::visit_boolean_expression (tree_boolean_expression&) 857 { 858 panic_impossible (); 859 } 860 861 void visit_compound_binary_expression(tree_compound_binary_expression &)862 tree_evaluator::visit_compound_binary_expression (tree_compound_binary_expression&) 863 { 864 panic_impossible (); 865 } 866 867 void visit_break_command(tree_break_command & cmd)868 tree_evaluator::visit_break_command (tree_break_command& cmd) 869 { 870 if (m_echo_state) 871 { 872 std::size_t line = cmd.line (); 873 echo_code (line); 874 m_echo_file_pos = line + 1; 875 } 876 877 if (m_debug_mode) 878 do_breakpoint (cmd.is_active_breakpoint (*this)); 879 880 if (m_in_loop_command) 881 m_breaking = 1; 882 else 883 error ("break must appear in a loop in the same file as loop command"); 884 } 885 886 void visit_colon_expression(tree_colon_expression &)887 tree_evaluator::visit_colon_expression (tree_colon_expression&) 888 { 889 panic_impossible (); 890 } 891 892 void visit_continue_command(tree_continue_command & cmd)893 tree_evaluator::visit_continue_command (tree_continue_command& cmd) 894 { 895 if (m_echo_state) 896 { 897 std::size_t line = cmd.line (); 898 echo_code (line); 899 m_echo_file_pos = line + 1; 900 } 901 902 if (m_debug_mode) 903 do_breakpoint (cmd.is_active_breakpoint (*this)); 904 905 if (m_in_loop_command) 906 m_continuing = 1; 907 } 908 909 bool statement_printing_enabled(void)910 tree_evaluator::statement_printing_enabled (void) 911 { 912 return ! (m_silent_functions && (m_statement_context == SC_FUNCTION 913 || m_statement_context == SC_SCRIPT)); 914 } 915 916 void reset_debug_state(void)917 tree_evaluator::reset_debug_state (void) 918 { 919 m_debug_mode = (m_bp_table.have_breakpoints () || m_dbstep_flag != 0 920 || in_debug_repl ()); 921 } 922 923 void reset_debug_state(bool mode)924 tree_evaluator::reset_debug_state (bool mode) 925 { 926 m_debug_mode = mode; 927 } 928 929 void enter_debugger(const std::string & prompt)930 tree_evaluator::enter_debugger (const std::string& prompt) 931 { 932 unwind_protect frame; 933 934 frame.add_fcn (command_history::ignore_entries, 935 command_history::ignoring_entries ()); 936 937 command_history::ignore_entries (false); 938 939 frame.add_method (m_call_stack, &call_stack::restore_frame, 940 m_call_stack.current_frame ()); 941 942 // Don't allow errors or warnings at the debug prompt to push us 943 // into deeper levels of debugging. 944 945 error_system& es = m_interpreter.get_error_system (); 946 947 frame.add_method (es, &error_system::set_debug_on_error, 948 es.debug_on_error ()); 949 950 frame.add_method (es, &error_system::set_debug_on_warning, 951 es.debug_on_warning ()); 952 953 es.debug_on_error (false); 954 es.debug_on_warning (false); 955 956 // Go up to the nearest user code frame. 957 958 m_debug_frame = m_call_stack.dbupdown (0); 959 960 // FIXME: probably we just want to print one line, not the 961 // entire statement, which might span many lines... 962 // 963 // tree_print_code tpc (octave_stdout); 964 // stmt.accept (tpc); 965 966 debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ()); 967 968 m_debugger_stack.push (dbgr); 969 970 frame.add ([this] (void) 971 { 972 delete m_debugger_stack.top (); 973 m_debugger_stack.pop (); 974 }); 975 976 dbgr->repl (prompt); 977 } 978 979 void keyboard(const std::string & prompt)980 tree_evaluator::keyboard (const std::string& prompt) 981 { 982 enter_debugger (prompt); 983 } 984 985 void dbupdown(int n,bool verbose)986 tree_evaluator::dbupdown (int n, bool verbose) 987 { 988 m_debug_frame = m_call_stack.dbupdown (n, verbose); 989 } 990 991 Matrix ignored_fcn_outputs(void) const992 tree_evaluator::ignored_fcn_outputs (void) const 993 { 994 Matrix retval; 995 996 const std::list<octave_lvalue> *lvalues = m_lvalue_list; 997 998 if (! lvalues) 999 return retval; 1000 1001 octave_idx_type nbh = 0; 1002 1003 for (const auto& lval : *lvalues) 1004 nbh += lval.is_black_hole (); 1005 1006 if (nbh > 0) 1007 { 1008 retval.resize (1, nbh); 1009 1010 octave_idx_type k = 0; 1011 octave_idx_type l = 0; 1012 1013 for (const auto& lval : *lvalues) 1014 { 1015 if (lval.is_black_hole ()) 1016 retval(l++) = k+1; 1017 1018 k += lval.numel (); 1019 } 1020 } 1021 1022 return retval; 1023 } 1024 1025 // If NAME is an operator (like "+", "-", ...), convert it to the 1026 // corresponding function name ("plus", "minus", ...). 1027 1028 static std::string get_operator_function_name(const std::string & name)1029 get_operator_function_name (const std::string& name) 1030 { 1031 // Bow to the god of compatibility. 1032 1033 // FIXME: it seems ugly to put this here, but there is no single 1034 // function in the parser that converts from the operator name to 1035 // the corresponding function name. At least try to do it without N 1036 // string compares. 1037 1038 std::size_t len = name.length (); 1039 1040 if (len == 3 && name == ".**") 1041 return "power"; 1042 else if (len == 2) 1043 { 1044 if (name[0] == '.') 1045 { 1046 switch (name[1]) 1047 { 1048 case '\'': 1049 return "transpose"; 1050 1051 case '+': 1052 return "plus"; 1053 1054 case '-': 1055 return "minus"; 1056 1057 case '*': 1058 return "times"; 1059 1060 case '/': 1061 return "rdivide"; 1062 1063 case '^': 1064 return "power"; 1065 1066 case '\\': 1067 return "ldivide"; 1068 1069 default: 1070 break; 1071 } 1072 } 1073 else if (name[1] == '=') 1074 { 1075 switch (name[0]) 1076 { 1077 case '<': 1078 return "le"; 1079 1080 case '=': 1081 return "eq"; 1082 1083 case '>': 1084 return "ge"; 1085 1086 case '~': 1087 case '!': 1088 return "ne"; 1089 1090 default: 1091 break; 1092 } 1093 } 1094 else if (name == "**") 1095 return "mpower"; 1096 } 1097 else if (len == 1) 1098 { 1099 switch (name[0]) 1100 { 1101 case '~': 1102 case '!': 1103 return "not"; 1104 1105 case '\'': 1106 return "ctranspose"; 1107 1108 case '+': 1109 return "plus"; 1110 1111 case '-': 1112 return "minus"; 1113 1114 case '*': 1115 return "mtimes"; 1116 1117 case '/': 1118 return "mrdivide"; 1119 1120 case '^': 1121 return "mpower"; 1122 1123 case '\\': 1124 return "mldivide"; 1125 1126 case '<': 1127 return "lt"; 1128 1129 case '>': 1130 return "gt"; 1131 1132 case '&': 1133 return "and"; 1134 1135 case '|': 1136 return "or"; 1137 1138 default: 1139 break; 1140 } 1141 } 1142 1143 return name; 1144 } 1145 1146 // Creates a function handle that takes into account the context, 1147 // finding local, nested, private, or sub functions. 1148 1149 octave_value make_fcn_handle(const std::string & name)1150 tree_evaluator::make_fcn_handle (const std::string& name) 1151 { 1152 octave_value retval; 1153 1154 // The str2func function can create a function handle with the name 1155 // of an operator (for example, "+"). If so, it is converted to the 1156 // name of the corresponding function ("+" -> "plus") and we create 1157 // a simple function handle using that name. 1158 1159 std::string fcn_name = get_operator_function_name (name); 1160 1161 // If FCN_NAME is different from NAME, then NAME is an operator. As 1162 // of version 2020a, Matlab apparently uses the function name 1163 // corresponding to the operator to search for private and local 1164 // functions in the current scope but not(!) nested functions. 1165 1166 bool name_is_operator = fcn_name != name; 1167 1168 std::size_t pos = fcn_name.find ('.'); 1169 1170 if (pos != std::string::npos) 1171 { 1172 // Recognize (some of? which ones?) the following cases 1173 // and create something other than a simple function handle? 1174 // Should we just be checking for the last two when the first 1175 // element of the dot-separated list is an object? If so, then 1176 // should this syntax be limited to a dot-separated list with 1177 // exactly two elements? 1178 // 1179 // object . method 1180 // object . static-method 1181 // 1182 // Code to do that duplicates some of simple_fcn_handle::call. 1183 1184 // Only accept expressions that contain one '.' separator. 1185 1186 // FIXME: The logic here is a bit complicated. Is there a good 1187 // way to simplify it? 1188 1189 std::string meth_nm = fcn_name.substr (pos+1); 1190 1191 if (meth_nm.find ('.') == std::string::npos) 1192 { 1193 std::string obj_nm = fcn_name.substr (0, pos); 1194 1195 // If obj_nm is an object in the current scope with a 1196 // method named meth_nm, create a classsimple handle. 1197 1198 octave_value object = varval (obj_nm); 1199 1200 if (object.is_defined () && object.is_classdef_object ()) 1201 { 1202 octave_classdef *cdef = object.classdef_object_value (); 1203 1204 if (cdef) 1205 { 1206 std::string class_nm = cdef->class_name (); 1207 1208 cdef_object cdef_obj = cdef->get_object (); 1209 1210 cdef_class cls = cdef_obj.get_class (); 1211 1212 cdef_method meth = cls.find_method (meth_nm); 1213 1214 if (meth.ok ()) 1215 { 1216 // If the method we found is static, create a 1217 // new function name from the class name and 1218 // method name and create a simple function 1219 // handle below. Otherwise, create a class 1220 // simple function handle. 1221 1222 if (meth.is_static ()) 1223 fcn_name = class_nm + '.' + meth_nm; 1224 else 1225 { 1226 octave_value meth_fcn = meth.get_function (); 1227 1228 octave_fcn_handle *fh 1229 = new octave_fcn_handle (object, meth_fcn, 1230 class_nm, meth_nm); 1231 1232 return octave_value (fh); 1233 } 1234 } 1235 } 1236 } 1237 } 1238 1239 // We didn't match anything above, so create handle to SIMPLE 1240 // package function or static class method. Function resolution 1241 // is performed when the handle is used. 1242 1243 return octave_value (new octave_fcn_handle (fcn_name)); 1244 } 1245 1246 // If the function name refers to a sub/local/private function or a 1247 // class method/constructor, create scoped function handle that is 1248 // bound to that function. Use the same precedence list as 1249 // fcn_info::find but limit search to the following types of 1250 // functions: 1251 // 1252 // nested functions (and subfunctions) 1253 // local functions in the current file 1254 // private function 1255 // class method 1256 // 1257 // For anything else we create a simple function handle that will be 1258 // resolved dynamically in the scope where it is evaluated. 1259 1260 symbol_scope curr_scope = get_current_scope (); 1261 1262 symbol_table& symtab = m_interpreter.get_symbol_table (); 1263 1264 if (curr_scope) 1265 { 1266 octave_value ov_fcn 1267 = symtab.find_scoped_function (fcn_name, curr_scope); 1268 1269 // If name is operator, we are in Fstr2func, so skip the stack 1270 // frame for that function. 1271 1272 bool skip_first = name_is_operator; 1273 octave_function *curr_fcn = current_function (skip_first); 1274 1275 if (ov_fcn.is_defined ()) 1276 { 1277 octave_function *fcn = ov_fcn.function_value (); 1278 1279 if (fcn->is_nested_function ()) 1280 { 1281 if (! name_is_operator) 1282 { 1283 // Get current stack frame and return handle to nested 1284 // function. 1285 1286 std::shared_ptr<stack_frame> frame 1287 = m_call_stack.get_current_stack_frame (); 1288 1289 // If we are creating a handle to the current 1290 // function or a handle to a sibling function (i.e., 1291 // not a child of the current function), then use 1292 // the calling stack frame as the context instead of 1293 // the current stack frame. 1294 1295 // FIXME: Do we need both checks here or is it 1296 // sufficient to check that the parent of curr_fcn 1297 // is the same as the parent of fcn? Is there any 1298 // case where curr_fcn could be nullptr, or does 1299 // that indicate an internal error of some kind? 1300 1301 if (curr_fcn 1302 && (fcn_name == curr_fcn->name () 1303 || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ())) 1304 frame = frame->access_link (); 1305 1306 octave_fcn_handle *fh 1307 = new octave_fcn_handle (ov_fcn, fcn_name, frame); 1308 1309 return octave_value (fh); 1310 } 1311 } 1312 else if (fcn->is_subfunction () 1313 /* || fcn->is_localfunction () */ 1314 || fcn->is_private_function ()) 1315 { 1316 // Create handle to SCOPED function (sub/local function 1317 // or private function). 1318 1319 std::list<std::string> parentage = fcn->parent_fcn_names (); 1320 1321 octave_fcn_handle *fh 1322 = new octave_fcn_handle (ov_fcn, fcn_name, parentage); 1323 1324 return octave_value (fh); 1325 } 1326 } 1327 1328 if (curr_fcn && (curr_fcn->is_class_method () 1329 || curr_fcn->is_class_constructor ())) 1330 { 1331 std::string dispatch_class = curr_fcn->dispatch_class (); 1332 1333 octave_value ov_meth 1334 = symtab.find_method (fcn_name, dispatch_class); 1335 1336 if (ov_meth.is_defined ()) 1337 { 1338 octave_function *fcn = ov_meth.function_value (); 1339 1340 // FIXME: do we need to check that it is a method of 1341 // dispatch_class, or is it sufficient to just check 1342 // that it is a method? 1343 1344 if (fcn->is_class_method ()) 1345 { 1346 // Create CLASSSIMPLE handle to method but don't 1347 // bind to the method. Lookup will be done later. 1348 1349 octave_fcn_handle *fh 1350 = new octave_fcn_handle (dispatch_class, fcn_name); 1351 1352 return octave_value (fh); 1353 } 1354 } 1355 } 1356 } 1357 1358 octave_value ov_fcn = symtab.find_user_function (fcn_name); 1359 1360 // Create handle to SIMPLE function. If the function is not found 1361 // now, then we will look for it again when the handle is used. 1362 1363 return octave_value (new octave_fcn_handle (ov_fcn, fcn_name)); 1364 } 1365 1366 /* 1367 %!test 1368 %! x = {".**", "power"; 1369 %! ".'", "transpose"; 1370 %! ".+", "plus"; 1371 %! ".-", "minus"; 1372 %! ".*", "times"; 1373 %! "./", "rdivide"; 1374 %! ".^", "power"; 1375 %! ".\\", "ldivide"; 1376 %! "<=", "le"; 1377 %! "==", "eq"; 1378 %! ">=", "ge"; 1379 %! "!=", "ne"; 1380 %! "~=", "ne"; 1381 %! "**", "mpower"; 1382 %! "~", "not"; 1383 %! "!", "not"; 1384 %! "\'", "ctranspose"; 1385 %! "+", "plus"; 1386 %! "-", "minus"; 1387 %! "*", "mtimes"; 1388 %! "/", "mrdivide"; 1389 %! "^", "mpower"; 1390 %! "\\", "mldivide"; 1391 %! "<", "lt"; 1392 %! ">", "gt"; 1393 %! "&", "and"; 1394 %! "|", "or"}; 1395 %! for i = 1:rows (x) 1396 %! assert (functions (str2func (x{i,1})).function, x{i,2}); 1397 %! endfor 1398 */ 1399 1400 octave_value evaluate(tree_decl_elt * elt)1401 tree_evaluator::evaluate (tree_decl_elt *elt) 1402 { 1403 // Do not allow functions to return null values. 1404 1405 tree_identifier *id = elt->ident (); 1406 1407 return id ? id->evaluate (*this).storable_value () : octave_value (); 1408 } 1409 1410 bool is_variable(const std::string & name) const1411 tree_evaluator::is_variable (const std::string& name) const 1412 { 1413 std::shared_ptr<stack_frame> frame 1414 = m_call_stack.get_current_stack_frame (); 1415 1416 return frame->is_variable (name); 1417 } 1418 1419 bool is_local_variable(const std::string & name) const1420 tree_evaluator::is_local_variable (const std::string& name) const 1421 { 1422 std::shared_ptr<stack_frame> frame 1423 = m_call_stack.get_current_stack_frame (); 1424 1425 return frame->is_local_variable (name); 1426 } 1427 1428 bool is_variable(const tree_expression * expr) const1429 tree_evaluator::is_variable (const tree_expression *expr) const 1430 { 1431 if (expr->is_identifier ()) 1432 { 1433 const tree_identifier *id 1434 = dynamic_cast<const tree_identifier *> (expr); 1435 1436 if (id->is_black_hole ()) 1437 return false; 1438 1439 return is_variable (id->symbol ()); 1440 } 1441 1442 return false; 1443 } 1444 1445 bool is_defined(const tree_expression * expr) const1446 tree_evaluator::is_defined (const tree_expression *expr) const 1447 { 1448 if (expr->is_identifier ()) 1449 { 1450 const tree_identifier *id 1451 = dynamic_cast<const tree_identifier *> (expr); 1452 1453 return is_defined (id->symbol ()); 1454 } 1455 1456 return false; 1457 } 1458 1459 bool is_variable(const symbol_record & sym) const1460 tree_evaluator::is_variable (const symbol_record& sym) const 1461 { 1462 std::shared_ptr<stack_frame> frame 1463 = m_call_stack.get_current_stack_frame (); 1464 1465 return frame->is_variable (sym); 1466 } 1467 1468 bool is_defined(const symbol_record & sym) const1469 tree_evaluator::is_defined (const symbol_record& sym) const 1470 { 1471 std::shared_ptr<stack_frame> frame 1472 = m_call_stack.get_current_stack_frame (); 1473 1474 return frame->is_defined (sym); 1475 } 1476 is_global(const std::string & name) const1477 bool tree_evaluator::is_global (const std::string& name) const 1478 { 1479 std::shared_ptr<stack_frame> frame 1480 = m_call_stack.get_current_stack_frame (); 1481 1482 return frame->is_global (name); 1483 } 1484 1485 octave_value varval(const symbol_record & sym) const1486 tree_evaluator::varval (const symbol_record& sym) const 1487 { 1488 std::shared_ptr<stack_frame> frame 1489 = m_call_stack.get_current_stack_frame (); 1490 1491 return frame->varval (sym); 1492 } 1493 1494 octave_value varval(const std::string & name) const1495 tree_evaluator::varval (const std::string& name) const 1496 { 1497 std::shared_ptr<stack_frame> frame 1498 = m_call_stack.get_current_stack_frame (); 1499 1500 return frame->varval (name); 1501 } 1502 install_variable(const std::string & name,const octave_value & value,bool global)1503 void tree_evaluator::install_variable (const std::string& name, 1504 const octave_value& value, 1505 bool global) 1506 { 1507 std::shared_ptr<stack_frame> frame 1508 = m_call_stack.get_current_stack_frame (); 1509 1510 return frame->install_variable (name, value, global); 1511 } 1512 1513 octave_value global_varval(const std::string & name) const1514 tree_evaluator::global_varval (const std::string& name) const 1515 { 1516 return m_call_stack.global_varval (name); 1517 } 1518 1519 octave_value& global_varref(const std::string & name)1520 tree_evaluator::global_varref (const std::string& name) 1521 { 1522 return m_call_stack.global_varref (name); 1523 } 1524 1525 void global_assign(const std::string & name,const octave_value & val)1526 tree_evaluator::global_assign (const std::string& name, 1527 const octave_value& val) 1528 { 1529 m_call_stack.global_varref (name) = val; 1530 } 1531 1532 octave_value top_level_varval(const std::string & name) const1533 tree_evaluator::top_level_varval (const std::string& name) const 1534 { 1535 return m_call_stack.get_top_level_value (name); 1536 } 1537 1538 void top_level_assign(const std::string & name,const octave_value & val)1539 tree_evaluator::top_level_assign (const std::string& name, 1540 const octave_value& val) 1541 { 1542 m_call_stack.set_top_level_value (name, val); 1543 } 1544 1545 void assign(const std::string & name,const octave_value & val)1546 tree_evaluator::assign (const std::string& name, const octave_value& val) 1547 { 1548 std::shared_ptr<stack_frame> frame 1549 = m_call_stack.get_current_stack_frame (); 1550 1551 frame->assign (name, val); 1552 } 1553 1554 void assignin(const std::string & context,const std::string & name,const octave_value & val)1555 tree_evaluator::assignin (const std::string& context, 1556 const std::string& name, const octave_value& val) 1557 { 1558 // FIXME: Can this be done without an unwind-protect frame, simply 1559 // by getting a reference to the caller or base stack frame and 1560 // calling assign on that? 1561 1562 unwind_action act ([this] (std::size_t frm) 1563 { 1564 m_call_stack.restore_frame (frm); 1565 }, m_call_stack.current_frame ()); 1566 1567 if (context == "caller") 1568 m_call_stack.goto_caller_frame (); 1569 else if (context == "base") 1570 m_call_stack.goto_base_frame (); 1571 else 1572 error ("assignin: CONTEXT must be \"caller\" or \"base\""); 1573 1574 if (valid_identifier (name)) 1575 { 1576 // Put the check here so that we don't slow down assignments 1577 // generally. Any that go through Octave's parser should have 1578 // already been checked. 1579 1580 if (iskeyword (name)) 1581 error ("assignin: invalid assignment to keyword '%s'", 1582 name.c_str ()); 1583 1584 assign (name, val); 1585 } 1586 else 1587 error ("assignin: invalid variable name '%s'", name.c_str ()); 1588 } 1589 1590 void source_file(const std::string & file_name,const std::string & context,bool verbose,bool require_file)1591 tree_evaluator::source_file (const std::string& file_name, 1592 const std::string& context, 1593 bool verbose, bool require_file) 1594 { 1595 // Map from absolute name of script file to recursion level. We 1596 // use a map instead of simply placing a limit on recursion in the 1597 // source_file function so that two mutually recursive scripts 1598 // written as 1599 // 1600 // foo1.m: 1601 // ------ 1602 // foo2 1603 // 1604 // foo2.m: 1605 // ------ 1606 // foo1 1607 // 1608 // and called with 1609 // 1610 // foo1 1611 // 1612 // (for example) will behave the same if they are written as 1613 // 1614 // foo1.m: 1615 // ------ 1616 // source ("foo2.m") 1617 // 1618 // foo2.m: 1619 // ------ 1620 // source ("foo1.m") 1621 // 1622 // and called with 1623 // 1624 // source ("foo1.m") 1625 // 1626 // (for example). 1627 1628 static std::map<std::string, int> source_call_depth; 1629 1630 std::string file_full_name 1631 = sys::file_ops::tilde_expand (file_name); 1632 1633 std::size_t pos 1634 = file_full_name.find_last_of (sys::file_ops::dir_sep_str ()); 1635 1636 std::string dir_name = file_full_name.substr (0, pos); 1637 1638 file_full_name = sys::env::make_absolute (file_full_name); 1639 1640 unwind_protect frame; 1641 1642 if (source_call_depth.find (file_full_name) == source_call_depth.end ()) 1643 source_call_depth[file_full_name] = -1; 1644 1645 frame.protect_var (source_call_depth[file_full_name]); 1646 1647 source_call_depth[file_full_name]++; 1648 1649 if (source_call_depth[file_full_name] >= max_recursion_depth ()) 1650 error ("max_recursion_depth exceeded"); 1651 1652 if (! context.empty ()) 1653 { 1654 frame.add_method (m_call_stack, &call_stack::restore_frame, 1655 m_call_stack.current_frame ()); 1656 1657 if (context == "caller") 1658 m_call_stack.goto_caller_frame (); 1659 else if (context == "base") 1660 m_call_stack.goto_base_frame (); 1661 else 1662 error ("source: context must be \"caller\" or \"base\""); 1663 } 1664 1665 // Find symbol name that would be in symbol_table, if it were loaded. 1666 std::size_t dir_end 1667 = file_name.find_last_of (sys::file_ops::dir_sep_chars ()); 1668 dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1; 1669 1670 std::size_t extension = file_name.find_last_of ('.'); 1671 if (extension == std::string::npos) 1672 extension = file_name.length (); 1673 1674 std::string symbol = file_name.substr (dir_end, extension - dir_end); 1675 std::string full_name = sys::canonicalize_file_name (file_name); 1676 1677 // Check if this file is already loaded (or in the path) 1678 symbol_table& symtab = m_interpreter.get_symbol_table (); 1679 octave_value ov_code = symtab.fcn_table_find (symbol); 1680 1681 // For compatibility with Matlab, accept both scripts and 1682 // functions. 1683 1684 if (ov_code.is_user_code ()) 1685 { 1686 octave_user_code *code = ov_code.user_code_value (); 1687 1688 if (! code 1689 || (sys::canonicalize_file_name (code->fcn_file_name ()) 1690 != full_name)) 1691 { 1692 // Wrong file, so load it below. 1693 ov_code = octave_value (); 1694 } 1695 } 1696 else 1697 { 1698 // Not a script, so load it below. 1699 ov_code = octave_value (); 1700 } 1701 1702 // If no symbol of this name, or the symbol is for a different 1703 // file, load. 1704 1705 if (ov_code.is_undefined ()) 1706 { 1707 try 1708 { 1709 ov_code = parse_fcn_file (m_interpreter, file_full_name, 1710 file_name, dir_name, "", "", 1711 require_file, true, false, false); 1712 } 1713 catch (execution_exception& e) 1714 { 1715 error (e, "source: error sourcing file '%s'", 1716 file_full_name.c_str ()); 1717 } 1718 } 1719 1720 // Return or error if we don't have a valid script or function. 1721 1722 if (ov_code.is_undefined ()) 1723 return; 1724 1725 if (! ov_code.is_user_code ()) 1726 error ("source: %s is not a script", full_name.c_str ()); 1727 1728 if (verbose) 1729 { 1730 octave_stdout << "executing commands from " << full_name << " ... "; 1731 octave_stdout.flush (); 1732 } 1733 1734 octave_user_code *code = ov_code.user_code_value (); 1735 1736 code->call (*this, 0, octave_value_list ()); 1737 1738 if (verbose) 1739 octave_stdout << "done." << std::endl; 1740 } 1741 1742 void set_auto_fcn_var(stack_frame::auto_var_type avt,const octave_value & val)1743 tree_evaluator::set_auto_fcn_var (stack_frame::auto_var_type avt, 1744 const octave_value& val) 1745 { 1746 m_call_stack.set_auto_fcn_var (avt, val); 1747 } 1748 1749 octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const1750 tree_evaluator::get_auto_fcn_var (stack_frame::auto_var_type avt) const 1751 { 1752 return m_call_stack.get_auto_fcn_var (avt); 1753 } 1754 1755 void define_parameter_list_from_arg_vector(tree_parameter_list * param_list,const octave_value_list & args)1756 tree_evaluator::define_parameter_list_from_arg_vector 1757 (tree_parameter_list *param_list, const octave_value_list& args) 1758 { 1759 int i = -1; 1760 1761 for (tree_decl_elt *elt : *param_list) 1762 { 1763 i++; 1764 1765 octave_lvalue ref = elt->lvalue (*this); 1766 1767 if (i < args.length ()) 1768 { 1769 if (args(i).is_defined () && args(i).is_magic_colon ()) 1770 { 1771 if (! eval_decl_elt (elt)) 1772 error ("no default value for argument %d", i+1); 1773 } 1774 else 1775 ref.define (args(i)); 1776 } 1777 else 1778 eval_decl_elt (elt); 1779 } 1780 } 1781 1782 void undefine_parameter_list(tree_parameter_list * param_list)1783 tree_evaluator::undefine_parameter_list (tree_parameter_list *param_list) 1784 { 1785 for (tree_decl_elt *elt : *param_list) 1786 { 1787 octave_lvalue ref = elt->lvalue (*this); 1788 1789 ref.assign (octave_value::op_asn_eq, octave_value ()); 1790 } 1791 } 1792 } 1793 1794 // END is documented in op-kw-docs. 1795 DEFCONSTMETHOD (end, interp, args, , 1796 doc: /* -*- texinfo -*- 1797 @deftypefn {} {} end 1798 Last element of an array or the end of any @code{for}, @code{parfor}, 1799 @code{if}, @code{do}, @code{while}, @code{function}, @code{switch}, 1800 @code{try}, or @code{unwind_protect} block. 1801 1802 As an index of an array, the magic index @qcode{"end"} refers to the 1803 last valid entry in an indexing operation. 1804 1805 Example: 1806 1807 @example 1808 @group 1809 @var{x} = [ 1 2 3; 4 5 6 ]; 1810 @var{x}(1,end) 1811 @result{} 3 1812 @var{x}(end,1) 1813 @result{} 4 1814 @var{x}(end,end) 1815 @result{} 6 1816 @end group 1817 @end example 1818 @seealso{for, parfor, if, do, while, function, switch, try, unwind_protect} 1819 @end deftypefn */) 1820 { 1821 octave::tree_evaluator& tw = interp.get_evaluator (); 1822 1823 return tw.evaluate_end_expression (args); 1824 } 1825 1826 /* 1827 %!test <*58830> 1828 %! fail ("__undef_sym__ (end)", 1829 %! "invalid use of 'end': may only be used to index existing value"); 1830 1831 %!test <58953> 1832 %! x = 1:10; 1833 %! assert (x(end), 10); 1834 %! assert (x(minus (end, 1)), 9); 1835 %! assert (x(minus (minus (end, 1), 1)), 8); 1836 */ 1837 1838 namespace octave 1839 { 1840 octave_value_list convert_to_const_vector(tree_argument_list * args)1841 tree_evaluator::convert_to_const_vector (tree_argument_list *args) 1842 { 1843 std::list<octave_value> arg_vals; 1844 1845 for (auto elt : *args) 1846 { 1847 // FIXME: is it possible for elt to be invalid? 1848 1849 if (! elt) 1850 break; 1851 1852 octave_value tmp = elt->evaluate (*this); 1853 1854 if (tmp.is_cs_list ()) 1855 { 1856 octave_value_list tmp_ovl = tmp.list_value (); 1857 1858 for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) 1859 arg_vals.push_back (tmp_ovl(i)); 1860 } 1861 else if (tmp.is_defined ()) 1862 arg_vals.push_back (tmp); 1863 } 1864 1865 return octave_value_list (arg_vals); 1866 } 1867 1868 octave_value_list convert_return_list_to_const_vector(tree_parameter_list * ret_list,int nargout,const Matrix & ignored_outputs,const Cell & varargout)1869 tree_evaluator::convert_return_list_to_const_vector 1870 (tree_parameter_list *ret_list, int nargout, const Matrix& ignored_outputs, 1871 const Cell& varargout) 1872 { 1873 octave_idx_type vlen = varargout.numel (); 1874 int len = ret_list->length (); 1875 1876 // Special case. Will do a shallow copy. 1877 if (len == 0) 1878 return varargout; 1879 else 1880 { 1881 int i = 0; 1882 int k = 0; 1883 int num_ignored = ignored_outputs.numel (); 1884 int ignored = num_ignored > 0 ? ignored_outputs(k) - 1 : -1; 1885 1886 if (nargout <= len) 1887 { 1888 int nout = nargout > 0 ? nargout : 1; 1889 octave_value_list retval (nout); 1890 1891 for (tree_decl_elt *elt : *ret_list) 1892 { 1893 if (nargout == 0 && ! is_defined (elt->ident ())) 1894 break; 1895 1896 if (ignored >= 0 && i == ignored) 1897 { 1898 i++; 1899 k++; 1900 ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; 1901 } 1902 else 1903 retval(i++) = evaluate (elt); 1904 1905 if (i == nout) 1906 break; 1907 } 1908 1909 return retval; 1910 } 1911 else 1912 { 1913 octave_value_list retval (len + vlen); 1914 1915 for (tree_decl_elt *elt : *ret_list) 1916 { 1917 if (ignored >= 0 && i == ignored) 1918 { 1919 i++; 1920 k++; 1921 ignored = k < num_ignored ? ignored_outputs(k) - 1 : -1; 1922 } 1923 else 1924 retval(i++) = evaluate (elt); 1925 } 1926 1927 for (octave_idx_type j = 0; j < vlen; j++) 1928 retval(i++) = varargout(j); 1929 1930 return retval; 1931 } 1932 } 1933 } 1934 1935 bool eval_decl_elt(tree_decl_elt * elt)1936 tree_evaluator::eval_decl_elt (tree_decl_elt *elt) 1937 { 1938 bool retval = false; 1939 1940 tree_identifier *id = elt->ident (); 1941 tree_expression *expr = elt->expression (); 1942 1943 if (id && expr) 1944 { 1945 octave_lvalue ult = id->lvalue (*this); 1946 1947 octave_value init_val = expr->evaluate (*this); 1948 1949 ult.assign (octave_value::op_asn_eq, init_val); 1950 1951 retval = true; 1952 } 1953 1954 return retval; 1955 } 1956 1957 bool switch_case_label_matches(tree_switch_case * expr,const octave_value & val)1958 tree_evaluator::switch_case_label_matches (tree_switch_case *expr, 1959 const octave_value& val) 1960 { 1961 tree_expression *label = expr->case_label (); 1962 1963 octave_value label_value = label->evaluate (*this); 1964 1965 if (label_value.is_defined ()) 1966 { 1967 if (label_value.iscell ()) 1968 { 1969 Cell cell (label_value.cell_value ()); 1970 1971 for (octave_idx_type i = 0; i < cell.rows (); i++) 1972 { 1973 for (octave_idx_type j = 0; j < cell.columns (); j++) 1974 { 1975 bool match = val.is_equal (cell(i,j)); 1976 1977 if (match) 1978 return true; 1979 } 1980 } 1981 } 1982 else 1983 return val.is_equal (label_value); 1984 } 1985 1986 return false; 1987 } 1988 push_stack_frame(const symbol_scope & scope)1989 void tree_evaluator::push_stack_frame (const symbol_scope& scope) 1990 { 1991 m_call_stack.push (scope); 1992 } 1993 push_stack_frame(octave_user_function * fcn,const std::shared_ptr<stack_frame> & closure_frames)1994 void tree_evaluator::push_stack_frame (octave_user_function *fcn, 1995 const std::shared_ptr<stack_frame>& closure_frames) 1996 { 1997 m_call_stack.push (fcn, closure_frames); 1998 } 1999 push_stack_frame(octave_user_function * fcn,const stack_frame::local_vars_map & local_vars,const std::shared_ptr<stack_frame> & closure_frames)2000 void tree_evaluator::push_stack_frame (octave_user_function *fcn, 2001 const stack_frame::local_vars_map& local_vars, 2002 const std::shared_ptr<stack_frame>& closure_frames) 2003 { 2004 m_call_stack.push (fcn, local_vars, closure_frames); 2005 } 2006 push_stack_frame(octave_user_script * script)2007 void tree_evaluator::push_stack_frame (octave_user_script *script) 2008 { 2009 m_call_stack.push (script); 2010 } 2011 push_stack_frame(octave_function * fcn)2012 void tree_evaluator::push_stack_frame (octave_function *fcn) 2013 { 2014 m_call_stack.push (fcn); 2015 } 2016 pop_stack_frame(void)2017 void tree_evaluator::pop_stack_frame (void) 2018 { 2019 m_call_stack.pop (); 2020 } 2021 current_line(void) const2022 int tree_evaluator::current_line (void) const 2023 { 2024 return m_call_stack.current_line (); 2025 } 2026 current_column(void) const2027 int tree_evaluator::current_column (void) const 2028 { 2029 return m_call_stack.current_column (); 2030 } 2031 debug_user_code_line(void) const2032 int tree_evaluator::debug_user_code_line (void) const 2033 { 2034 return m_call_stack.debug_user_code_line (); 2035 } 2036 debug_user_code_column(void) const2037 int tree_evaluator::debug_user_code_column (void) const 2038 { 2039 return m_call_stack.debug_user_code_column (); 2040 } 2041 debug_where(std::ostream & os) const2042 void tree_evaluator::debug_where (std::ostream& os) const 2043 { 2044 std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame (); 2045 2046 frm->display_stopped_in_message (os); 2047 } 2048 current_user_code(void) const2049 octave_user_code * tree_evaluator::current_user_code (void) const 2050 { 2051 return m_call_stack.current_user_code (); 2052 } 2053 curr_fcn_unwind_protect_frame(void)2054 unwind_protect * tree_evaluator::curr_fcn_unwind_protect_frame (void) 2055 { 2056 return m_call_stack.curr_fcn_unwind_protect_frame (); 2057 } 2058 debug_user_code(void) const2059 octave_user_code * tree_evaluator::debug_user_code (void) const 2060 { 2061 return m_call_stack.debug_user_code (); 2062 } 2063 current_function(bool skip_first) const2064 octave_function * tree_evaluator::current_function (bool skip_first) const 2065 { 2066 return m_call_stack.current_function (skip_first); 2067 } 2068 caller_function(void) const2069 octave_function * tree_evaluator::caller_function (void) const 2070 { 2071 return m_call_stack.current_function (true); 2072 } 2073 goto_frame(std::size_t n,bool verbose)2074 bool tree_evaluator::goto_frame (std::size_t n, bool verbose) 2075 { 2076 return m_call_stack.goto_frame (n, verbose); 2077 } 2078 goto_caller_frame(void)2079 void tree_evaluator::goto_caller_frame (void) 2080 { 2081 m_call_stack.goto_caller_frame (); 2082 } 2083 goto_base_frame(void)2084 void tree_evaluator::goto_base_frame (void) 2085 { 2086 m_call_stack.goto_base_frame (); 2087 } 2088 restore_frame(std::size_t n)2089 void tree_evaluator::restore_frame (std::size_t n) 2090 { 2091 return m_call_stack.restore_frame (n); 2092 } 2093 get_dispatch_class(void) const2094 std::string tree_evaluator::get_dispatch_class (void) const 2095 { 2096 return m_call_stack.get_dispatch_class (); 2097 } 2098 set_dispatch_class(const std::string & class_name)2099 void tree_evaluator::set_dispatch_class (const std::string& class_name) 2100 { 2101 m_call_stack.set_dispatch_class (class_name); 2102 } 2103 2104 bool is_class_method_executing(std::string & dclass) const2105 tree_evaluator::is_class_method_executing (std::string& dclass) const 2106 { 2107 return m_call_stack.is_class_method_executing (dclass); 2108 } 2109 2110 bool is_class_constructor_executing(std::string & dclass) const2111 tree_evaluator::is_class_constructor_executing (std::string& dclass) const 2112 { 2113 return m_call_stack.is_class_constructor_executing (dclass); 2114 } 2115 2116 std::list<std::shared_ptr<stack_frame>> backtrace_frames(octave_idx_type & curr_user_frame) const2117 tree_evaluator::backtrace_frames (octave_idx_type& curr_user_frame) const 2118 { 2119 return m_call_stack.backtrace_frames (curr_user_frame); 2120 } 2121 2122 std::list<std::shared_ptr<stack_frame>> backtrace_frames(void) const2123 tree_evaluator::backtrace_frames (void) const 2124 { 2125 return m_call_stack.backtrace_frames (); 2126 } 2127 2128 std::list<frame_info> backtrace_info(octave_idx_type & curr_user_frame,bool print_subfn) const2129 tree_evaluator::backtrace_info (octave_idx_type& curr_user_frame, 2130 bool print_subfn) const 2131 { 2132 return m_call_stack.backtrace_info (curr_user_frame, print_subfn); 2133 } 2134 backtrace_info(void) const2135 std::list<frame_info> tree_evaluator::backtrace_info (void) const 2136 { 2137 return m_call_stack.backtrace_info (); 2138 } 2139 2140 octave_map backtrace(octave_idx_type & curr_user_frame,bool print_subfn) const2141 tree_evaluator::backtrace (octave_idx_type& curr_user_frame, 2142 bool print_subfn) const 2143 { 2144 return m_call_stack.backtrace (curr_user_frame, print_subfn); 2145 } 2146 backtrace(void) const2147 octave_map tree_evaluator::backtrace (void) const 2148 { 2149 return m_call_stack.backtrace (); 2150 } 2151 empty_backtrace(void) const2152 octave_map tree_evaluator::empty_backtrace (void) const 2153 { 2154 return m_call_stack.empty_backtrace (); 2155 } 2156 backtrace_message(void) const2157 std::string tree_evaluator::backtrace_message (void) const 2158 { 2159 std::list<frame_info> frames = backtrace_info (); 2160 2161 std::ostringstream buf; 2162 2163 for (const auto& frm : frames) 2164 { 2165 buf << " " << frm.fcn_name (); 2166 2167 int line = frm.line (); 2168 2169 if (line > 0) 2170 { 2171 buf << " at line " << line; 2172 2173 int column = frm.column (); 2174 2175 if (column > 0) 2176 buf << " column " << column; 2177 2178 buf << "\n"; 2179 } 2180 } 2181 2182 return buf.str (); 2183 } 2184 push_dummy_scope(const std::string & name)2185 void tree_evaluator::push_dummy_scope (const std::string& name) 2186 { 2187 symbol_scope dummy_scope (name + "$dummy"); 2188 2189 m_call_stack.push (dummy_scope); 2190 } 2191 pop_scope(void)2192 void tree_evaluator::pop_scope (void) 2193 { 2194 m_call_stack.pop (); 2195 } 2196 get_top_scope(void) const2197 symbol_scope tree_evaluator::get_top_scope (void) const 2198 { 2199 return m_call_stack.top_scope (); 2200 } 2201 get_current_scope(void) const2202 symbol_scope tree_evaluator::get_current_scope (void) const 2203 { 2204 return m_call_stack.current_scope (); 2205 } 2206 mlock(bool skip_first) const2207 void tree_evaluator::mlock (bool skip_first) const 2208 { 2209 octave_function *fcn = m_call_stack.current_function (skip_first); 2210 2211 if (! fcn) 2212 error ("mlock: invalid use outside a function"); 2213 2214 if (fcn->is_builtin_function ()) 2215 { 2216 warning ("mlock: locking built-in function has no effect"); 2217 return; 2218 } 2219 2220 fcn->lock (); 2221 } 2222 munlock(bool skip_first) const2223 void tree_evaluator::munlock (bool skip_first) const 2224 { 2225 octave_function *fcn = m_call_stack.current_function (skip_first); 2226 2227 if (! fcn) 2228 error ("munlock: invalid use outside a function"); 2229 2230 if (fcn->is_builtin_function ()) 2231 { 2232 warning ("munlock: unlocking built-in function has no effect"); 2233 return; 2234 } 2235 2236 fcn->unlock (); 2237 } 2238 mislocked(bool skip_first) const2239 bool tree_evaluator::mislocked (bool skip_first) const 2240 { 2241 octave_function *fcn = m_call_stack.current_function (skip_first); 2242 2243 if (! fcn) 2244 error ("mislocked: invalid use outside a function"); 2245 2246 return fcn->islocked (); 2247 } 2248 2249 octave_value max_stack_depth(const octave_value_list & args,int nargout)2250 tree_evaluator::max_stack_depth (const octave_value_list& args, int nargout) 2251 { 2252 return m_call_stack.max_stack_depth (args, nargout); 2253 } 2254 display_call_stack(void) const2255 void tree_evaluator::display_call_stack (void) const 2256 { 2257 m_call_stack.display (); 2258 } 2259 find(const std::string & name)2260 octave_value tree_evaluator::find (const std::string& name) 2261 { 2262 std::shared_ptr<stack_frame> frame 2263 = m_call_stack.get_current_stack_frame (); 2264 2265 octave_value val = frame->varval (name); 2266 2267 if (val.is_defined ()) 2268 return val; 2269 2270 // Subfunction. I think it only makes sense to check for 2271 // subfunctions if we are currently executing a function defined 2272 // from a .m file. 2273 2274 octave_value fcn = frame->find_subfunction (name); 2275 2276 if (fcn.is_defined ()) 2277 return fcn; 2278 2279 symbol_table& symtab = m_interpreter.get_symbol_table (); 2280 2281 return symtab.fcn_table_find (name, ovl ()); 2282 } 2283 clear_objects(void)2284 void tree_evaluator::clear_objects (void) 2285 { 2286 std::shared_ptr<stack_frame> frame 2287 = m_call_stack.get_current_stack_frame (); 2288 2289 frame->clear_objects (); 2290 } 2291 clear_variable(const std::string & name)2292 void tree_evaluator::clear_variable (const std::string& name) 2293 { 2294 std::shared_ptr<stack_frame> frame 2295 = m_call_stack.get_current_stack_frame (); 2296 2297 frame->clear_variable (name); 2298 } 2299 clear_variable_pattern(const std::string & pattern)2300 void tree_evaluator::clear_variable_pattern (const std::string& pattern) 2301 { 2302 std::shared_ptr<stack_frame> frame 2303 = m_call_stack.get_current_stack_frame (); 2304 2305 frame->clear_variable_pattern (pattern); 2306 } 2307 clear_variable_regexp(const std::string & pattern)2308 void tree_evaluator::clear_variable_regexp (const std::string& pattern) 2309 { 2310 std::shared_ptr<stack_frame> frame 2311 = m_call_stack.get_current_stack_frame (); 2312 2313 frame->clear_variable_regexp (pattern); 2314 } 2315 clear_variables(void)2316 void tree_evaluator::clear_variables (void) 2317 { 2318 std::shared_ptr<stack_frame> frame 2319 = m_call_stack.get_current_stack_frame (); 2320 2321 frame->clear_variables (); 2322 } 2323 clear_global_variable(const std::string & name)2324 void tree_evaluator::clear_global_variable (const std::string& name) 2325 { 2326 m_call_stack.clear_global_variable (name); 2327 } 2328 2329 void clear_global_variable_pattern(const std::string & pattern)2330 tree_evaluator::clear_global_variable_pattern (const std::string& pattern) 2331 { 2332 m_call_stack.clear_global_variable_pattern (pattern); 2333 } 2334 clear_global_variable_regexp(const std::string & pattern)2335 void tree_evaluator::clear_global_variable_regexp(const std::string& pattern) 2336 { 2337 m_call_stack.clear_global_variable_regexp (pattern); 2338 } 2339 clear_global_variables(void)2340 void tree_evaluator::clear_global_variables (void) 2341 { 2342 m_call_stack.clear_global_variables (); 2343 } 2344 clear_all(bool force)2345 void tree_evaluator::clear_all (bool force) 2346 { 2347 // FIXME: should this also clear objects? 2348 2349 clear_variables (); 2350 clear_global_variables (); 2351 2352 symbol_table& symtab = m_interpreter.get_symbol_table (); 2353 2354 symtab.clear_functions (force); 2355 } 2356 clear_symbol(const std::string & name)2357 void tree_evaluator::clear_symbol (const std::string& name) 2358 { 2359 // FIXME: are we supposed to do both here? 2360 2361 clear_variable (name); 2362 2363 symbol_table& symtab = m_interpreter.get_symbol_table (); 2364 2365 symtab.clear_function (name); 2366 } 2367 clear_symbol_pattern(const std::string & pattern)2368 void tree_evaluator::clear_symbol_pattern (const std::string& pattern) 2369 { 2370 // FIXME: are we supposed to do both here? 2371 2372 clear_variable_pattern (pattern); 2373 2374 symbol_table& symtab = m_interpreter.get_symbol_table (); 2375 2376 symtab.clear_function_pattern (pattern); 2377 } 2378 clear_symbol_regexp(const std::string & pattern)2379 void tree_evaluator::clear_symbol_regexp (const std::string& pattern) 2380 { 2381 // FIXME: are we supposed to do both here? 2382 2383 clear_variable_regexp (pattern); 2384 2385 symbol_table& symtab = m_interpreter.get_symbol_table (); 2386 2387 symtab.clear_function_regexp (pattern); 2388 } 2389 global_variable_names(void) const2390 std::list<std::string> tree_evaluator::global_variable_names (void) const 2391 { 2392 return m_call_stack.global_variable_names (); 2393 } 2394 top_level_variable_names(void) const2395 std::list<std::string> tree_evaluator::top_level_variable_names (void) const 2396 { 2397 return m_call_stack.top_level_variable_names (); 2398 } 2399 variable_names(void) const2400 std::list<std::string> tree_evaluator::variable_names (void) const 2401 { 2402 return m_call_stack.variable_names (); 2403 } 2404 2405 // Return a pointer to the user-defined function FNAME. If FNAME is empty, 2406 // search backward for the first user-defined function in the 2407 // current call stack. 2408 2409 octave_user_code * get_user_code(const std::string & fname,const std::string & class_name)2410 tree_evaluator::get_user_code (const std::string& fname, 2411 const std::string& class_name) 2412 { 2413 octave_user_code *user_code = nullptr; 2414 2415 if (fname.empty ()) 2416 user_code = m_call_stack.debug_user_code (); 2417 else 2418 { 2419 std::string name = fname; 2420 2421 if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@') 2422 { 2423 auto beg = name.begin () + 2; // never have @/method 2424 auto end = name.end () - 1; // never have trailing '/' 2425 std::replace (beg, end, '/', sys::file_ops::dir_sep_char ()); 2426 } 2427 2428 std::size_t name_len = name.length (); 2429 2430 if (name_len > 2 && name.substr (name_len-2) == ".m") 2431 name = name.substr (0, name_len-2); 2432 2433 if (name.empty ()) 2434 return nullptr; 2435 2436 symbol_table& symtab = m_interpreter.get_symbol_table (); 2437 2438 octave_value fcn; 2439 std::size_t p2 = std::string::npos; 2440 2441 if (name[0] == '@') 2442 { 2443 std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1); 2444 2445 if (p1 == std::string::npos) 2446 return nullptr; 2447 2448 std::string dispatch_type = name.substr (1, p1-1); 2449 2450 p2 = name.find ('>', p1); 2451 2452 std::string method = name.substr (p1+1, p2-1); 2453 2454 fcn = symtab.find_method (method, dispatch_type); 2455 } 2456 else if (! class_name.empty ()) 2457 { 2458 cdef_manager& cdm = m_interpreter.get_cdef_manager (); 2459 2460 fcn = cdm.find_method (class_name, name); 2461 2462 // If there is no classdef method, then try legacy classes. 2463 if (fcn.is_undefined ()) 2464 fcn = symtab.find_method (name, class_name); 2465 } 2466 else 2467 { 2468 p2 = name.find ('>'); 2469 2470 std::string main_fcn = name.substr (0, p2); 2471 2472 fcn = symtab.find_function (main_fcn); 2473 } 2474 2475 // List of function names sub1>sub2>... 2476 std::string subfuns; 2477 2478 if (p2 != std::string::npos) 2479 subfuns = name.substr (p2+1); 2480 2481 if (fcn.is_defined () && fcn.is_user_code ()) 2482 user_code = fcn.user_code_value (); 2483 2484 if (! user_code || subfuns.empty ()) 2485 return user_code; 2486 2487 fcn = user_code->find_subfunction (subfuns); 2488 2489 if (fcn.is_undefined ()) 2490 return nullptr; 2491 2492 user_code = fcn.user_code_value (); 2493 } 2494 2495 return user_code; 2496 } 2497 2498 std::string current_function_name(bool skip_first) const2499 tree_evaluator::current_function_name (bool skip_first) const 2500 { 2501 octave_function *curfcn = m_call_stack.current_function (skip_first); 2502 2503 if (curfcn) 2504 return curfcn->name (); 2505 2506 return ""; 2507 } 2508 2509 bool in_user_code(void) const2510 tree_evaluator::in_user_code (void) const 2511 { 2512 return m_call_stack.current_user_code () != nullptr; 2513 } 2514 2515 void visit_decl_command(tree_decl_command & cmd)2516 tree_evaluator::visit_decl_command (tree_decl_command& cmd) 2517 { 2518 if (m_echo_state) 2519 { 2520 std::size_t line = cmd.line (); 2521 echo_code (line); 2522 m_echo_file_pos = line + 1; 2523 } 2524 2525 if (m_debug_mode) 2526 do_breakpoint (cmd.is_active_breakpoint (*this)); 2527 2528 // FIXME: tree_decl_init_list is not derived from tree, so should it 2529 // really have an accept method? 2530 2531 tree_decl_init_list *init_list = cmd.initializer_list (); 2532 2533 if (init_list) 2534 init_list->accept (*this); 2535 } 2536 2537 void visit_decl_elt(tree_decl_elt & elt)2538 tree_evaluator::visit_decl_elt (tree_decl_elt& elt) 2539 { 2540 tree_identifier *id = elt.ident (); 2541 2542 if (id) 2543 { 2544 if (elt.is_global ()) 2545 m_call_stack.make_global (id->symbol ()); 2546 else if (elt.is_persistent ()) 2547 m_call_stack.make_persistent (id->symbol ()); 2548 else 2549 error ("declaration list element not global or persistent"); 2550 2551 octave_lvalue ult = id->lvalue (*this); 2552 2553 if (ult.is_undefined ()) 2554 { 2555 tree_expression *expr = elt.expression (); 2556 2557 octave_value init_val; 2558 2559 if (expr) 2560 init_val = expr->evaluate (*this); 2561 else 2562 init_val = Matrix (); 2563 2564 ult.assign (octave_value::op_asn_eq, init_val); 2565 } 2566 } 2567 } 2568 2569 void visit_simple_for_command(tree_simple_for_command & cmd)2570 tree_evaluator::visit_simple_for_command (tree_simple_for_command& cmd) 2571 { 2572 std::size_t line = cmd.line (); 2573 2574 if (m_echo_state) 2575 { 2576 echo_code (line); 2577 line++; 2578 } 2579 2580 if (m_debug_mode) 2581 do_breakpoint (cmd.is_active_breakpoint (*this)); 2582 2583 // FIXME: need to handle PARFOR loops here using cmd.in_parallel () 2584 // and cmd.maxproc_expr (); 2585 2586 unwind_protect_var<bool> upv (m_in_loop_command, true); 2587 2588 tree_expression *expr = cmd.control_expr (); 2589 2590 octave_value rhs = expr->evaluate (*this); 2591 2592 #if defined (HAVE_LLVM) 2593 if (tree_jit::execute (cmd, rhs)) 2594 return; 2595 #endif 2596 2597 if (rhs.is_undefined ()) 2598 return; 2599 2600 tree_expression *lhs = cmd.left_hand_side (); 2601 2602 octave_lvalue ult = lhs->lvalue (*this); 2603 2604 tree_statement_list *loop_body = cmd.body (); 2605 2606 if (rhs.is_range ()) 2607 { 2608 Range rng = rhs.range_value (); 2609 2610 octave_idx_type steps = rng.numel (); 2611 2612 for (octave_idx_type i = 0; i < steps; i++) 2613 { 2614 if (m_echo_state) 2615 m_echo_file_pos = line; 2616 2617 octave_value val (rng.elem (i)); 2618 2619 ult.assign (octave_value::op_asn_eq, val); 2620 2621 if (loop_body) 2622 loop_body->accept (*this); 2623 2624 if (quit_loop_now ()) 2625 break; 2626 } 2627 } 2628 else if (rhs.is_scalar_type ()) 2629 { 2630 if (m_echo_state) 2631 m_echo_file_pos = line; 2632 2633 ult.assign (octave_value::op_asn_eq, rhs); 2634 2635 if (loop_body) 2636 loop_body->accept (*this); 2637 2638 // Maybe decrement break and continue states. 2639 quit_loop_now (); 2640 } 2641 else if (rhs.is_matrix_type () || rhs.iscell () || rhs.is_string () 2642 || rhs.isstruct ()) 2643 { 2644 // A matrix or cell is reshaped to 2 dimensions and iterated by 2645 // columns. 2646 2647 dim_vector dv = rhs.dims ().redim (2); 2648 2649 octave_idx_type nrows = dv(0); 2650 octave_idx_type steps = dv(1); 2651 2652 octave_value arg = rhs; 2653 if (rhs.ndims () > 2) 2654 arg = arg.reshape (dv); 2655 2656 if (nrows > 0 && steps > 0) 2657 { 2658 octave_value_list idx; 2659 octave_idx_type iidx; 2660 2661 // for row vectors, use single index to speed things up. 2662 if (nrows == 1) 2663 { 2664 idx.resize (1); 2665 iidx = 0; 2666 } 2667 else 2668 { 2669 idx.resize (2); 2670 idx(0) = octave_value::magic_colon_t; 2671 iidx = 1; 2672 } 2673 2674 for (octave_idx_type i = 1; i <= steps; i++) 2675 { 2676 if (m_echo_state) 2677 m_echo_file_pos = line; 2678 2679 // do_index_op expects one-based indices. 2680 idx(iidx) = i; 2681 octave_value val = arg.do_index_op (idx); 2682 2683 ult.assign (octave_value::op_asn_eq, val); 2684 2685 if (loop_body) 2686 loop_body->accept (*this); 2687 2688 if (quit_loop_now ()) 2689 break; 2690 } 2691 } 2692 else 2693 { 2694 // Handle empty cases, while still assigning to loop var. 2695 ult.assign (octave_value::op_asn_eq, arg); 2696 } 2697 } 2698 else 2699 error ("invalid type in for loop expression near line %d, column %d", 2700 cmd.line (), cmd.column ()); 2701 } 2702 2703 void visit_complex_for_command(tree_complex_for_command & cmd)2704 tree_evaluator::visit_complex_for_command (tree_complex_for_command& cmd) 2705 { 2706 std::size_t line = cmd.line (); 2707 2708 if (m_echo_state) 2709 { 2710 echo_code (line); 2711 line++; 2712 } 2713 2714 if (m_debug_mode) 2715 do_breakpoint (cmd.is_active_breakpoint (*this)); 2716 2717 unwind_protect_var<bool> upv (m_in_loop_command, true); 2718 2719 tree_expression *expr = cmd.control_expr (); 2720 2721 octave_value rhs = expr->evaluate (*this); 2722 2723 if (rhs.is_undefined ()) 2724 return; 2725 2726 if (! rhs.isstruct ()) 2727 error ("in statement 'for [X, Y] = VAL', VAL must be a structure"); 2728 2729 // Cycle through structure elements. First element of id_list 2730 // is set to value and the second is set to the name of the 2731 // structure element. 2732 2733 tree_argument_list *lhs = cmd.left_hand_side (); 2734 2735 auto p = lhs->begin (); 2736 2737 tree_expression *elt = *p++; 2738 2739 octave_lvalue val_ref = elt->lvalue (*this); 2740 2741 elt = *p; 2742 2743 octave_lvalue key_ref = elt->lvalue (*this); 2744 2745 const octave_map tmp_val = rhs.map_value (); 2746 2747 tree_statement_list *loop_body = cmd.body (); 2748 2749 string_vector keys = tmp_val.keys (); 2750 2751 octave_idx_type nel = keys.numel (); 2752 2753 for (octave_idx_type i = 0; i < nel; i++) 2754 { 2755 if (m_echo_state) 2756 m_echo_file_pos = line; 2757 2758 std::string key = keys[i]; 2759 2760 const Cell val_lst = tmp_val.contents (key); 2761 2762 octave_idx_type n = val_lst.numel (); 2763 2764 octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst); 2765 2766 val_ref.assign (octave_value::op_asn_eq, val); 2767 key_ref.assign (octave_value::op_asn_eq, key); 2768 2769 if (loop_body) 2770 loop_body->accept (*this); 2771 2772 if (quit_loop_now ()) 2773 break; 2774 } 2775 } 2776 2777 void visit_octave_user_script(octave_user_script &)2778 tree_evaluator::visit_octave_user_script (octave_user_script&) 2779 { 2780 // ?? 2781 panic_impossible (); 2782 } 2783 2784 octave_value_list execute_user_script(octave_user_script & user_script,int nargout,const octave_value_list & args)2785 tree_evaluator::execute_user_script (octave_user_script& user_script, 2786 int nargout, 2787 const octave_value_list& args) 2788 { 2789 octave_value_list retval; 2790 2791 std::string file_name = user_script.fcn_file_name (); 2792 2793 if (args.length () != 0 || nargout != 0) 2794 error ("invalid call to script %s", file_name.c_str ()); 2795 2796 tree_statement_list *cmd_list = user_script.body (); 2797 2798 if (! cmd_list) 2799 return retval; 2800 2801 if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth)) 2802 error ("max_recursion_depth exceeded"); 2803 2804 unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_SCRIPT); 2805 2806 profiler::enter<octave_user_script> block (m_profiler, user_script); 2807 2808 if (echo ()) 2809 push_echo_state (tree_evaluator::ECHO_SCRIPTS, file_name); 2810 2811 cmd_list->accept (*this); 2812 2813 if (m_returning) 2814 m_returning = 0; 2815 2816 if (m_breaking) 2817 m_breaking--; 2818 2819 return retval; 2820 } 2821 2822 void visit_octave_user_function(octave_user_function &)2823 tree_evaluator::visit_octave_user_function (octave_user_function&) 2824 { 2825 // ?? 2826 panic_impossible (); 2827 } 2828 2829 octave_value_list execute_user_function(octave_user_function & user_function,int nargout,const octave_value_list & xargs)2830 tree_evaluator::execute_user_function (octave_user_function& user_function, 2831 int nargout, 2832 const octave_value_list& xargs) 2833 { 2834 octave_value_list retval; 2835 2836 tree_statement_list *cmd_list = user_function.body (); 2837 2838 if (! cmd_list) 2839 return retval; 2840 2841 // If this function is a classdef constructor, extract the first input 2842 // argument, which must be the partially constructed object instance. 2843 2844 octave_value_list args (xargs); 2845 octave_value_list ret_args; 2846 2847 if (user_function.is_classdef_constructor ()) 2848 { 2849 if (args.length () > 0) 2850 { 2851 ret_args = args.slice (0, 1, true); 2852 args = args.slice (1, args.length () - 1, true); 2853 } 2854 else 2855 panic_impossible (); 2856 } 2857 2858 #if defined (HAVE_LLVM) 2859 if (user_function.is_special_expr () 2860 && tree_jit::execute (user_function, args, retval)) 2861 return retval; 2862 #endif 2863 2864 if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth)) 2865 error ("max_recursion_depth exceeded"); 2866 2867 Matrix ignored_outputs = ignored_fcn_outputs (); 2868 2869 bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, args.length (), 2870 nargout, user_function.takes_varargs (), 2871 user_function.all_va_args (args)); 2872 2873 tree_parameter_list *param_list = user_function.parameter_list (); 2874 2875 if (param_list && ! param_list->varargs_only ()) 2876 define_parameter_list_from_arg_vector (param_list, args); 2877 2878 // For classdef constructor, pre-populate the output arguments 2879 // with the pre-initialized object instance, extracted above. 2880 2881 tree_parameter_list *ret_list = user_function.return_list (); 2882 2883 if (user_function.is_classdef_constructor ()) 2884 { 2885 if (! ret_list) 2886 error ("%s: invalid classdef constructor, no output argument defined", 2887 user_function.dispatch_class ().c_str ()); 2888 2889 define_parameter_list_from_arg_vector (ret_list, ret_args); 2890 } 2891 2892 unwind_action act2 ([&user_function] () { 2893 user_function.restore_warning_states (); 2894 }); 2895 2896 // Evaluate the commands that make up the function. 2897 2898 unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_FUNCTION); 2899 2900 { 2901 profiler::enter<octave_user_function> block (m_profiler, user_function); 2902 2903 if (echo ()) 2904 push_echo_state (tree_evaluator::ECHO_FUNCTIONS, 2905 user_function.fcn_file_name ()); 2906 2907 if (user_function.is_special_expr ()) 2908 { 2909 assert (cmd_list->length () == 1); 2910 2911 tree_statement *stmt = cmd_list->front (); 2912 2913 tree_expression *expr = stmt->expression (); 2914 2915 if (expr) 2916 { 2917 m_call_stack.set_location (stmt->line (), stmt->column ()); 2918 2919 retval = expr->evaluate_n (*this, nargout); 2920 } 2921 } 2922 else 2923 cmd_list->accept (*this); 2924 } 2925 2926 if (m_returning) 2927 m_returning = 0; 2928 2929 if (m_breaking) 2930 m_breaking--; 2931 2932 // Copy return values out. 2933 2934 if (ret_list && ! user_function.is_special_expr ()) 2935 { 2936 Cell varargout; 2937 2938 if (ret_list->takes_varargs ()) 2939 { 2940 octave_value varargout_varval = varval ("varargout"); 2941 2942 if (varargout_varval.is_defined ()) 2943 varargout = varargout_varval.xcell_value ("varargout must be a cell array object"); 2944 } 2945 2946 retval = convert_return_list_to_const_vector (ret_list, nargout, 2947 ignored_outputs, 2948 varargout); 2949 } 2950 2951 return retval; 2952 } 2953 2954 void visit_octave_user_function_header(octave_user_function &)2955 tree_evaluator::visit_octave_user_function_header (octave_user_function&) 2956 { 2957 panic_impossible (); 2958 } 2959 2960 void visit_octave_user_function_trailer(octave_user_function &)2961 tree_evaluator::visit_octave_user_function_trailer (octave_user_function&) 2962 { 2963 panic_impossible (); 2964 } 2965 2966 void visit_function_def(tree_function_def & cmd)2967 tree_evaluator::visit_function_def (tree_function_def& cmd) 2968 { 2969 octave_value fcn = cmd.function (); 2970 2971 octave_function *f = fcn.function_value (); 2972 2973 if (f) 2974 { 2975 std::string nm = f->name (); 2976 2977 symbol_table& symtab = m_interpreter.get_symbol_table (); 2978 2979 symtab.install_cmdline_function (nm, fcn); 2980 2981 // Make sure that any variable with the same name as the new 2982 // function is cleared. 2983 2984 assign (nm); 2985 } 2986 } 2987 2988 void visit_identifier(tree_identifier &)2989 tree_evaluator::visit_identifier (tree_identifier&) 2990 { 2991 panic_impossible (); 2992 } 2993 2994 void visit_if_clause(tree_if_clause &)2995 tree_evaluator::visit_if_clause (tree_if_clause&) 2996 { 2997 panic_impossible (); 2998 } 2999 3000 void visit_if_command(tree_if_command & cmd)3001 tree_evaluator::visit_if_command (tree_if_command& cmd) 3002 { 3003 if (m_echo_state) 3004 { 3005 std::size_t line = cmd.line (); 3006 echo_code (line); 3007 m_echo_file_pos = line + 1; 3008 } 3009 3010 // FIXME: tree_if_command_list is not derived from tree, so should it 3011 // really have an accept method? 3012 3013 tree_if_command_list *lst = cmd.cmd_list (); 3014 3015 if (lst) 3016 lst->accept (*this); 3017 } 3018 3019 void visit_if_command_list(tree_if_command_list & lst)3020 tree_evaluator::visit_if_command_list (tree_if_command_list& lst) 3021 { 3022 for (tree_if_clause *tic : lst) 3023 { 3024 tree_expression *expr = tic->condition (); 3025 3026 if (! (in_debug_repl () 3027 && m_call_stack.current_frame () == m_debug_frame)) 3028 m_call_stack.set_location (tic->line (), tic->column ()); 3029 3030 if (m_debug_mode && ! tic->is_else_clause ()) 3031 do_breakpoint (tic->is_active_breakpoint (*this)); 3032 3033 if (tic->is_else_clause () || is_logically_true (expr, "if")) 3034 { 3035 tree_statement_list *stmt_lst = tic->commands (); 3036 3037 if (stmt_lst) 3038 stmt_lst->accept (*this); 3039 3040 break; 3041 } 3042 } 3043 } 3044 3045 void visit_index_expression(tree_index_expression &)3046 tree_evaluator::visit_index_expression (tree_index_expression&) 3047 { 3048 panic_impossible (); 3049 } 3050 3051 void visit_matrix(tree_matrix &)3052 tree_evaluator::visit_matrix (tree_matrix&) 3053 { 3054 panic_impossible (); 3055 } 3056 3057 void visit_cell(tree_cell &)3058 tree_evaluator::visit_cell (tree_cell&) 3059 { 3060 panic_impossible (); 3061 } 3062 3063 void visit_multi_assignment(tree_multi_assignment &)3064 tree_evaluator::visit_multi_assignment (tree_multi_assignment&) 3065 { 3066 panic_impossible (); 3067 } 3068 3069 void visit_no_op_command(tree_no_op_command & cmd)3070 tree_evaluator::visit_no_op_command (tree_no_op_command& cmd) 3071 { 3072 if (m_echo_state) 3073 { 3074 std::size_t line = cmd.line (); 3075 echo_code (line); 3076 m_echo_file_pos = line + 1; 3077 } 3078 3079 if (m_debug_mode && cmd.is_end_of_fcn_or_script ()) 3080 do_breakpoint (cmd.is_active_breakpoint (*this), true); 3081 } 3082 3083 void visit_constant(tree_constant &)3084 tree_evaluator::visit_constant (tree_constant&) 3085 { 3086 panic_impossible (); 3087 } 3088 3089 void visit_fcn_handle(tree_fcn_handle &)3090 tree_evaluator::visit_fcn_handle (tree_fcn_handle&) 3091 { 3092 panic_impossible (); 3093 } 3094 3095 void visit_parameter_list(tree_parameter_list &)3096 tree_evaluator::visit_parameter_list (tree_parameter_list&) 3097 { 3098 panic_impossible (); 3099 } 3100 3101 void visit_postfix_expression(tree_postfix_expression &)3102 tree_evaluator::visit_postfix_expression (tree_postfix_expression&) 3103 { 3104 panic_impossible (); 3105 } 3106 3107 void visit_prefix_expression(tree_prefix_expression &)3108 tree_evaluator::visit_prefix_expression (tree_prefix_expression&) 3109 { 3110 panic_impossible (); 3111 } 3112 3113 void visit_return_command(tree_return_command & cmd)3114 tree_evaluator::visit_return_command (tree_return_command& cmd) 3115 { 3116 if (m_echo_state) 3117 { 3118 std::size_t line = cmd.line (); 3119 echo_code (line); 3120 m_echo_file_pos = line + 1; 3121 } 3122 3123 if (m_debug_mode) 3124 do_breakpoint (cmd.is_active_breakpoint (*this)); 3125 3126 // Act like dbcont. 3127 3128 if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame) 3129 dbcont (); 3130 else if (m_statement_context == SC_FUNCTION 3131 || m_statement_context == SC_SCRIPT 3132 || m_in_loop_command) 3133 m_returning = 1; 3134 } 3135 3136 void visit_simple_assignment(tree_simple_assignment &)3137 tree_evaluator::visit_simple_assignment (tree_simple_assignment&) 3138 { 3139 panic_impossible (); 3140 } 3141 3142 void visit_statement(tree_statement & stmt)3143 tree_evaluator::visit_statement (tree_statement& stmt) 3144 { 3145 tree_command *cmd = stmt.command (); 3146 tree_expression *expr = stmt.expression (); 3147 3148 if (cmd || expr) 3149 { 3150 if (! (in_debug_repl () 3151 && m_call_stack.current_frame () == m_debug_frame)) 3152 m_call_stack.set_location (stmt.line (), stmt.column ()); 3153 3154 try 3155 { 3156 if (cmd) 3157 { 3158 unwind_protect_var<const std::list<octave_lvalue> *> 3159 upv (m_lvalue_list, nullptr); 3160 3161 cmd->accept (*this); 3162 } 3163 else 3164 { 3165 if (m_echo_state) 3166 { 3167 std::size_t line = stmt.line (); 3168 echo_code (line); 3169 m_echo_file_pos = line + 1; 3170 } 3171 3172 if (m_debug_mode) 3173 do_breakpoint (expr->is_active_breakpoint (*this)); 3174 3175 // FIXME: maybe all of this should be packaged in 3176 // one virtual function that returns a flag saying whether 3177 // or not the expression will take care of binding ans and 3178 // printing the result. 3179 3180 // FIXME: it seems that we should just have to 3181 // evaluate the expression and that should take care of 3182 // everything, binding ans as necessary? 3183 3184 octave_value tmp_result = expr->evaluate (*this, 0); 3185 3186 if (tmp_result.is_defined ()) 3187 { 3188 bool do_bind_ans = false; 3189 3190 if (expr->is_identifier ()) 3191 do_bind_ans = ! is_variable (expr); 3192 else 3193 do_bind_ans = ! expr->is_assignment_expression (); 3194 3195 if (do_bind_ans) 3196 bind_ans (tmp_result, expr->print_result () 3197 && statement_printing_enabled ()); 3198 } 3199 } 3200 } 3201 catch (const std::bad_alloc&) 3202 { 3203 // FIXME: We want to use error_with_id here so that give users 3204 // control over this error message but error_with_id will 3205 // require some memory allocations. Is there anything we can 3206 // do to make those more likely to succeed? 3207 3208 error_with_id ("Octave:bad-alloc", 3209 "out of memory or dimension too large for Octave's index type"); 3210 } 3211 catch (const interrupt_exception&) 3212 { 3213 // If we are debugging, then continue with next statement. 3214 // Otherwise, jump out of here. 3215 3216 if (m_debug_mode) 3217 m_interpreter.recover_from_exception (); 3218 else 3219 throw; 3220 } 3221 catch (const execution_exception& ee) 3222 { 3223 error_system& es = m_interpreter.get_error_system (); 3224 3225 if ((m_interpreter.interactive () 3226 || application::forced_interactive ()) 3227 && ((es.debug_on_error () 3228 && m_bp_table.debug_on_err (es.last_error_id ())) 3229 || (es.debug_on_caught () 3230 && m_bp_table.debug_on_caught (es.last_error_id ()))) 3231 && in_user_code ()) 3232 { 3233 es.save_exception (ee); 3234 es.display_exception (ee, std::cerr); 3235 3236 enter_debugger (); 3237 3238 // It doesn't make sense to continue execution after an 3239 // error occurs so force the debugger to quit all debug 3240 // levels and return the the top prompt. 3241 3242 throw quit_debug_exception (true); 3243 } 3244 else 3245 throw; 3246 } 3247 } 3248 } 3249 3250 void visit_statement_list(tree_statement_list & lst)3251 tree_evaluator::visit_statement_list (tree_statement_list& lst) 3252 { 3253 // FIXME: commented out along with else clause below. 3254 // static octave_value_list empty_list; 3255 3256 auto p = lst.begin (); 3257 3258 if (p != lst.end ()) 3259 { 3260 while (true) 3261 { 3262 tree_statement *elt = *p++; 3263 3264 if (! elt) 3265 error ("invalid statement found in statement list!"); 3266 3267 octave_quit (); 3268 3269 elt->accept (*this); 3270 3271 if (m_breaking || m_continuing) 3272 break; 3273 3274 if (m_returning) 3275 break; 3276 3277 if (p == lst.end ()) 3278 break; 3279 else 3280 { 3281 // Clear previous values before next statement is 3282 // evaluated so that we aren't holding an extra 3283 // reference to a value that may be used next. For 3284 // example, in code like this: 3285 // 3286 // X = rand (N); # refcount for X should be 1 3287 // # after this statement 3288 // 3289 // X(idx) = val; # no extra copy of X should be 3290 // # needed, but we will be faked 3291 // # out if retval is not cleared 3292 // # between statements here 3293 3294 // result_values = empty_list; 3295 } 3296 } 3297 } 3298 } 3299 3300 void visit_switch_case(tree_switch_case &)3301 tree_evaluator::visit_switch_case (tree_switch_case&) 3302 { 3303 panic_impossible (); 3304 } 3305 3306 void visit_switch_case_list(tree_switch_case_list &)3307 tree_evaluator::visit_switch_case_list (tree_switch_case_list&) 3308 { 3309 panic_impossible (); 3310 } 3311 3312 void visit_switch_command(tree_switch_command & cmd)3313 tree_evaluator::visit_switch_command (tree_switch_command& cmd) 3314 { 3315 if (m_echo_state) 3316 { 3317 std::size_t line = cmd.line (); 3318 echo_code (line); 3319 m_echo_file_pos = line + 1; 3320 } 3321 3322 if (m_debug_mode) 3323 do_breakpoint (cmd.is_active_breakpoint (*this)); 3324 3325 tree_expression *expr = cmd.switch_value (); 3326 3327 if (! expr) 3328 error ("missing value in switch command near line %d, column %d", 3329 cmd.line (), cmd.column ()); 3330 3331 octave_value val = expr->evaluate (*this); 3332 3333 tree_switch_case_list *lst = cmd.case_list (); 3334 3335 if (lst) 3336 { 3337 for (tree_switch_case *t : *lst) 3338 { 3339 if (t->is_default_case () || switch_case_label_matches (t, val)) 3340 { 3341 tree_statement_list *stmt_lst = t->commands (); 3342 3343 if (stmt_lst) 3344 stmt_lst->accept (*this); 3345 3346 break; 3347 } 3348 } 3349 } 3350 } 3351 3352 void visit_try_catch_command(tree_try_catch_command & cmd)3353 tree_evaluator::visit_try_catch_command (tree_try_catch_command& cmd) 3354 { 3355 if (m_echo_state) 3356 { 3357 std::size_t line = cmd.line (); 3358 echo_code (line); 3359 m_echo_file_pos = line + 1; 3360 } 3361 3362 bool execution_error = false; 3363 octave_scalar_map err_map; 3364 3365 tree_statement_list *try_code = cmd.body (); 3366 3367 if (try_code) 3368 { 3369 // unwind frame before catch block 3370 3371 unwind_protect frame; 3372 3373 interpreter_try (frame); 3374 3375 // The catch code is *not* added to unwind_protect stack; it 3376 // doesn't need to be run on interrupts. 3377 3378 try 3379 { 3380 try_code->accept (*this); 3381 } 3382 catch (const execution_exception& ee) 3383 { 3384 execution_error = true; 3385 3386 error_system& es = m_interpreter.get_error_system (); 3387 3388 es.save_exception (ee); 3389 3390 err_map.assign ("message", es.last_error_message ()); 3391 err_map.assign ("identifier", es.last_error_id ()); 3392 err_map.assign ("stack", es.last_error_stack ()); 3393 3394 m_interpreter.recover_from_exception (); 3395 } 3396 3397 // Actions attached to unwind_protect frame will run here, prior 3398 // to executing the catch block. 3399 } 3400 3401 if (execution_error) 3402 { 3403 tree_statement_list *catch_code = cmd.cleanup (); 3404 3405 if (catch_code) 3406 { 3407 tree_identifier *expr_id = cmd.identifier (); 3408 3409 if (expr_id) 3410 { 3411 octave_lvalue ult = expr_id->lvalue (*this); 3412 3413 ult.assign (octave_value::op_asn_eq, err_map); 3414 } 3415 3416 // perform actual "catch" block 3417 catch_code->accept (*this); 3418 } 3419 } 3420 } 3421 3422 void do_unwind_protect_cleanup_code(tree_statement_list * list)3423 tree_evaluator::do_unwind_protect_cleanup_code (tree_statement_list *list) 3424 { 3425 unwind_protect frame; 3426 3427 frame.protect_var (octave_interrupt_state); 3428 octave_interrupt_state = 0; 3429 3430 // We want to preserve the last location info for possible 3431 // backtracking. 3432 3433 frame.add_method (m_call_stack, &call_stack::set_line, 3434 m_call_stack.current_line ()); 3435 frame.add_method (m_call_stack, &call_stack::set_column, 3436 m_call_stack.current_column ()); 3437 3438 // Similarly, if we have seen a return or break statement, allow all 3439 // the cleanup code to run before returning or handling the break. 3440 // We don't have to worry about continue statements because they can 3441 // only occur in loops. 3442 3443 frame.protect_var (m_returning); 3444 m_returning = 0; 3445 3446 frame.protect_var (m_breaking); 3447 m_breaking = 0; 3448 3449 try 3450 { 3451 if (list) 3452 list->accept (*this); 3453 } 3454 catch (const execution_exception& ee) 3455 { 3456 error_system& es = m_interpreter.get_error_system (); 3457 3458 es.save_exception (ee); 3459 m_interpreter.recover_from_exception (); 3460 3461 if (m_breaking || m_returning) 3462 frame.discard (2); 3463 else 3464 frame.run (2); 3465 3466 frame.discard (2); 3467 3468 throw; 3469 } 3470 3471 // The unwind_protects are popped off the stack in the reverse of 3472 // the order they are pushed on. 3473 3474 // FIXME: these statements say that if we see a break or 3475 // return statement in the cleanup block, that we want to use the 3476 // new value of the breaking or returning flag instead of restoring 3477 // the previous value. Is that the right thing to do? I think so. 3478 // Consider the case of 3479 // 3480 // function foo () 3481 // unwind_protect 3482 // fprintf (stderr, "1: this should always be executed\n"); 3483 // break; 3484 // fprintf (stderr, "1: this should never be executed\n"); 3485 // unwind_protect_cleanup 3486 // fprintf (stderr, "2: this should always be executed\n"); 3487 // return; 3488 // fprintf (stderr, "2: this should never be executed\n"); 3489 // end_unwind_protect 3490 // endfunction 3491 // 3492 // If we reset the value of the breaking flag, both the returning 3493 // flag and the breaking flag will be set, and we shouldn't have 3494 // both. So, use the most recent one. If there is no return or 3495 // break in the cleanup block, the values should be reset to 3496 // whatever they were when the cleanup block was entered. 3497 3498 if (m_breaking || m_returning) 3499 frame.discard (2); 3500 else 3501 frame.run (2); 3502 } 3503 3504 void visit_unwind_protect_command(tree_unwind_protect_command & cmd)3505 tree_evaluator::visit_unwind_protect_command (tree_unwind_protect_command& cmd) 3506 { 3507 if (m_echo_state) 3508 { 3509 std::size_t line = cmd.line (); 3510 echo_code (line); 3511 m_echo_file_pos = line + 1; 3512 } 3513 3514 tree_statement_list *cleanup_code = cmd.cleanup (); 3515 3516 tree_statement_list *unwind_protect_code = cmd.body (); 3517 3518 if (unwind_protect_code) 3519 { 3520 try 3521 { 3522 unwind_protect_code->accept (*this); 3523 } 3524 catch (const execution_exception& ee) 3525 { 3526 error_system& es = m_interpreter.get_error_system (); 3527 3528 // FIXME: Maybe we should be able to temporarily set the 3529 // interpreter's exception handling state to something "safe" 3530 // while the cleanup block runs instead of just resetting it 3531 // here? 3532 es.save_exception (ee); 3533 m_interpreter.recover_from_exception (); 3534 3535 // Run the cleanup code on exceptions, so that it is run even 3536 // in case of interrupt or out-of-memory. 3537 do_unwind_protect_cleanup_code (cleanup_code); 3538 3539 // If an error occurs inside the cleanup code, a new 3540 // exception will be thrown instead of the original. 3541 throw; 3542 } 3543 catch (const interrupt_exception&) 3544 { 3545 // The comments above apply here as well. 3546 m_interpreter.recover_from_exception (); 3547 do_unwind_protect_cleanup_code (cleanup_code); 3548 throw; 3549 } 3550 3551 // Also execute the unwind_protect_cleanump code if the 3552 // unwind_protect block runs without error. 3553 do_unwind_protect_cleanup_code (cleanup_code); 3554 } 3555 } 3556 3557 void visit_while_command(tree_while_command & cmd)3558 tree_evaluator::visit_while_command (tree_while_command& cmd) 3559 { 3560 std::size_t line = cmd.line (); 3561 3562 if (m_echo_state) 3563 { 3564 echo_code (line); 3565 line++; 3566 } 3567 3568 #if defined (HAVE_LLVM) 3569 if (tree_jit::execute (cmd)) 3570 return; 3571 #endif 3572 3573 unwind_protect_var<bool> upv (m_in_loop_command, true); 3574 3575 tree_expression *expr = cmd.condition (); 3576 3577 if (! expr) 3578 panic_impossible (); 3579 3580 for (;;) 3581 { 3582 if (m_echo_state) 3583 m_echo_file_pos = line; 3584 3585 if (m_debug_mode) 3586 do_breakpoint (cmd.is_active_breakpoint (*this)); 3587 3588 if (is_logically_true (expr, "while")) 3589 { 3590 tree_statement_list *loop_body = cmd.body (); 3591 3592 if (loop_body) 3593 loop_body->accept (*this); 3594 3595 if (quit_loop_now ()) 3596 break; 3597 } 3598 else 3599 break; 3600 } 3601 } 3602 3603 void visit_do_until_command(tree_do_until_command & cmd)3604 tree_evaluator::visit_do_until_command (tree_do_until_command& cmd) 3605 { 3606 std::size_t line = cmd.line (); 3607 3608 if (m_echo_state) 3609 { 3610 echo_code (line); 3611 line++; 3612 } 3613 3614 #if defined (HAVE_LLVM) 3615 if (tree_jit::execute (cmd)) 3616 return; 3617 #endif 3618 3619 unwind_protect_var<bool> upv (m_in_loop_command, true); 3620 3621 tree_expression *expr = cmd.condition (); 3622 int until_line = cmd.line (); 3623 int until_column = cmd.column (); 3624 3625 if (! expr) 3626 panic_impossible (); 3627 3628 for (;;) 3629 { 3630 if (m_echo_state) 3631 m_echo_file_pos = line; 3632 3633 tree_statement_list *loop_body = cmd.body (); 3634 3635 if (loop_body) 3636 loop_body->accept (*this); 3637 3638 if (quit_loop_now ()) 3639 break; 3640 3641 if (m_debug_mode) 3642 do_breakpoint (cmd.is_active_breakpoint (*this)); 3643 3644 m_call_stack.set_location (until_line, until_column); 3645 3646 if (is_logically_true (expr, "do-until")) 3647 break; 3648 } 3649 } 3650 3651 void visit_superclass_ref(tree_superclass_ref &)3652 tree_evaluator::visit_superclass_ref (tree_superclass_ref&) 3653 { 3654 panic_impossible (); 3655 } 3656 3657 void visit_metaclass_query(tree_metaclass_query &)3658 tree_evaluator::visit_metaclass_query (tree_metaclass_query&) 3659 { 3660 panic_impossible (); 3661 } 3662 bind_ans(const octave_value & val,bool print)3663 void tree_evaluator::bind_ans (const octave_value& val, bool print) 3664 { 3665 static std::string ans = "ans"; 3666 3667 if (val.is_defined ()) 3668 { 3669 if (val.is_cs_list ()) 3670 { 3671 octave_value_list lst = val.list_value (); 3672 3673 for (octave_idx_type i = 0; i < lst.length (); i++) 3674 bind_ans (lst(i), print); 3675 } 3676 else 3677 { 3678 assign (ans, val); 3679 3680 if (print) 3681 { 3682 octave_value_list args = ovl (val); 3683 args.stash_name_tags (string_vector (ans)); 3684 feval ("display", args); 3685 } 3686 } 3687 } 3688 } 3689 3690 void do_breakpoint(tree_statement & stmt)3691 tree_evaluator::do_breakpoint (tree_statement& stmt) 3692 { 3693 do_breakpoint (stmt.is_active_breakpoint (*this), 3694 stmt.is_end_of_fcn_or_script ()); 3695 } 3696 3697 void do_breakpoint(bool is_breakpoint,bool is_end_of_fcn_or_script)3698 tree_evaluator::do_breakpoint (bool is_breakpoint, 3699 bool is_end_of_fcn_or_script) 3700 { 3701 bool break_on_this_statement = false; 3702 3703 if (is_breakpoint) 3704 break_on_this_statement = true; 3705 else if (m_dbstep_flag > 0) 3706 { 3707 if (m_call_stack.current_frame () == m_debug_frame) 3708 { 3709 if (m_dbstep_flag == 1 || is_end_of_fcn_or_script) 3710 { 3711 // We get here if we are doing a "dbstep" or a "dbstep N" and the 3712 // count has reached 1 so that we must stop and return to debug 3713 // prompt. Alternatively, "dbstep N" has been used but the end 3714 // of the frame has been reached so we stop at the last line and 3715 // return to prompt. 3716 3717 break_on_this_statement = true; 3718 } 3719 else 3720 { 3721 // Executing "dbstep N". Decrease N by one and continue. 3722 3723 m_dbstep_flag--; 3724 } 3725 3726 } 3727 else if (m_dbstep_flag == 1 3728 && m_call_stack.current_frame () < m_debug_frame) 3729 { 3730 // We stepped out from the end of a function. 3731 3732 m_debug_frame = m_call_stack.current_frame (); 3733 3734 break_on_this_statement = true; 3735 } 3736 } 3737 else if (m_dbstep_flag == -1) 3738 { 3739 // We get here if we are doing a "dbstep in". 3740 3741 break_on_this_statement = true; 3742 3743 m_debug_frame = m_call_stack.current_frame (); 3744 } 3745 else if (m_dbstep_flag == -2) 3746 { 3747 // We get here if we are doing a "dbstep out". Check for end of 3748 // function and whether the current frame is the same as the 3749 // cached value because we want to step out from the frame where 3750 // "dbstep out" was evaluated, not from any functions called from 3751 // that frame. 3752 3753 if (is_end_of_fcn_or_script 3754 && m_call_stack.current_frame () == m_debug_frame) 3755 m_dbstep_flag = -1; 3756 } 3757 3758 if (break_on_this_statement) 3759 { 3760 m_dbstep_flag = 0; 3761 3762 enter_debugger (); 3763 } 3764 } 3765 3766 bool is_logically_true(tree_expression * expr,const char * warn_for)3767 tree_evaluator::is_logically_true (tree_expression *expr, 3768 const char *warn_for) 3769 { 3770 bool expr_value = false; 3771 3772 octave_value t1 = expr->evaluate (*this); 3773 3774 if (t1.is_defined ()) 3775 return t1.is_true (); 3776 else 3777 error ("%s: undefined value used in conditional expression", warn_for); 3778 3779 return expr_value; 3780 } 3781 3782 octave_value max_recursion_depth(const octave_value_list & args,int nargout)3783 tree_evaluator::max_recursion_depth (const octave_value_list& args, 3784 int nargout) 3785 { 3786 return set_internal_variable (m_max_recursion_depth, args, nargout, 3787 "max_recursion_depth", 0); 3788 } 3789 3790 symbol_info_list glob_symbol_info(const std::string & pattern) const3791 tree_evaluator::glob_symbol_info (const std::string& pattern) const 3792 { 3793 return m_call_stack.glob_symbol_info (pattern); 3794 } 3795 3796 symbol_info_list regexp_symbol_info(const std::string & pattern) const3797 tree_evaluator::regexp_symbol_info (const std::string& pattern) const 3798 { 3799 return m_call_stack.regexp_symbol_info (pattern); 3800 } 3801 3802 symbol_info_list get_symbol_info(void)3803 tree_evaluator::get_symbol_info (void) 3804 { 3805 return m_call_stack.get_symbol_info (); 3806 } 3807 3808 symbol_info_list top_scope_symbol_info(void) const3809 tree_evaluator::top_scope_symbol_info (void) const 3810 { 3811 return m_call_stack.top_scope_symbol_info (); 3812 } 3813 get_autoload_map(void) const3814 octave_map tree_evaluator::get_autoload_map (void) const 3815 { 3816 Cell func_names (dim_vector (m_autoload_map.size (), 1)); 3817 Cell file_names (dim_vector (m_autoload_map.size (), 1)); 3818 3819 octave_idx_type i = 0; 3820 for (const auto& fcn_fname : m_autoload_map) 3821 { 3822 func_names(i) = fcn_fname.first; 3823 file_names(i) = fcn_fname.second; 3824 3825 i++; 3826 } 3827 3828 octave_map m; 3829 3830 m.assign ("function", func_names); 3831 m.assign ("file", file_names); 3832 3833 return m; 3834 } 3835 lookup_autoload(const std::string & nm) const3836 std::string tree_evaluator::lookup_autoload (const std::string& nm) const 3837 { 3838 std::string retval; 3839 3840 auto p = m_autoload_map.find (nm); 3841 3842 if (p != m_autoload_map.end ()) 3843 { 3844 load_path& lp = m_interpreter.get_load_path (); 3845 3846 retval = lp.find_file (p->second); 3847 } 3848 3849 return retval; 3850 } 3851 autoloaded_functions(void) const3852 std::list<std::string> tree_evaluator::autoloaded_functions (void) const 3853 { 3854 std::list<std::string> names; 3855 3856 for (const auto& fcn_fname : m_autoload_map) 3857 names.push_back (fcn_fname.first); 3858 3859 return names; 3860 } 3861 3862 std::list<std::string> reverse_lookup_autoload(const std::string & nm) const3863 tree_evaluator::reverse_lookup_autoload (const std::string& nm) const 3864 { 3865 std::list<std::string> names; 3866 3867 for (const auto& fcn_fname : m_autoload_map) 3868 if (nm == fcn_fname.second) 3869 names.push_back (fcn_fname.first); 3870 3871 return names; 3872 } 3873 add_autoload(const std::string & fcn,const std::string & nm)3874 void tree_evaluator::add_autoload (const std::string& fcn, 3875 const std::string& nm) 3876 { 3877 std::string file_name = check_autoload_file (nm); 3878 3879 m_autoload_map[fcn] = file_name; 3880 } 3881 remove_autoload(const std::string & fcn,const std::string & nm)3882 void tree_evaluator::remove_autoload (const std::string& fcn, 3883 const std::string& nm) 3884 { 3885 check_autoload_file (nm); 3886 3887 // Remove function from symbol table and autoload map. 3888 symbol_table& symtab = m_interpreter.get_symbol_table (); 3889 3890 symtab.clear_dld_function (fcn); 3891 3892 m_autoload_map.erase (fcn); 3893 } 3894 3895 octave_value whos_line_format(const octave_value_list & args,int nargout)3896 tree_evaluator::whos_line_format (const octave_value_list& args, int nargout) 3897 { 3898 return set_internal_variable (m_whos_line_format, args, nargout, 3899 "whos_line_format"); 3900 } 3901 3902 octave_value silent_functions(const octave_value_list & args,int nargout)3903 tree_evaluator::silent_functions (const octave_value_list& args, int nargout) 3904 { 3905 return set_internal_variable (m_silent_functions, args, nargout, 3906 "silent_functions"); 3907 } 3908 3909 octave_value string_fill_char(const octave_value_list & args,int nargout)3910 tree_evaluator::string_fill_char (const octave_value_list& args, int nargout) 3911 { 3912 return set_internal_variable (m_string_fill_char, args, nargout, 3913 "string_fill_char"); 3914 } 3915 3916 // Final step of processing an indexing error. Add the name of the 3917 // variable being indexed, if any, then issue an error. (Will this also 3918 // be needed by pt-lvalue, which calls subsref?) 3919 final_index_error(index_exception & e,const tree_expression * expr)3920 void tree_evaluator::final_index_error (index_exception& e, 3921 const tree_expression *expr) 3922 { 3923 std::string extra_message; 3924 3925 if (is_variable (expr)) 3926 { 3927 std::string var = expr->name (); 3928 3929 e.set_var (var); 3930 3931 symbol_table& symtab = m_interpreter.get_symbol_table (); 3932 3933 octave_value fcn = symtab.find_function (var); 3934 3935 if (fcn.is_function ()) 3936 { 3937 octave_function *fp = fcn.function_value (); 3938 3939 if (fp && fp->name () == var) 3940 extra_message 3941 = " (note: variable '" + var + "' shadows function)"; 3942 } 3943 } 3944 3945 std::string msg = e.message () + extra_message; 3946 3947 error_with_id (e.err_id (), "%s", msg.c_str ()); 3948 } 3949 3950 octave_value do_who(int argc,const string_vector & argv,bool return_list,bool verbose)3951 tree_evaluator::do_who (int argc, const string_vector& argv, 3952 bool return_list, bool verbose) 3953 { 3954 return m_call_stack.do_who (argc, argv, return_list, verbose); 3955 } 3956 3957 octave_value_list make_value_list(tree_argument_list * args,const string_vector & arg_nm)3958 tree_evaluator::make_value_list (tree_argument_list *args, 3959 const string_vector& arg_nm) 3960 { 3961 octave_value_list retval; 3962 3963 if (args) 3964 { 3965 unwind_protect_var<const std::list<octave_lvalue> *> 3966 upv (m_lvalue_list, nullptr); 3967 3968 int len = args->length (); 3969 3970 unwind_protect_var<int> upv2 (m_index_position); 3971 unwind_protect_var<int> upv3 (m_num_indices); 3972 3973 m_num_indices = len; 3974 3975 std::list<octave_value> arg_vals; 3976 3977 int k = 0; 3978 3979 for (auto elt : *args) 3980 { 3981 // FIXME: is it possible for elt to be invalid? 3982 3983 if (! elt) 3984 break; 3985 3986 m_index_position = k++; 3987 3988 octave_value tmp = elt->evaluate (*this); 3989 3990 if (tmp.is_cs_list ()) 3991 { 3992 octave_value_list tmp_ovl = tmp.list_value (); 3993 3994 for (octave_idx_type i = 0; i < tmp_ovl.length (); i++) 3995 arg_vals.push_back (tmp_ovl(i)); 3996 } 3997 else if (tmp.is_defined ()) 3998 arg_vals.push_back (tmp); 3999 } 4000 4001 retval = octave_value_list (arg_vals); 4002 } 4003 4004 octave_idx_type n = retval.length (); 4005 4006 if (n > 0) 4007 retval.stash_name_tags (arg_nm); 4008 4009 return retval; 4010 } 4011 4012 std::list<octave_lvalue> make_lvalue_list(tree_argument_list * lhs)4013 tree_evaluator::make_lvalue_list (tree_argument_list *lhs) 4014 { 4015 std::list<octave_lvalue> retval; 4016 4017 for (tree_expression *elt : *lhs) 4018 retval.push_back (elt->lvalue (*this)); 4019 4020 return retval; 4021 } 4022 4023 void push_echo_state(int type,const std::string & file_name,std::size_t pos)4024 tree_evaluator::push_echo_state (int type, const std::string& file_name, 4025 std::size_t pos) 4026 { 4027 unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); 4028 4029 if (frame) 4030 { 4031 push_echo_state_cleanup (*frame); 4032 4033 set_echo_state (type, file_name, pos); 4034 } 4035 } 4036 4037 void set_echo_state(int type,const std::string & file_name,std::size_t pos)4038 tree_evaluator::set_echo_state (int type, const std::string& file_name, 4039 std::size_t pos) 4040 { 4041 m_echo_state = echo_this_file (file_name, type); 4042 m_echo_file_name = file_name; 4043 m_echo_file_pos = pos; 4044 } 4045 4046 void uwp_set_echo_state(bool state,const std::string & file_name,std::size_t pos)4047 tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name, 4048 std::size_t pos) 4049 { 4050 m_echo_state = state; 4051 m_echo_file_name = file_name; 4052 m_echo_file_pos = pos; 4053 } 4054 4055 void maybe_set_echo_state(void)4056 tree_evaluator::maybe_set_echo_state (void) 4057 { 4058 octave_function *caller = caller_function (); 4059 4060 if (caller && caller->is_user_code ()) 4061 { 4062 octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller); 4063 4064 int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS; 4065 4066 std::string file_name = fcn->fcn_file_name (); 4067 4068 std::size_t pos = m_call_stack.current_line (); 4069 4070 set_echo_state (type, file_name, pos); 4071 } 4072 } 4073 4074 void push_echo_state_cleanup(unwind_protect & frame)4075 tree_evaluator::push_echo_state_cleanup (unwind_protect& frame) 4076 { 4077 frame.add_method (this, &tree_evaluator::uwp_set_echo_state, 4078 m_echo_state, m_echo_file_name, m_echo_file_pos); 4079 } 4080 maybe_push_echo_state_cleanup(void)4081 bool tree_evaluator::maybe_push_echo_state_cleanup (void) 4082 { 4083 // This function is expected to be called from ECHO, which would be 4084 // the top of the call stack. If the caller of ECHO is a 4085 // user-defined function or script, then set up unwind-protect 4086 // elements to restore echo state. 4087 4088 unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame (); 4089 4090 if (frame) 4091 { 4092 push_echo_state_cleanup (*frame); 4093 return true; 4094 } 4095 4096 return false; 4097 } 4098 4099 4100 octave_value echo(const octave_value_list & args,int)4101 tree_evaluator::echo (const octave_value_list& args, int) 4102 { 4103 bool cleanup_pushed = maybe_push_echo_state_cleanup (); 4104 4105 string_vector argv = args.make_argv (); 4106 4107 switch (args.length ()) 4108 { 4109 case 0: 4110 if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS)) 4111 { 4112 m_echo = ECHO_OFF; 4113 m_echo_files.clear (); 4114 } 4115 else 4116 m_echo = ECHO_SCRIPTS; 4117 break; 4118 4119 case 1: 4120 { 4121 std::string arg0 = argv[0]; 4122 4123 if (arg0 == "on") 4124 m_echo = ECHO_SCRIPTS; 4125 else if (arg0 == "off") 4126 m_echo = ECHO_OFF; 4127 else 4128 { 4129 std::string file = fcn_file_in_path (arg0); 4130 file = sys::env::make_absolute (file); 4131 4132 if (file.empty ()) 4133 error ("echo: no such file %s", arg0.c_str ()); 4134 4135 if (m_echo & ECHO_ALL) 4136 { 4137 // Echo is enabled for all functions, so turn it off 4138 // for this one. 4139 4140 m_echo_files[file] = false; 4141 } 4142 else 4143 { 4144 // Echo may be enabled for specific functions. 4145 4146 auto p = m_echo_files.find (file); 4147 4148 if (p == m_echo_files.end ()) 4149 { 4150 // Not this one, so enable it. 4151 4152 m_echo |= ECHO_FUNCTIONS; 4153 m_echo_files[file] = true; 4154 } 4155 else 4156 { 4157 // This one is already in the list. Flip the 4158 // status for it. 4159 4160 p->second = ! p->second; 4161 } 4162 } 4163 } 4164 } 4165 break; 4166 4167 case 2: 4168 { 4169 std::string arg0 = argv[0]; 4170 std::string arg1 = argv[1]; 4171 4172 if (arg1 == "on" || arg1 == "off") 4173 std::swap (arg0, arg1); 4174 4175 if (arg0 == "on") 4176 { 4177 if (arg1 == "all") 4178 { 4179 m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL); 4180 m_echo_files.clear (); 4181 } 4182 else 4183 { 4184 std::string file = fcn_file_in_path (arg1); 4185 file = sys::env::make_absolute (file); 4186 4187 if (file.empty ()) 4188 error ("echo: no such file %s", arg1.c_str ()); 4189 4190 m_echo |= ECHO_FUNCTIONS; 4191 m_echo_files[file] = true; 4192 } 4193 } 4194 else if (arg0 == "off") 4195 { 4196 if (arg1 == "all") 4197 { 4198 m_echo = ECHO_OFF; 4199 m_echo_files.clear (); 4200 } 4201 else 4202 { 4203 std::string file = fcn_file_in_path (arg1); 4204 file = sys::env::make_absolute (file); 4205 4206 if (file.empty ()) 4207 error ("echo: no such file %s", arg1.c_str ()); 4208 4209 m_echo_files[file] = false; 4210 } 4211 } 4212 else 4213 print_usage (); 4214 } 4215 break; 4216 4217 default: 4218 print_usage (); 4219 break; 4220 } 4221 4222 if (cleanup_pushed) 4223 maybe_set_echo_state (); 4224 4225 return octave_value (); 4226 } 4227 in_debug_repl(void) const4228 bool tree_evaluator::in_debug_repl (void) const 4229 { 4230 return (m_debugger_stack.empty () 4231 ? false : m_debugger_stack.top()->in_debug_repl ()); 4232 } 4233 dbcont(void)4234 void tree_evaluator::dbcont (void) 4235 { 4236 if (! m_debugger_stack.empty ()) 4237 m_debugger_stack.top()->dbcont (); 4238 } 4239 dbquit(bool all)4240 void tree_evaluator::dbquit (bool all) 4241 { 4242 if (! m_debugger_stack.empty ()) 4243 m_debugger_stack.top()->dbquit (all); 4244 } 4245 end_value(const octave_value & value,octave_idx_type index_position,octave_idx_type num_indices)4246 static octave_value end_value (const octave_value& value, 4247 octave_idx_type index_position, 4248 octave_idx_type num_indices) 4249 { 4250 dim_vector dv = value.dims (); 4251 int ndims = dv.ndims (); 4252 4253 if (num_indices < ndims) 4254 { 4255 for (int i = num_indices; i < ndims; i++) 4256 dv(num_indices-1) *= dv(i); 4257 4258 if (num_indices == 1) 4259 { 4260 ndims = 2; 4261 dv.resize (ndims); 4262 dv(1) = 1; 4263 } 4264 else 4265 { 4266 ndims = num_indices; 4267 dv.resize (ndims); 4268 } 4269 } 4270 4271 return (index_position < ndims 4272 ? octave_value (dv(index_position)) : octave_value (1.0)); 4273 } 4274 4275 octave_value_list evaluate_end_expression(const octave_value_list & args)4276 tree_evaluator::evaluate_end_expression (const octave_value_list& args) 4277 { 4278 int nargin = args.length (); 4279 4280 if (nargin != 0 && nargin != 3) 4281 print_usage (); 4282 4283 if (nargin == 3) 4284 { 4285 octave_idx_type index_position 4286 = args(1).xidx_type_value ("end: K must be integer value"); 4287 4288 if (index_position < 1) 4289 error ("end: K must be greater than zero"); 4290 4291 octave_idx_type num_indices 4292 = args(2).xidx_type_value ("end: N must be integer value"); 4293 4294 if (num_indices < 1) 4295 error ("end: N must be greater than zero"); 4296 4297 return end_value (args(0), index_position-1, num_indices); 4298 } 4299 4300 // If m_indexed_object is undefined, then this use of 'end' is 4301 // either appearing in a function call argument list or in an 4302 // attempt to index an undefined symbol. There seems to be no 4303 // reasonable way to provide a better error message. So just fail 4304 // with an invalid use message. See bug #58830. 4305 4306 if (m_indexed_object.is_undefined ()) 4307 error ("invalid use of 'end': may only be used to index existing value"); 4308 4309 octave_value expr_result; 4310 4311 if (m_index_list.empty ()) 4312 expr_result = m_indexed_object; 4313 else 4314 { 4315 try 4316 { 4317 // When evaluating "end" with no arguments, we should have 4318 // been called from the built-in Fend function that appears 4319 // in the context of an argument list. Fend will be 4320 // evaluated in its own stack frame. But we need to 4321 // evaluate the partial expression that the special "end" 4322 // token applies to in the calling stack frame. 4323 4324 unwind_action act ([this] (std::size_t frm) 4325 { 4326 m_call_stack.restore_frame (frm); 4327 }, m_call_stack.current_frame ()); 4328 4329 std::size_t n = m_call_stack.find_current_user_frame (); 4330 m_call_stack.goto_frame (n); 4331 4332 // End is only valid inside argument lists used for 4333 // indexing. The dispatch class is set by the function that 4334 // evaluates the argument list. 4335 4336 // Silently ignore extra output values. 4337 4338 octave_value_list tmp 4339 = m_indexed_object.subsref (m_index_type, m_index_list, 1); 4340 4341 expr_result = tmp.length () ? tmp(0) : octave_value (); 4342 4343 if (expr_result.is_cs_list ()) 4344 err_indexed_cs_list (); 4345 } 4346 catch (index_exception&) 4347 { 4348 error ("error evaluating partial expression for END"); 4349 } 4350 } 4351 4352 if (expr_result.isobject ()) 4353 { 4354 // FIXME: is there a better way to lookup and execute a method 4355 // that handles all the details like setting the dispatch class 4356 // appropriately? 4357 4358 std::string dispatch_class = expr_result.class_name (); 4359 4360 symbol_table& symtab = m_interpreter.get_symbol_table (); 4361 4362 octave_value meth = symtab.find_method ("end", dispatch_class); 4363 4364 if (meth.is_defined ()) 4365 return m_interpreter.feval 4366 (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1); 4367 } 4368 4369 return end_value (expr_result, m_index_position, m_num_indices); 4370 } 4371 4372 octave_value PS4(const octave_value_list & args,int nargout)4373 tree_evaluator::PS4 (const octave_value_list& args, int nargout) 4374 { 4375 return set_internal_variable (m_PS4, args, nargout, "PS4"); 4376 } 4377 echo_this_file(const std::string & file,int type) const4378 bool tree_evaluator::echo_this_file (const std::string& file, int type) const 4379 { 4380 if ((type & m_echo) == ECHO_SCRIPTS) 4381 { 4382 // Asking about scripts and echo is enabled for them. 4383 return true; 4384 } 4385 4386 if ((type & m_echo) == ECHO_FUNCTIONS) 4387 { 4388 // Asking about functions and echo is enabled for functions. 4389 // Now, which ones? 4390 4391 auto p = m_echo_files.find (file); 4392 4393 if (m_echo & ECHO_ALL) 4394 { 4395 // Return true ulness echo was turned off for a specific 4396 // file. 4397 4398 return (p == m_echo_files.end () || p->second); 4399 } 4400 else 4401 { 4402 // Return true if echo is specifically enabled for this file. 4403 4404 return p != m_echo_files.end () && p->second; 4405 } 4406 } 4407 4408 return false; 4409 } 4410 echo_code(std::size_t line)4411 void tree_evaluator::echo_code (std::size_t line) 4412 { 4413 std::string prefix = command_editor::decode_prompt_string (m_PS4); 4414 4415 octave_function *curr_fcn = m_call_stack.current_function (); 4416 4417 if (curr_fcn && curr_fcn->is_user_code ()) 4418 { 4419 octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn); 4420 4421 std::size_t num_lines = line - m_echo_file_pos + 1; 4422 4423 std::deque<std::string> lines 4424 = code->get_code_lines (m_echo_file_pos, num_lines); 4425 4426 for (auto& elt : lines) 4427 octave_stdout << prefix << elt << std::endl; 4428 } 4429 } 4430 4431 // Decide if it's time to quit a for or while loop. quit_loop_now(void)4432 bool tree_evaluator::quit_loop_now (void) 4433 { 4434 octave_quit (); 4435 4436 // Maybe handle 'continue N' someday... 4437 4438 if (m_continuing) 4439 m_continuing--; 4440 4441 bool quit = (m_returning || m_breaking || m_continuing); 4442 4443 if (m_breaking) 4444 m_breaking--; 4445 4446 return quit; 4447 } 4448 bind_auto_fcn_vars(const string_vector & arg_names,const Matrix & ignored_outputs,int nargin,int nargout,bool takes_varargs,const octave_value_list & va_args)4449 void tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names, 4450 const Matrix& ignored_outputs, 4451 int nargin, int nargout, 4452 bool takes_varargs, 4453 const octave_value_list& va_args) 4454 { 4455 set_auto_fcn_var (stack_frame::ARG_NAMES, Cell (arg_names)); 4456 set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs); 4457 set_auto_fcn_var (stack_frame::NARGIN, nargin); 4458 set_auto_fcn_var (stack_frame::NARGOUT, nargout); 4459 set_auto_fcn_var (stack_frame::SAVED_WARNING_STATES, octave_value ()); 4460 4461 if (takes_varargs) 4462 assign ("varargin", va_args.cell_value ()); 4463 } 4464 4465 std::string check_autoload_file(const std::string & nm) const4466 tree_evaluator::check_autoload_file (const std::string& nm) const 4467 { 4468 if (sys::env::absolute_pathname (nm)) 4469 return nm; 4470 4471 std::string full_name = nm; 4472 4473 octave_user_code *fcn = m_call_stack.current_user_code (); 4474 4475 bool found = false; 4476 4477 if (fcn) 4478 { 4479 std::string fname = fcn->fcn_file_name (); 4480 4481 if (! fname.empty ()) 4482 { 4483 fname = sys::env::make_absolute (fname); 4484 fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1); 4485 4486 sys::file_stat fs (fname + nm); 4487 4488 if (fs.exists ()) 4489 { 4490 full_name = fname + nm; 4491 found = true; 4492 } 4493 } 4494 } 4495 4496 if (! found) 4497 warning_with_id ("Octave:autoload-relative-file-name", 4498 "autoload: '%s' is not an absolute filename", 4499 nm.c_str ()); 4500 4501 return full_name; 4502 } 4503 } 4504 4505 DEFMETHOD (max_recursion_depth, interp, args, nargout, 4506 doc: /* -*- texinfo -*- 4507 @deftypefn {} {@var{val} =} max_recursion_depth () 4508 @deftypefnx {} {@var{old_val} =} max_recursion_depth (@var{new_val}) 4509 @deftypefnx {} {} max_recursion_depth (@var{new_val}, "local") 4510 Query or set the internal limit on the number of times a function may 4511 be called recursively. 4512 4513 If the limit is exceeded, an error message is printed and control returns to 4514 the top level. 4515 4516 When called from inside a function with the @qcode{"local"} option, the 4517 variable is changed locally for the function and any subroutines it calls. 4518 The original variable value is restored when exiting the function. 4519 4520 @seealso{max_stack_depth} 4521 @end deftypefn */) 4522 { 4523 octave::tree_evaluator& tw = interp.get_evaluator (); 4524 4525 return tw.max_recursion_depth (args, nargout); 4526 } 4527 4528 /* 4529 %!test 4530 %! orig_val = max_recursion_depth (); 4531 %! old_val = max_recursion_depth (2*orig_val); 4532 %! assert (orig_val, old_val); 4533 %! assert (max_recursion_depth (), 2*orig_val); 4534 %! max_recursion_depth (orig_val); 4535 %! assert (max_recursion_depth (), orig_val); 4536 4537 %!error (max_recursion_depth (1, 2)) 4538 */ 4539 4540 DEFMETHOD (whos_line_format, interp, args, nargout, 4541 doc: /* -*- texinfo -*- 4542 @deftypefn {} {@var{val} =} whos_line_format () 4543 @deftypefnx {} {@var{old_val} =} whos_line_format (@var{new_val}) 4544 @deftypefnx {} {} whos_line_format (@var{new_val}, "local") 4545 Query or set the format string used by the command @code{whos}. 4546 4547 A full format string is: 4548 @c Set example in small font to prevent overfull line 4549 4550 @smallexample 4551 %[modifier]<command>[:width[:left-min[:balance]]]; 4552 @end smallexample 4553 4554 The following command sequences are available: 4555 4556 @table @code 4557 @item %a 4558 Prints attributes of variables (g=global, p=persistent, f=formal parameter). 4559 4560 @item %b 4561 Prints number of bytes occupied by variables. 4562 4563 @item %c 4564 Prints class names of variables. 4565 4566 @item %e 4567 Prints elements held by variables. 4568 4569 @item %n 4570 Prints variable names. 4571 4572 @item %s 4573 Prints dimensions of variables. 4574 4575 @item %t 4576 Prints type names of variables. 4577 @end table 4578 4579 Every command may also have an alignment modifier: 4580 4581 @table @code 4582 @item l 4583 Left alignment. 4584 4585 @item r 4586 Right alignment (default). 4587 4588 @item c 4589 Column-aligned (only applicable to command %s). 4590 @end table 4591 4592 The @code{width} parameter is a positive integer specifying the minimum 4593 number of columns used for printing. No maximum is needed as the field will 4594 auto-expand as required. 4595 4596 The parameters @code{left-min} and @code{balance} are only available when 4597 the column-aligned modifier is used with the command @samp{%s}. 4598 @code{balance} specifies the column number within the field width which 4599 will be aligned between entries. Numbering starts from 0 which indicates 4600 the leftmost column. @code{left-min} specifies the minimum field width to 4601 the left of the specified balance column. 4602 4603 The default format is: 4604 4605 @qcode{" %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;@xbackslashchar{}n"} 4606 4607 When called from inside a function with the @qcode{"local"} option, the 4608 variable is changed locally for the function and any subroutines it calls. 4609 The original variable value is restored when exiting the function. 4610 @seealso{whos} 4611 @end deftypefn */) 4612 { 4613 octave::tree_evaluator& tw = interp.get_evaluator (); 4614 4615 return tw.whos_line_format (args, nargout); 4616 } 4617 4618 DEFMETHOD (silent_functions, interp, args, nargout, 4619 doc: /* -*- texinfo -*- 4620 @deftypefn {} {@var{val} =} silent_functions () 4621 @deftypefnx {} {@var{old_val} =} silent_functions (@var{new_val}) 4622 @deftypefnx {} {} silent_functions (@var{new_val}, "local") 4623 Query or set the internal variable that controls whether internal 4624 output from a function is suppressed. 4625 4626 If this option is disabled, Octave will display the results produced by 4627 evaluating expressions within a function body that are not terminated with 4628 a semicolon. 4629 4630 When called from inside a function with the @qcode{"local"} option, the 4631 variable is changed locally for the function and any subroutines it calls. 4632 The original variable value is restored when exiting the function. 4633 @end deftypefn */) 4634 { 4635 octave::tree_evaluator& tw = interp.get_evaluator (); 4636 4637 return tw.silent_functions (args, nargout); 4638 } 4639 4640 /* 4641 %!test 4642 %! orig_val = silent_functions (); 4643 %! old_val = silent_functions (! orig_val); 4644 %! assert (orig_val, old_val); 4645 %! assert (silent_functions (), ! orig_val); 4646 %! silent_functions (orig_val); 4647 %! assert (silent_functions (), orig_val); 4648 4649 %!error (silent_functions (1, 2)) 4650 */ 4651 4652 DEFMETHOD (string_fill_char, interp, args, nargout, 4653 doc: /* -*- texinfo -*- 4654 @deftypefn {} {@var{val} =} string_fill_char () 4655 @deftypefnx {} {@var{old_val} =} string_fill_char (@var{new_val}) 4656 @deftypefnx {} {} string_fill_char (@var{new_val}, "local") 4657 Query or set the internal variable used to pad all rows of a character 4658 matrix to the same length. 4659 4660 The value must be a single character and the default is @qcode{" "} (a 4661 single space). For example: 4662 4663 @example 4664 @group 4665 string_fill_char ("X"); 4666 [ "these"; "are"; "strings" ] 4667 @result{} "theseXX" 4668 "areXXXX" 4669 "strings" 4670 @end group 4671 @end example 4672 4673 When called from inside a function with the @qcode{"local"} option, the 4674 variable is changed locally for the function and any subroutines it calls. 4675 The original variable value is restored when exiting the function. 4676 @end deftypefn */) 4677 { 4678 octave::tree_evaluator& tw = interp.get_evaluator (); 4679 4680 return tw.string_fill_char (args, nargout); 4681 } 4682 4683 /* 4684 ## string_fill_char() function call must be outside of %!test block 4685 ## due to the way a %!test block is wrapped inside a function 4686 %!shared orig_val, old_val 4687 %! orig_val = string_fill_char (); 4688 %! old_val = string_fill_char ("X"); 4689 %!test 4690 %! assert (orig_val, old_val); 4691 %! assert (string_fill_char (), "X"); 4692 %! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]); 4693 %! string_fill_char (orig_val); 4694 %! assert (string_fill_char (), orig_val); 4695 4696 %!assert ( [ [], {1} ], {1} ) 4697 4698 %!error (string_fill_char (1, 2)) 4699 */ 4700 4701 DEFMETHOD (PS4, interp, args, nargout, 4702 doc: /* -*- texinfo -*- 4703 @deftypefn {} {@var{val} =} PS4 () 4704 @deftypefnx {} {@var{old_val} =} PS4 (@var{new_val}) 4705 @deftypefnx {} {} PS4 (@var{new_val}, "local") 4706 Query or set the character string used to prefix output produced 4707 when echoing commands is enabled. 4708 4709 The default value is @qcode{"+ "}. 4710 @xref{Diary and Echo Commands}, for a description of echoing commands. 4711 4712 When called from inside a function with the @qcode{"local"} option, the 4713 variable is changed locally for the function and any subroutines it calls. 4714 The original variable value is restored when exiting the function. 4715 @seealso{echo, PS1, PS2} 4716 @end deftypefn */) 4717 { 4718 octave::tree_evaluator& tw = interp.get_evaluator (); 4719 4720 return tw.PS4 (args, nargout); 4721 } 4722 4723 DEFMETHOD (echo, interp, args, nargout, 4724 doc: /* -*- texinfo -*- 4725 @deftypefn {} {} echo 4726 @deftypefnx {} {} echo on 4727 @deftypefnx {} {} echo off 4728 @deftypefnx {} {} echo on all 4729 @deftypefnx {} {} echo off all 4730 @deftypefnx {} {} echo @var{function} on 4731 @deftypefnx {} {} echo @var{function} off 4732 Control whether commands are displayed as they are executed. 4733 4734 Valid options are: 4735 4736 @table @code 4737 @item on 4738 Enable echoing of commands as they are executed in script files. 4739 4740 @item off 4741 Disable echoing of commands as they are executed in script files. 4742 4743 @item on all 4744 Enable echoing of commands as they are executed in script files and 4745 functions. 4746 4747 @item off all 4748 Disable echoing of commands as they are executed in script files and 4749 functions. 4750 4751 @item @var{function} on 4752 Enable echoing of commands as they are executed in the named function. 4753 4754 @item @var{function} off 4755 Disable echoing of commands as they are executed in the named function. 4756 @end table 4757 4758 @noindent 4759 With no arguments, @code{echo} toggles the current echo state. 4760 4761 @seealso{PS4} 4762 @end deftypefn */) 4763 { 4764 octave::tree_evaluator& tw = interp.get_evaluator (); 4765 4766 return tw.echo (args, nargout); 4767 } 4768 4769 /* 4770 %!error echo ([]) 4771 %!error echo (0) 4772 %!error echo ("") 4773 %!error echo ("Octave") 4774 %!error echo ("off", "invalid") 4775 %!error echo ("on", "invalid") 4776 %!error echo ("on", "all", "all") 4777 */ 4778