GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
pt-eval.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2009-2026 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 <condition_variable>
33#include <iostream>
34#include <list>
35#include <mutex>
36#include <string>
37#include <thread>
38
39#include "cmd-edit.h"
40#include "file-ops.h"
41#include "file-stat.h"
42#include "lo-array-errwarn.h"
43#include "lo-ieee.h"
44#include "oct-env.h"
45
46#include "bp-table.h"
47#include "call-stack.h"
48#include "cdef-manager.h"
49#include "defun.h"
50#include "error.h"
51#include "errwarn.h"
52#include "event-manager.h"
53#include "input.h"
54#include "interpreter-private.h"
55#include "interpreter.h"
56#include "mex-private.h"
57#include "octave.h"
58#include "ov-classdef.h"
59#include "ov-fcn-handle.h"
60#include "ov-mex-fcn.h"
61#include "ov-usr-fcn.h"
62#include "ov-re-sparse.h"
63#include "ov-cx-sparse.h"
64#include "parse.h"
65#include "profiler.h"
66#include "pt-all.h"
67#include "pt-anon-scopes.h"
68#include "pt-eval.h"
69#include "pt-tm-const.h"
70#include "stack-frame.h"
71#include "symtab.h"
72#include "unwind-prot.h"
73#include "utils.h"
74#include "variables.h"
75
77
78OCTAVE_NORETURN static void
79error_unexpected (const char *name)
80{
81 error ("unexpected call to %s - please report this bug", name);
82}
83
84// Normal evaluator.
85
86class quit_debug_exception
87{
88public:
89
90 quit_debug_exception (bool all = false) : m_all (all) { }
91
92 quit_debug_exception (const quit_debug_exception&) = default;
93
94 quit_debug_exception& operator = (const quit_debug_exception&) = default;
95
96 ~quit_debug_exception () = default;
97
98 bool all () const { return m_all; }
99
100private:
101
102 bool m_all;
103};
104
105class debugger
106{
107public:
108
109 enum execution_mode
110 {
111 EX_NORMAL = 0,
112 EX_CONTINUE = 1,
113 EX_QUIT = 2,
114 EX_QUIT_ALL = 3
115 };
116
117 debugger (interpreter& interp, std::size_t level)
118 : m_interpreter (interp), m_level (level),
119 m_execution_mode (EX_NORMAL), m_in_debug_repl (false)
120 { }
121
122 int server_loop ();
123
124 void repl (const std::string& prompt = "debug> ");
125
126 bool in_debug_repl () const { return m_in_debug_repl; }
127
128 void dbcont () { m_execution_mode = EX_CONTINUE; }
129
130 void dbquit (bool all = false)
131 {
132 if (all)
133 m_execution_mode = EX_QUIT_ALL;
134 else
135 m_execution_mode = EX_QUIT;
136 }
137
138 bool quitting_debugger () const;
139
140private:
141
142 interpreter& m_interpreter;
143
144 std::size_t m_level;
145 execution_mode m_execution_mode;
146 bool m_in_debug_repl;
147};
148
149// FIXME: Could the debugger server_loop and repl functions be merged
150// with the corresponding tree_evaluator functions or do they need to
151// remain separate? They perform nearly the same functions.
152
153int
154debugger::server_loop ()
155{
156 // Process events from the event queue.
157
158 tree_evaluator& tw = m_interpreter.get_evaluator ();
159
160 void (tree_evaluator::*server_mode_fptr) (bool)
161 = &tree_evaluator::server_mode;
162 unwind_action act (server_mode_fptr, &tw, true);
163
164 int exit_status = 0;
165
166 do
167 {
168 if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
169 break;
170
171 if (quitting_debugger ())
172 break;
173
174 try
175 {
176 // FIXME: Should we call octave_quit in the octave::sleep
177 // and/or command_editor::run_event_hooks functions?
178
179 octave_quit ();
180
181 // FIXME: Running the event queue should be decoupled from
182 // the command_editor.
183
184 // FIXME: Is it OK to use command_editor::run_event_hooks
185 // here? It may run more than one queued function per call,
186 // and it seems that the checks at the top of the loop
187 // probably need to be done after each individual event
188 // function is executed. For now, maybe the simplest thing
189 // would be to pass a predicate function (lambda expression)
190 // to the command_editor::run_event_hooks and have it check
191 // that and break out of the eval loop(s) if the condition
192 // is met?
193
194 // FIXME: We should also use a condition variable to manage
195 // the execution of entries in the queue and eliminate the
196 // need for the busy-wait loop.
197
199
201
202 sleep (0.1);
203 }
204 catch (const interrupt_exception&)
205 {
207 m_interpreter.recover_from_exception ();
208
209 // Required newline when the user does Ctrl+C at the prompt.
210 if (m_interpreter.interactive ())
211 octave_stdout << "\n";
212 }
213 catch (const index_exception& e)
214 {
215 m_interpreter.recover_from_exception ();
216
217 std::cerr << "error: unhandled index exception: "
218 << e.message () << " -- trying to return to prompt"
219 << std::endl;
220 }
221 catch (const execution_exception& ee)
222 {
223 error_system& es = m_interpreter.get_error_system ();
224
225 es.save_exception (ee);
226 es.display_exception (ee);
227
228 if (m_interpreter.interactive ())
229 {
230 m_interpreter.recover_from_exception ();
231 }
232 else
233 {
234 // We should exit with a nonzero status.
235 exit_status = 1;
236 break;
237 }
238 }
239 catch (const quit_debug_exception& qde)
240 {
241 if (qde.all ())
242 throw;
243
244 // Continue in this debug level.
245 }
246 catch (const std::bad_alloc&)
247 {
248 m_interpreter.recover_from_exception ();
249
250 std::cerr << "error: out of memory -- trying to return to prompt"
251 << std::endl;
252 }
253 }
254 while (exit_status == 0);
255
256 if (exit_status == EOF)
257 {
258 if (m_interpreter.interactive ())
259 octave_stdout << "\n";
260
261 exit_status = 0;
262 }
263
264 return exit_status;
265}
266
267void
268debugger::repl (const std::string& prompt_arg)
269{
270 unwind_protect frame;
271
272 frame.protect_var (m_in_debug_repl);
273 frame.protect_var (m_execution_mode);
274
275 m_in_debug_repl = true;
276
277 tree_evaluator& tw = m_interpreter.get_evaluator ();
278
279 bool silent = tw.quiet_breakpoint_flag (false);
280
283
284 tw.goto_frame (tw.debug_frame ());
285
286 octave_user_code *caller = tw.current_user_code ();
287 std::string fcn_file_nm, fcn_nm;
288
289 if (caller)
290 {
291 fcn_file_nm = caller->fcn_file_name ();
292 fcn_nm = fcn_file_nm.empty () ? caller->name () : fcn_file_nm;
293 }
294
295 int curr_debug_line = tw.current_line ();
296
297 std::ostringstream buf;
298
299 input_system& input_sys = m_interpreter.get_input_system ();
300
301 event_manager& evmgr = m_interpreter.get_event_manager ();
302
303 if (! fcn_nm.empty ())
304 {
305 if (input_sys.gud_mode ())
306 {
307 static char ctrl_z = 'Z' & 0x1f;
308
309 buf << ctrl_z << ctrl_z << fcn_nm << ':' << curr_debug_line;
310 }
311 else
312 {
313 // FIXME: we should come up with a clean way to detect
314 // that we are stopped on the no-op command that marks the
315 // end of a function or script.
316
317 if (! silent)
318 {
319 std::shared_ptr<stack_frame> frm = tw.current_user_frame ();
320
321 frm->display_stopped_in_message (buf);
322 }
323
324 evmgr.enter_debugger_event (fcn_nm, fcn_file_nm, curr_debug_line);
325
326 evmgr.set_workspace ();
327
329 fcn_nm, curr_debug_line);
330
331 if (! silent)
332 {
333 std::string line_buf;
334
335 if (caller)
336 line_buf = caller->get_code_line (curr_debug_line);
337
338 if (! line_buf.empty ())
339 buf << curr_debug_line << ": " << line_buf;
340 else
341 buf << "[End of function]";
342 }
343 }
344 }
345
346 if (silent)
348
349 std::string stopped_in_msg = buf.str ();
350
351 if (m_interpreter.server_mode ())
352 {
353 if (! stopped_in_msg.empty ())
354 octave_stdout << stopped_in_msg << std::endl;
355
356 evmgr.push_event_queue ();
357
358 frame.add (&event_manager::pop_event_queue, &evmgr);
359
360 frame.add (&tree_evaluator::set_parser, &tw, tw.get_parser ());
361
362 std::shared_ptr<push_parser>
363 debug_parser (new push_parser (m_interpreter));
364
365 tw.set_parser (debug_parser);
366
367 server_loop ();
368 }
369 else
370 {
371 if (! stopped_in_msg.empty ())
372 std::cerr << stopped_in_msg << std::endl;
373
374 std::string tmp_prompt = prompt_arg;
375 if (m_level > 0)
376 tmp_prompt = "[" + std::to_string (m_level) + "]" + prompt_arg;
377
378 frame.add (&interpreter::set_PS1, &m_interpreter, m_interpreter.PS1 ());
379 m_interpreter.PS1 (tmp_prompt);
380
381 if (! m_interpreter.interactive ())
382 {
383 void (interpreter::*interactive_fptr) (bool)
384 = &interpreter::interactive;
385 frame.add (interactive_fptr, &m_interpreter,
386 m_interpreter.interactive ());
387
388 m_interpreter.interactive (true);
389
390 // FIXME: should debugging be possible in an embedded
391 // interpreter?
392
394
395 if (app)
396 {
397 void (application::*forced_interactive_fptr) (bool)
398 = &application::forced_interactive;
399 frame.add (forced_interactive_fptr, app,
400 app->forced_interactive ());
401
402 app->forced_interactive (true);
403 }
404 }
405
406#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
407
408 input_reader reader (m_interpreter);
409
410 push_parser debug_parser (m_interpreter);
411
412#else
413
414 parser debug_parser (m_interpreter);
415
416#endif
417
418 error_system& es = m_interpreter.get_error_system ();
419
420 while (m_in_debug_repl)
421 {
422 if (m_execution_mode == EX_CONTINUE || tw.dbstep_flag ())
423 break;
424
425 if (quitting_debugger ())
426 break;
427
428 try
429 {
430 debug_parser.reset ();
431
432#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
433
434 int retval = 0;
435
436 std::string prompt
438
439 bool auto_repeat_state = input_sys.auto_repeat_debug_command ();
440
441 unwind_action restore_auto_repeat_debugging_command ([&input_sys, auto_repeat_state] () { input_sys.auto_repeat_debug_command (auto_repeat_state); });
442 do
443 {
444 bool eof = false;
445 std::string input_line = reader.get_input (prompt, eof);
446
447 if (eof)
448 {
449 retval = EOF;
450 break;
451 }
452
453 retval = debug_parser.run (input_line, false);
454
455 input_sys.auto_repeat_debug_command (false);
456 prompt = command_editor::decode_prompt_string (m_interpreter.PS2 ());
457 }
458 while (retval < 0);
459
460#else
461
462 int retval = debug_parser.run ();
463
464#endif
465 if (command_editor::interrupt (false))
466 {
467 // Break regardless of m_execution_mode value.
468
469 quitting_debugger ();
470
471 break;
472 }
473 else
474 {
475 if (retval == 0)
476 {
477 std::shared_ptr<tree_statement_list> stmt_list
478 = debug_parser.statement_list ();
479
480 if (stmt_list)
481 stmt_list->accept (tw);
482
485
486 // FIXME: the following statement is here because
487 // the last command may have been a dbup, dbdown, or
488 // dbstep command that changed the current debug
489 // frame. If so, we need to reset the current frame
490 // for the call stack. But is this right way to do
491 // this job? What if the statement list was
492 // something like "dbup; dbstack"? Will the call to
493 // dbstack use the right frame? If not, how can we
494 // fix this problem?
495 tw.goto_frame (tw.debug_frame ());
496 }
497
498 octave_quit ();
499 }
500 }
501 catch (const execution_exception& ee)
502 {
503 es.save_exception (ee);
504 es.display_exception (ee);
505
506 // Ignore errors when in debugging mode;
507 m_interpreter.recover_from_exception ();
508 }
509 catch (const quit_debug_exception& qde)
510 {
511 if (qde.all ())
512 throw;
513
514 // Continue in this debug level.
515 }
516 }
517 }
518}
519
520bool
521debugger::quitting_debugger () const
522{
523 if (m_execution_mode == EX_QUIT)
524 {
525 // If there is no enclosing debug level or the top-level
526 // repl is not active, handle dbquit the same as dbcont.
527
528 if (m_level > 0 || m_interpreter.server_mode ()
529 || m_interpreter.in_top_level_repl ())
530 throw quit_debug_exception ();
531 else
532 return true;
533 }
534
535 if (m_execution_mode == EX_QUIT_ALL)
536 {
537 // If the top-level repl is not active, handle "dbquit all"
538 // the same as dbcont.
539
540 if (m_interpreter.server_mode () || m_interpreter.in_top_level_repl ())
541 throw quit_debug_exception (true);
542 else
543 return true;
544 }
545
546 return false;
547}
548
549bool
551{
552 return m_call_stack.at_top_level ();
553}
554
555std::string
556tree_evaluator::mfilename (const std::string& opt) const
557{
558 std::string fname;
559
560 octave_user_code *fcn = m_call_stack.current_user_code ();
561
562 if (fcn)
563 {
564 fname = fcn->fcn_file_name ();
565
566 if (fname.empty ())
567 fname = fcn->name ();
568 }
569
570 if (opt == "fullpathext")
571 return fname;
572
573 std::size_t dpos = fname.rfind (sys::file_ops::dir_sep_char ());
574 std::size_t epos = fname.rfind ('.');
575
576 if (epos <= dpos+1)
577 epos = std::string::npos;
578
579 if (epos != std::string::npos)
580 fname = fname.substr (0, epos);
581
582 if (opt == "fullpath")
583 return fname;
584
585 if (dpos != std::string::npos)
586 fname = fname.substr (dpos+1);
587
588 return fname;
589}
590
591void
592tree_evaluator::parse_and_execute (const std::string& input,
593 bool& incomplete_parse)
594{
595 incomplete_parse = false;
596
597 unwind_protect_var<bool> upv (m_in_top_level_repl, true);
598
599 if (at_top_level ())
600 {
601 dbstep_flag (0);
603 }
604
605 // FIXME: OK to do this job here, or should it be in the functions
606 // that do the actual prompting?
607
608 // Update the time stamp for the "prompt" so that automatically
609 // finding modified files based on file modification times will
610 // work. In the future, we may do something completely different to
611 // check for changes to files but for now, we rely on the prompt
612 // time stamp to limit the checks for file modification times.
613
614 Vlast_prompt_time.stamp ();
615
616 bool eof = false;
617
618 event_manager& evmgr = m_interpreter.get_event_manager ();
619
620 if (command_history::add (input))
621 evmgr.append_history (input);
622
623 m_exit_status = m_parser->run (input, eof);
624
625 if (m_exit_status == 0)
626 {
627 std::shared_ptr<tree_statement_list>
628 stmt_list = m_parser->statement_list ();
629
630 if (stmt_list)
631 {
633
634 eval (stmt_list, m_interpreter.interactive ());
635
636 evmgr.set_workspace ();
637 }
638 else if (m_parser->at_end_of_input ())
639 m_exit_status = EOF;
640 }
641 else
642 incomplete_parse = true;
643
644 // FIXME: Should we be checking m_exit_status or incomplete_parse or
645 // both here? Could EOF have a value other than -1, and is there
646 // possible confusion between that state and the parser returning -1?
647
648 if (m_exit_status == -1)
649 m_exit_status = 0;
650 else
651 m_parser->reset ();
652
653 evmgr.pre_input_event ();
654}
655
656void
658{
659 std::mutex mtx;
660 std::unique_lock<std::mutex> lock (mtx);
661 std::condition_variable cv;
662 bool incomplete_parse = false;
663 bool evaluation_pending = false;
664 bool exiting = false;
665
666 event_manager& evmgr = m_interpreter.get_event_manager ();
667
668 while (true)
669 {
670 // FIXME: Detect EOF? Use readline? If
671 // so, then we need to disable idle event loop hook function
672 // execution.
673
674 std::string ps
675 = incomplete_parse ? m_interpreter.PS2 () : m_interpreter.PS1 ();
676
677 std::cout << command_editor::decode_prompt_string (ps);
678
679 std::string input;
680 std::getline (std::cin, input);
681
682 if (input.empty ())
683 continue;
684
685 incomplete_parse = false;
686 evaluation_pending = true;
687 exiting = false;
688
689 evmgr.post_event
690 ([this, input, &mtx, &incomplete_parse, &evaluation_pending, &cv, &exiting] (interpreter& interp)
691 {
692 // INTERPRETER THREAD
693
694 std::lock_guard<std::mutex> local_lock (mtx);
695
696 try
697 {
698 interp.parse_and_execute (input, incomplete_parse);
699 }
700 catch (const exit_exception&)
701 {
702 evaluation_pending = false;
703 exiting = true;
704 cv.notify_all ();
705 throw;
706 }
707 catch (const execution_exception& ee)
708 {
709 error_system& es = interp.get_error_system ();
710
711 es.save_exception (ee);
712 es.display_exception (ee);
713
714 if (interp.interactive ())
715 {
716 interp.recover_from_exception ();
717 m_parser->reset ();
718 evaluation_pending = false;
719 cv.notify_all ();
720 }
721 else
722 {
723 evaluation_pending = false;
724 cv.notify_all ();
725 throw exit_exception (1);
726 }
727 }
728 catch (...)
729 {
730 evaluation_pending = false;
731 cv.notify_all ();
732 throw;
733 }
734
735 evaluation_pending = false;
736 cv.notify_all ();
737 });
738
739 // Wait until evaluation is finished before prompting for input
740 // again.
741
742 cv.wait (lock, [&evaluation_pending] { return ! evaluation_pending; });
743
744 if (exiting)
745 break;
746 }
747}
748
749int
751{
752 // The big loop. Read, Eval, Print, Loop. Normally user
753 // interaction at the command line in a terminal session, but we may
754 // also end up here when reading from a pipe or when stdin is
755 // connected to a file by the magic of input redirection.
756
757 int exit_status = 0;
758
759 // FIXME: should this choice be a command-line option? Note that we
760 // intend that the push parser interface only be used for
761 // interactive sessions.
762
763#if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
764 static bool use_command_line_push_parser = true;
765#else
766 static bool use_command_line_push_parser = false;
767#endif
768
769 // The following logic is written as it is to allow easy transition
770 // to setting USE_COMMAND_LINE_PUSH_PARSER at run time and to
771 // simplify the logic of the main loop below by using the same
772 // base_parser::run interface for both push and pull parsers.
773
774 std::shared_ptr<base_parser> repl_parser;
775
776 if (m_interpreter.interactive ())
777 {
778 if (use_command_line_push_parser)
779 {
780 push_parser *pp
781 = new push_parser (m_interpreter,
782 new input_reader (m_interpreter));
783
784 repl_parser = std::shared_ptr<base_parser> (pp);
785 }
786 else
787 {
788 parser *pp = new parser (new lexer (m_interpreter));
789 repl_parser = std::shared_ptr<base_parser> (pp);
790 }
791 }
792 else
793 {
794 parser *pp = new parser (new lexer (stdin, m_interpreter));
795 repl_parser = std::shared_ptr<base_parser> (pp);
796 }
797
798 do
799 {
800 try
801 {
802 unwind_protect_var<bool> upv (m_in_top_level_repl, true);
803
804 repl_parser->reset ();
805
806 if (at_top_level ())
807 {
808 dbstep_flag (0);
810 }
811
812 exit_status = repl_parser->run ();
813
814 if (exit_status == 0)
815 {
816 std::shared_ptr<tree_statement_list>
817 stmt_list = repl_parser->statement_list ();
818
819 if (stmt_list)
820 {
822
823 eval (stmt_list, m_interpreter.interactive ());
824 }
825 else if (repl_parser->at_end_of_input ())
826 {
827 exit_status = EOF;
828 break;
829 }
830 }
831 }
832 catch (const interrupt_exception&)
833 {
834 m_interpreter.recover_from_exception ();
835
836 // Required newline when the user does Ctrl+C at the prompt.
837 if (m_interpreter.interactive ())
838 octave_stdout << "\n";
839 }
840 catch (const index_exception& ie)
841 {
842 m_interpreter.recover_from_exception ();
843
844 std::cerr << "error: unhandled index exception: "
845 << ie.message () << " -- trying to return to prompt"
846 << std::endl;
847 }
848 catch (const execution_exception& ee)
849 {
850 error_system& es = m_interpreter.get_error_system ();
851
852 es.save_exception (ee);
853 es.display_exception (ee);
854
855 if (m_interpreter.interactive ())
856 m_interpreter.recover_from_exception ();
857 else
858 {
859 // We should exit with a nonzero status.
860 exit_status = 1;
861 break;
862 }
863 }
864 catch (const quit_debug_exception&)
865 {
866 m_interpreter.recover_from_exception ();
867
868 // FIXME: Does anything else need to happen here?
869 }
870 catch (const std::bad_alloc&)
871 {
872 m_interpreter.recover_from_exception ();
873
874 std::cerr << "error: out of memory -- trying to return to prompt"
875 << std::endl;
876 }
877 }
878 while (exit_status == 0);
879
880 if (exit_status == EOF)
881 {
882 if (m_interpreter.interactive ())
883 octave_stdout << "\n";
884
885 exit_status = 0;
886 }
887
888 return exit_status;
889}
890
891int
893{
894 // Process events from the event queue.
895
896 unwind_protect_var<bool> upv1 (m_server_mode, true);
897
898 m_exit_status = 0;
899
900 std::shared_ptr<push_parser> parser (new push_parser (m_interpreter));
902
903 // FIXME: We are currently resetting the parser after every call to
904 // recover_from_exception. This action should probably be handled
905 // in a more consistent way, but resetting the parser in every call
906 // to interpreter::recover_from_exception appears to cause
907 // segfaults in the test suite.
908
909 do
910 {
911 try
912 {
913 // FIXME: Should we call octave_quit in the octave::sleep
914 // and/or command_editor::run_event_hooks functions?
915
916 octave_quit ();
917
918 // FIXME: Running the event queue should be decoupled from
919 // the command_editor. We should also use a condition
920 // variable to manage the execution of entries in the queue
921 // and eliminate the need for the busy-wait loop.
922
924
926
927 sleep (0.1);
928 }
929 catch (const interrupt_exception&)
930 {
932 m_interpreter.recover_from_exception ();
933 m_parser->reset ();
934
935 // Required newline when the user does Ctrl+C at the prompt.
936 if (m_interpreter.interactive ())
937 octave_stdout << "\n";
938 }
939 catch (const index_exception& e)
940 {
941 m_interpreter.recover_from_exception ();
942 m_parser->reset ();
943
944 std::cerr << "error: unhandled index exception: "
945 << e.message () << " -- trying to return to prompt"
946 << std::endl;
947 }
948 catch (const execution_exception& ee)
949 {
950 error_system& es = m_interpreter.get_error_system ();
951
952 es.save_exception (ee);
953 es.display_exception (ee);
954
955 if (m_interpreter.interactive ())
956 {
957 m_interpreter.recover_from_exception ();
958 m_parser->reset ();
959 }
960 else
961 {
962 // We should exit with a nonzero status.
963 m_exit_status = 1;
964 break;
965 }
966 }
967 catch (const quit_debug_exception&)
968 {
970 m_interpreter.recover_from_exception ();
971 m_parser->reset ();
972 }
973 catch (const exit_exception& xe)
974 {
975 m_exit_status = xe.exit_status ();
976 break;
977 }
978 catch (const std::bad_alloc&)
979 {
980 m_interpreter.recover_from_exception ();
981 m_parser->reset ();
982
983 std::cerr << "error: out of memory -- trying to return to prompt"
984 << std::endl;
985 }
986 }
987 while (m_exit_status == 0);
988
989 if (m_exit_status == EOF)
990 {
991 if (m_interpreter.interactive ())
992 octave_stdout << "\n";
993
994 m_exit_status = 0;
995 }
996
997 return m_exit_status;
998}
999
1000void
1001tree_evaluator::eval (std::shared_ptr<tree_statement_list>& stmt_list,
1002 bool interactive)
1003{
1004 try
1005 {
1006 stmt_list->accept (*this);
1007
1008 octave_quit ();
1009
1010 if (! interactive)
1011 {
1012 bool quit = (m_returning || m_breaking);
1013
1014 if (m_returning)
1015 m_returning = 0;
1016
1017 if (m_breaking)
1018 m_breaking--;
1019
1020 if (quit)
1021 return;
1022 }
1023
1026 }
1027 catch (const quit_debug_exception&)
1028 {
1029 m_interpreter.recover_from_exception ();
1030 }
1031}
1032
1034tree_evaluator::eval_string (const std::string& eval_str, bool silent,
1035 int& parse_status, int nargout)
1036{
1037 octave_value_list retval;
1038
1039 parser eval_parser (eval_str, m_interpreter);
1040
1041 do
1042 {
1043 eval_parser.reset ();
1044
1045 // If we are looking at
1046 //
1047 // val = eval ("code");
1048 //
1049 // then don't allow code to be parsed as a command.
1050
1051 if (nargout > 0)
1052 eval_parser.disallow_command_syntax ();
1053
1054 parse_status = eval_parser.run ();
1055
1056 if (parse_status == 0)
1057 {
1058 std::shared_ptr<tree_statement_list> stmt_list
1059 = eval_parser.statement_list ();
1060
1061 if (stmt_list)
1062 {
1063 tree_statement *stmt = nullptr;
1064
1065 if (stmt_list->size () == 1
1066 && (stmt = stmt_list->front ())
1067 && stmt->is_expression ())
1068 {
1069 tree_expression *expr = stmt->expression ();
1070
1071 if (silent)
1072 expr->set_print_flag (false);
1073
1074 retval = expr->evaluate_n (*this, nargout);
1075
1076 bool do_bind_ans = false;
1077
1078 if (expr->is_identifier ())
1079 do_bind_ans = ! is_variable (expr);
1080 else
1081 do_bind_ans = ! expr->is_assignment_expression ();
1082
1083 if (nargout == 0 && do_bind_ans && ! retval.empty ())
1084 bind_ans (retval(0), expr->print_result ());
1085
1086 if (nargout == 0)
1087 retval = octave_value_list ();
1088 }
1089 else if (nargout == 0)
1090 stmt_list->accept (*this);
1091 else
1092 error ("eval: invalid use of statement list");
1093
1094 if (returning () || breaking () || continuing ())
1095 break;
1096 }
1097 else if (eval_parser.at_end_of_input ())
1098 break;
1099 }
1100 }
1101 while (parse_status == 0);
1102
1103 return retval;
1104}
1105
1107tree_evaluator::eval_string (const std::string& eval_str,
1108 bool silent, int& parse_status)
1109{
1110 octave_value retval;
1111
1112 octave_value_list tmp = eval_string (eval_str, silent, parse_status, 1);
1113
1114 if (! tmp.empty ())
1115 retval = tmp(0);
1116
1117 return retval;
1118}
1119
1122 bool silent, int& parse_status,
1123 int nargout)
1124{
1125 std::string s = arg.xstring_value ("eval: expecting string argument");
1126
1127 return eval_string (s, silent, parse_status, nargout);
1128}
1129
1131tree_evaluator::eval (const std::string& try_code,
1132 int nargout)
1133{
1134 int parse_status = 0;
1135
1136 return eval_string (try_code, nargout > 0, parse_status, nargout);
1137}
1138
1140tree_evaluator::eval (const std::string& try_code,
1141 const std::string& catch_code,
1142 int nargout)
1143{
1144 octave_value_list retval;
1145
1146 error_system& es = m_interpreter.get_error_system ();
1147
1148 int parse_status = 0;
1149
1150 bool execution_error = false;
1151
1153
1154 try
1155 {
1156 tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
1157 }
1158 catch (const execution_exception& ee)
1159 {
1160 es.save_exception (ee);
1161 m_interpreter.recover_from_exception ();
1162
1163 execution_error = true;
1164 }
1165
1166 if (parse_status != 0 || execution_error)
1167 {
1168 tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
1169
1170 retval = (nargout > 0) ? tmp : octave_value_list ();
1171 }
1172 else
1173 {
1174 if (nargout > 0)
1175 retval = tmp;
1176
1177 // FIXME: we should really be rethrowing whatever
1178 // exception occurred, not just throwing an
1179 // execution exception.
1180 if (execution_error)
1181 throw execution_exception ();
1182 }
1183
1184 return retval;
1185}
1186
1188tree_evaluator::evalin (const std::string& context,
1189 const std::string& try_code,
1190 int nargout)
1191{
1192 unwind_action act ([this] (std::size_t frm)
1193 {
1194 m_call_stack.restore_frame (frm);
1195 }, m_call_stack.current_frame ());
1196
1197 if (context == "caller")
1198 m_call_stack.goto_caller_frame ();
1199 else if (context == "base")
1200 m_call_stack.goto_base_frame ();
1201 else
1202 error (R"(evalin: CONTEXT must be "caller" or "base")");
1203
1204 int parse_status = 0;
1205
1206 return eval_string (try_code, nargout > 0, parse_status, nargout);
1207}
1208
1210tree_evaluator::evalin (const std::string& context,
1211 const std::string& try_code,
1212 const std::string& catch_code,
1213 int nargout)
1214{
1215 octave_value_list retval;
1216
1217 unwind_action act1 ([this] (std::size_t frm)
1218 {
1219 m_call_stack.restore_frame (frm);
1220 }, m_call_stack.current_frame ());
1221
1222 if (context == "caller")
1223 m_call_stack.goto_caller_frame ();
1224 else if (context == "base")
1225 m_call_stack.goto_base_frame ();
1226 else
1227 error (R"(evalin: CONTEXT must be "caller" or "base")");
1228
1229 error_system& es = m_interpreter.get_error_system ();
1230
1231 int parse_status = 0;
1232
1233 bool execution_error = false;
1234
1236
1237 try
1238 {
1239 tmp = eval_string (try_code, nargout > 0, parse_status, nargout);
1240 }
1241 catch (const execution_exception& ee)
1242 {
1243 es.save_exception (ee);
1244 m_interpreter.recover_from_exception ();
1245
1246 execution_error = true;
1247 }
1248
1249 if (parse_status != 0 || execution_error)
1250 {
1251 tmp = eval_string (catch_code, nargout > 0, parse_status, nargout);
1252
1253 retval = (nargout > 0) ? tmp : octave_value_list ();
1254 }
1255 else
1256 {
1257 if (nargout > 0)
1258 retval = tmp;
1259
1260 // FIXME: we should really be rethrowing whatever
1261 // exception occurred, not just throwing an
1262 // execution exception.
1263 if (execution_error)
1264 throw execution_exception ();
1265 }
1266
1267 return retval;
1268}
1269
1270void
1272{
1273 error_unexpected ("tree_evaluator::visit_anon_fcn_handle");
1274}
1275
1276void
1278{
1279 error_unexpected ("tree_evaluator::visit_argument_list");
1280}
1281
1282void
1284{
1285 warning ("function arguments validation blocks are not supported; INCORRECT RESULTS ARE POSSIBLE");
1286}
1287
1288void
1290{
1291 error_unexpected ("tree_evaluator::visit_args_block_attribute_list");
1292}
1293
1294void
1296{
1297 error_unexpected ("tree_evaluator::visit_args_block_validation_list");
1298}
1299
1300void
1302{
1303 error_unexpected ("tree_evaluator::visit_arg_validation");
1304}
1305
1306void
1308{
1309 error_unexpected ("tree_evaluator::visit_arg_size_spec");
1310}
1311
1312void
1314{
1315 error_unexpected ("tree_evaluator::visit_arg_validation_fcns");
1316}
1317
1318void
1320{
1321 error_unexpected ("tree_evaluator::visit_binary_expression");
1322}
1323
1324void
1326{
1327 error_unexpected ("tree_evaluator::visit_boolean_expression");
1328}
1329
1330void
1332{
1333 error_unexpected ("tree_evaluator::visit_compound_binary_expression");
1334}
1335
1336void
1338{
1339 if (m_echo_state)
1340 {
1341 int line = cmd.line ();
1342 if (line < 0)
1343 line = 1;
1344 echo_code (line);
1345 m_echo_file_pos = line + 1;
1346 }
1347
1348 if (m_debug_mode)
1349 do_breakpoint (cmd.is_active_breakpoint (*this));
1350
1351 if (m_in_loop_command)
1352 m_breaking = 1;
1353 else
1354 error ("break must appear in a loop in the same file as loop command");
1355}
1356
1357void
1359{
1360 error_unexpected ("tree_evaluator::visit_colon_expression");
1361}
1362
1363void
1365{
1366 if (m_echo_state)
1367 {
1368 int line = cmd.line ();
1369 if (line < 0)
1370 line = 1;
1371 echo_code (line);
1372 m_echo_file_pos = line + 1;
1373 }
1374
1375 if (m_debug_mode)
1376 do_breakpoint (cmd.is_active_breakpoint (*this));
1377
1378 if (m_in_loop_command)
1379 m_continuing = 1;
1380}
1381
1382bool
1384{
1385 return ! (m_silent_functions && (m_statement_context == SC_FUNCTION
1386 || m_statement_context == SC_SCRIPT));
1387}
1388
1389void
1391{
1392 m_debug_mode = (m_bp_table.have_breakpoints ()
1393 || m_dbstep_flag != 0
1394 || m_break_on_next_stmt
1395 || in_debug_repl ());
1396}
1397
1398void
1400{
1401 m_debug_mode = mode;
1402}
1403
1404void
1405tree_evaluator::enter_debugger (const std::string& prompt)
1406{
1407 unwind_protect frame;
1408
1411
1413
1414 frame.add (&call_stack::restore_frame, &m_call_stack,
1415 m_call_stack.current_frame ());
1416
1417 // Don't allow errors or warnings at the debug prompt to push us
1418 // into deeper levels of debugging.
1419
1420 error_system& es = m_interpreter.get_error_system ();
1421
1423
1425 es.debug_on_warning ());
1426
1427 es.debug_on_error (false);
1428 es.debug_on_warning (false);
1429
1430 // Go up to the nearest user code frame.
1431
1432 tree_evaluator& tw = m_interpreter.get_evaluator ();
1433
1434 frame.add ([&tw, saved_frame = m_debug_frame] ()
1435 {
1436 if (! tw.dbstep_flag ())
1437 tw.debug_frame (saved_frame);
1438 });
1439
1440 m_debug_frame = m_call_stack.dbupdown (0);
1441
1442 // FIXME: probably we just want to print one line, not the
1443 // entire statement, which might span many lines...
1444 //
1445 // tree_print_code tpc (octave_stdout);
1446 // stmt.accept (tpc);
1447
1448 debugger *dbgr = new debugger (m_interpreter, m_debugger_stack.size ());
1449
1450 m_debugger_stack.push (dbgr);
1451
1452 frame.add ([this] ()
1453 {
1454 delete m_debugger_stack.top ();
1455 m_debugger_stack.pop ();
1457 });
1458
1459 dbgr->repl (prompt);
1460}
1461
1462void
1463tree_evaluator::keyboard (const std::string& prompt)
1464{
1465 enter_debugger (prompt);
1466}
1467
1468void
1469tree_evaluator::dbupdown (int n, bool verbose)
1470{
1471 m_debug_frame = m_call_stack.dbupdown (n, verbose);
1472}
1473
1474std::string tree_evaluator::inputname (int n, bool ids_only) const
1475{
1476 std::shared_ptr<stack_frame> frame = m_call_stack.current_user_frame ();
1477
1478 return frame->inputname (n, ids_only);
1479}
1480
1481Matrix
1483{
1484 Matrix retval;
1485
1486 const std::list<octave_lvalue> *lvalues = m_lvalue_list;
1487
1488 if (! lvalues)
1489 return retval;
1490
1491 octave_idx_type nbh = 0;
1492
1493 for (const auto& lval : *lvalues)
1494 nbh += lval.is_black_hole ();
1495
1496 if (nbh > 0)
1497 {
1498 retval.resize (1, nbh);
1499
1500 octave_idx_type k = 0;
1501 octave_idx_type l = 0;
1502
1503 for (const auto& lval : *lvalues)
1504 {
1505 if (lval.is_black_hole ())
1506 retval(l++) = k+1;
1507
1508 k += lval.numel ();
1509 }
1510 }
1511
1512 return retval;
1513}
1514
1515// If NAME is an operator (like "+", "-", ...), convert it to the
1516// corresponding function name ("plus", "minus", ...).
1517
1518static std::string
1519get_operator_function_name (const std::string& name)
1520{
1521 // Bow to the god of compatibility.
1522
1523 // FIXME: it seems ugly to put this here, but there is no single
1524 // function in the parser that converts from the operator name to
1525 // the corresponding function name. At least try to do it without N
1526 // string compares.
1527
1528 std::size_t len = name.length ();
1529
1530 if (len == 2)
1531 {
1532 if (name[0] == '.')
1533 {
1534 switch (name[1])
1535 {
1536 case '\'':
1537 return "transpose";
1538
1539 case '*':
1540 return "times";
1541
1542 case '/':
1543 return "rdivide";
1544
1545 case '^':
1546 return "power";
1547
1548 case '\\':
1549 return "ldivide";
1550
1551 default:
1552 break;
1553 }
1554 }
1555 else if (name[1] == '=')
1556 {
1557 switch (name[0])
1558 {
1559 case '<':
1560 return "le";
1561
1562 case '=':
1563 return "eq";
1564
1565 case '>':
1566 return "ge";
1567
1568 case '~':
1569 case '!':
1570 return "ne";
1571
1572 default:
1573 break;
1574 }
1575 }
1576 }
1577 else if (len == 1)
1578 {
1579 switch (name[0])
1580 {
1581 case '~':
1582 case '!':
1583 return "not";
1584
1585 case '\'':
1586 return "ctranspose";
1587
1588 case '+':
1589 return "plus";
1590
1591 case '-':
1592 return "minus";
1593
1594 case '*':
1595 return "mtimes";
1596
1597 case '/':
1598 return "mrdivide";
1599
1600 case '^':
1601 return "mpower";
1602
1603 case '\\':
1604 return "mldivide";
1605
1606 case '<':
1607 return "lt";
1608
1609 case '>':
1610 return "gt";
1611
1612 case '&':
1613 return "and";
1614
1615 case '|':
1616 return "or";
1617
1618 default:
1619 break;
1620 }
1621 }
1622
1623 return name;
1624}
1625
1626// Creates a function handle that takes into account the context,
1627// finding local, nested, private, or sub functions.
1628
1630tree_evaluator::make_fcn_handle (const std::string& name)
1631{
1632 octave_value retval;
1633
1634 // The str2func function can create a function handle with the name
1635 // of an operator (for example, "+"). If so, it is converted to the
1636 // name of the corresponding function ("+" -> "plus") and we create
1637 // a simple function handle using that name.
1638
1639 std::string fcn_name = get_operator_function_name (name);
1640
1641 // If FCN_NAME is different from NAME, then NAME is an operator. As
1642 // of version 2020a, Matlab apparently uses the function name
1643 // corresponding to the operator to search for private and local
1644 // functions in the current scope but not(!) nested functions.
1645
1646 bool name_is_operator = fcn_name != name;
1647
1648 std::size_t pos = fcn_name.find ('.');
1649
1650 if (pos != std::string::npos)
1651 {
1652 // Recognize (some of? which ones?) the following cases
1653 // and create something other than a simple function handle?
1654 // Should we just be checking for the last two when the first
1655 // element of the dot-separated list is an object? If so, then
1656 // should this syntax be limited to a dot-separated list with
1657 // exactly two elements?
1658 //
1659 // object . method
1660 // object . static-method
1661 //
1662 // Code to do that duplicates some of simple_fcn_handle::call.
1663
1664 // Only accept expressions that contain one '.' separator.
1665
1666 // FIXME: The logic here is a bit complicated. Is there a good
1667 // way to simplify it?
1668
1669 std::string meth_nm = fcn_name.substr (pos+1);
1670
1671 if (meth_nm.find ('.') == std::string::npos)
1672 {
1673 std::string obj_nm = fcn_name.substr (0, pos);
1674
1675 // If obj_nm is an object in the current scope with a
1676 // method named meth_nm, create a classsimple handle.
1677
1678 octave_value object = varval (obj_nm);
1679
1680 if (object.is_defined () && object.is_classdef_object ())
1681 {
1682 octave_classdef *cdef = object.classdef_object_value ();
1683
1684 if (cdef)
1685 {
1686 std::string class_nm = cdef->class_name ();
1687
1688 cdef_object cdef_obj = cdef->get_object ();
1689
1690 cdef_class cls = cdef_obj.get_class ();
1691
1692 cdef_method meth = cls.find_method (meth_nm);
1693
1694 if (meth.ok ())
1695 {
1696 // If the method we found is static, create a
1697 // new function name from the class name and
1698 // method name and create a simple function
1699 // handle below. Otherwise, create a class
1700 // simple function handle.
1701
1702 if (meth.is_static ())
1703 fcn_name = class_nm + '.' + meth_nm;
1704 else
1705 {
1706 octave_value meth_fcn = meth.get_function ();
1707
1709 = new octave_fcn_handle (object, meth_fcn,
1710 class_nm, meth_nm);
1711
1712 return octave_value (fh);
1713 }
1714 }
1715 }
1716 }
1717 }
1718
1719 // We didn't match anything above, so create handle to SIMPLE
1720 // package function or static class method. Function resolution
1721 // is performed when the handle is used.
1722
1723 return octave_value (new octave_fcn_handle (fcn_name));
1724 }
1725
1726 // If the function name refers to a sub/local/private function or a
1727 // class method/constructor, create scoped function handle that is
1728 // bound to that function. Use the same precedence list as
1729 // fcn_info::find but limit search to the following types of
1730 // functions:
1731 //
1732 // nested functions (and subfunctions)
1733 // local functions in the current file
1734 // private function
1735 // class method
1736 //
1737 // For anything else we create a simple function handle that will be
1738 // resolved dynamically in the scope where it is evaluated.
1739
1740 symbol_scope curr_scope = get_current_scope ();
1741
1742 symbol_table& symtab = m_interpreter.get_symbol_table ();
1743
1744 if (curr_scope)
1745 {
1746 octave_value ov_fcn
1747 = symtab.find_scoped_function (fcn_name, curr_scope);
1748
1749 // If name is operator, we are in Fstr2func, so skip the stack
1750 // frame for that function.
1751
1752 bool skip_first = name_is_operator;
1753 octave_function *curr_fcn = current_function (skip_first);
1754
1755 if (ov_fcn.is_defined ())
1756 {
1757 octave_function *fcn = ov_fcn.function_value ();
1758
1759 if (fcn->is_nested_function ())
1760 {
1761 if (! name_is_operator)
1762 {
1763 // Get current stack frame and return handle to nested
1764 // function.
1765
1766 std::shared_ptr<stack_frame> frame
1767 = m_call_stack.get_current_stack_frame ();
1768
1769 // If we are creating a handle to the current
1770 // function or a handle to a sibling function (i.e.,
1771 // not a child of the current function), then use
1772 // the calling stack frame as the context instead of
1773 // the current stack frame.
1774
1775 // FIXME: Do we need both checks here or is it
1776 // sufficient to check that the parent of curr_fcn
1777 // is the same as the parent of fcn? Is there any
1778 // case where curr_fcn could be nullptr, or does
1779 // that indicate an internal error of some kind?
1780
1781 if (curr_fcn
1782 && (fcn_name == curr_fcn->name ()
1783 || fcn->parent_fcn_name () == curr_fcn->parent_fcn_name ()))
1784 frame = frame->access_link ();
1785
1787 = new octave_fcn_handle (ov_fcn, fcn_name, frame);
1788
1789 return octave_value (fh);
1790 }
1791 }
1792 else if (fcn->is_subfunction ()
1793 /* || fcn->is_localfunction () */
1794 || fcn->is_private_function ())
1795 {
1796 // Create handle to SCOPED function (sub/local function
1797 // or private function).
1798
1799 std::list<std::string> parentage = fcn->parent_fcn_names ();
1800
1802 = new octave_fcn_handle (ov_fcn, fcn_name, parentage);
1803
1804 return octave_value (fh);
1805 }
1806 }
1807
1808 if (curr_fcn && (curr_fcn->is_class_method ()
1809 || curr_fcn->is_class_constructor ()))
1810 {
1811 std::string dispatch_class = curr_fcn->dispatch_class ();
1812
1813 octave_value ov_meth
1814 = symtab.find_method (fcn_name, dispatch_class);
1815
1816 if (ov_meth.is_defined ())
1817 {
1818 octave_function *fcn = ov_meth.function_value ();
1819
1820 // FIXME: do we need to check that it is a method of
1821 // dispatch_class, or is it sufficient to just check
1822 // that it is a method?
1823
1824 if (fcn->is_class_method ())
1825 {
1826 // Create CLASSSIMPLE handle to method but don't
1827 // bind to the method. Lookup will be done later.
1828
1830 = new octave_fcn_handle (dispatch_class, fcn_name);
1831
1832 return octave_value (fh);
1833 }
1834 }
1835 }
1836 }
1837
1838 octave_value ov_fcn = symtab.find_user_function (fcn_name);
1839
1840 // Create handle to SIMPLE function. If the function is not found
1841 // now, then we will look for it again when the handle is used.
1842
1843 return octave_value (new octave_fcn_handle (ov_fcn, fcn_name));
1844}
1845
1846/*
1847%!test
1848%! x = {".'", "transpose";
1849%! ".*", "times";
1850%! "./", "rdivide";
1851%! ".^", "power";
1852%! ".\\", "ldivide";
1853%! "<=", "le";
1854%! "==", "eq";
1855%! ">=", "ge";
1856%! "!=", "ne";
1857%! "~=", "ne";
1858%! "~", "not";
1859%! "!", "not";
1860%! "\'", "ctranspose";
1861%! "+", "plus";
1862%! "-", "minus";
1863%! "*", "mtimes";
1864%! "/", "mrdivide";
1865%! "^", "mpower";
1866%! "\\", "mldivide";
1867%! "<", "lt";
1868%! ">", "gt";
1869%! "&", "and";
1870%! "|", "or"};
1871%! for i = 1:rows (x)
1872%! assert (functions (str2func (x{i,1})).function, x{i,2});
1873%! endfor
1874*/
1875
1878{
1879 // Do not allow functions to return null values.
1880
1881 tree_identifier *id = elt->ident ();
1882
1883 return id ? id->evaluate (*this).storable_value () : octave_value ();
1884}
1885
1886bool
1887tree_evaluator::is_variable (const std::string& name) const
1888{
1889 std::shared_ptr<stack_frame> frame
1890 = m_call_stack.get_current_stack_frame ();
1891
1892 return frame->is_variable (name);
1893}
1894
1895bool
1896tree_evaluator::is_local_variable (const std::string& name) const
1897{
1898 std::shared_ptr<stack_frame> frame
1899 = m_call_stack.get_current_stack_frame ();
1900
1901 return frame->is_local_variable (name);
1902}
1903
1904bool
1906{
1907 if (expr->is_identifier ())
1908 {
1909 const tree_identifier *id
1910 = dynamic_cast<const tree_identifier *> (expr);
1911
1912 if (id->is_black_hole ())
1913 return false;
1914
1915 return is_variable (id->symbol ());
1916 }
1917
1918 return false;
1919}
1920
1921bool
1923{
1924 if (expr->is_identifier ())
1925 {
1926 const tree_identifier *id
1927 = dynamic_cast<const tree_identifier *> (expr);
1928
1929 return is_defined (id->symbol ());
1930 }
1931
1932 return false;
1933}
1934
1935bool
1937{
1938 std::shared_ptr<stack_frame> frame
1939 = m_call_stack.get_current_stack_frame ();
1940
1941 return frame->is_variable (sym);
1942}
1943
1944bool
1946{
1947 std::shared_ptr<stack_frame> frame
1948 = m_call_stack.get_current_stack_frame ();
1949
1950 return frame->is_defined (sym);
1951}
1952
1953bool
1954tree_evaluator::is_global (const std::string& name) const
1955{
1956 std::shared_ptr<stack_frame> frame
1957 = m_call_stack.get_current_stack_frame ();
1958
1959 return frame->is_global (name);
1960}
1961
1964{
1965 std::shared_ptr<stack_frame> frame
1966 = m_call_stack.get_current_stack_frame ();
1967
1968 return frame->varval (sym);
1969}
1970
1972tree_evaluator::varval (const std::string& name) const
1973{
1974 std::shared_ptr<stack_frame> frame
1975 = m_call_stack.get_current_stack_frame ();
1976
1977 return frame->varval (name);
1978}
1979
1980void
1981tree_evaluator::install_variable (const std::string& name,
1982 const octave_value& value,
1983 bool global)
1984{
1985 std::shared_ptr<stack_frame> frame
1986 = m_call_stack.get_current_stack_frame ();
1987
1988 return frame->install_variable (name, value, global);
1989}
1990
1992tree_evaluator::global_varval (const std::string& name) const
1993{
1994 return m_call_stack.global_varval (name);
1995}
1996
1998tree_evaluator::global_varref (const std::string& name)
1999{
2000 return m_call_stack.global_varref (name);
2001}
2002
2003void
2004tree_evaluator::global_assign (const std::string& name,
2005 const octave_value& val)
2006{
2007 m_call_stack.global_varref (name) = val;
2008}
2009
2011tree_evaluator::top_level_varval (const std::string& name) const
2012{
2013 return m_call_stack.get_top_level_value (name);
2014}
2015
2016void
2017tree_evaluator::top_level_assign (const std::string& name,
2018 const octave_value& val)
2019{
2020 m_call_stack.set_top_level_value (name, val);
2021}
2022
2023void
2024tree_evaluator::assign (const std::string& name, const octave_value& val)
2025{
2026 std::shared_ptr<stack_frame> frame
2027 = m_call_stack.get_current_stack_frame ();
2028
2029 frame->assign (name, val);
2030}
2031
2032void
2033tree_evaluator::assignin (const std::string& context,
2034 const std::string& name, const octave_value& val)
2035{
2036 // FIXME: Can this be done without an unwind-protect frame, simply
2037 // by getting a reference to the caller or base stack frame and
2038 // calling assign on that?
2039
2040 unwind_action act ([this] (std::size_t frm)
2041 {
2042 m_call_stack.restore_frame (frm);
2043 }, m_call_stack.current_frame ());
2044
2045 if (context == "caller")
2046 m_call_stack.goto_caller_frame ();
2047 else if (context == "base")
2048 m_call_stack.goto_base_frame ();
2049 else
2050 error (R"(assignin: CONTEXT must be "caller" or "base")");
2051
2052 if (valid_identifier (name))
2053 {
2054 // Put the check here so that we don't slow down assignments
2055 // generally. Any that go through Octave's parser should have
2056 // already been checked.
2057
2058 if (iskeyword (name))
2059 error ("assignin: invalid assignment to keyword '%s'",
2060 name.c_str ());
2061
2062 assign (name, val);
2063 }
2064 else
2065 error ("assignin: invalid variable name '%s'", name.c_str ());
2066}
2067
2068void
2069tree_evaluator::source_file (const std::string& file_name,
2070 const std::string& context,
2071 bool verbose, bool require_file)
2072{
2073 // Map from absolute name of script file to recursion level. We
2074 // use a map instead of simply placing a limit on recursion in the
2075 // source_file function so that two mutually recursive scripts
2076 // written as
2077 //
2078 // foo1.m:
2079 // ------
2080 // foo2
2081 //
2082 // foo2.m:
2083 // ------
2084 // foo1
2085 //
2086 // and called with
2087 //
2088 // foo1
2089 //
2090 // (for example) will behave the same if they are written as
2091 //
2092 // foo1.m:
2093 // ------
2094 // source ("foo2.m")
2095 //
2096 // foo2.m:
2097 // ------
2098 // source ("foo1.m")
2099 //
2100 // and called with
2101 //
2102 // source ("foo1.m")
2103 //
2104 // (for example).
2105
2106 static std::map<std::string, int> source_call_depth;
2107
2108 std::string file_full_name
2109 = sys::file_ops::tilde_expand (file_name);
2110
2111 std::size_t pos
2112 = file_full_name.find_last_of (sys::file_ops::dir_sep_str ());
2113
2114 std::string dir_name = file_full_name.substr (0, pos);
2115
2116 file_full_name = sys::env::make_absolute (file_full_name);
2117
2118 unwind_protect frame;
2119
2120 if (source_call_depth.find (file_full_name) == source_call_depth.end ())
2121 source_call_depth[file_full_name] = -1;
2122
2123 frame.protect_var (source_call_depth[file_full_name]);
2124
2125 source_call_depth[file_full_name]++;
2126
2127 if (source_call_depth[file_full_name] >= max_recursion_depth ())
2128 error ("max_recursion_depth exceeded");
2129
2130 if (! context.empty ())
2131 {
2132 frame.add (&call_stack::restore_frame, &m_call_stack,
2133 m_call_stack.current_frame ());
2134
2135 if (context == "caller")
2136 m_call_stack.goto_caller_frame ();
2137 else if (context == "base")
2138 m_call_stack.goto_base_frame ();
2139 else
2140 error (R"(source: CONTEXT must be "caller" or "base")");
2141 }
2142
2143 // Find symbol name that would be in symbol_table, if it were loaded.
2144 std::size_t dir_end
2145 = file_name.find_last_of (sys::file_ops::dir_sep_chars ());
2146 dir_end = (dir_end == std::string::npos) ? 0 : dir_end + 1;
2147
2148 std::size_t extension = file_name.find_last_of ('.');
2149 if (extension == std::string::npos)
2150 extension = file_name.length ();
2151
2152 std::string symbol = file_name.substr (dir_end, extension - dir_end);
2153 std::string full_name = sys::canonicalize_file_name (file_name);
2154
2155 // Check if this file is already loaded (or in the path)
2156 symbol_table& symtab = m_interpreter.get_symbol_table ();
2157 octave_value ov_code = symtab.fcn_table_find (symbol);
2158
2159 // For compatibility with Matlab, accept both scripts and
2160 // functions.
2161
2162 if (ov_code.is_user_code ())
2163 {
2164 octave_user_code *code = ov_code.user_code_value ();
2165
2166 if (! code
2167 || (sys::canonicalize_file_name (code->fcn_file_name ())
2168 != full_name))
2169 {
2170 // Wrong file, so load it below.
2171 ov_code = octave_value ();
2172 }
2173 }
2174 else
2175 {
2176 // Not a script, so load it below.
2177 ov_code = octave_value ();
2178 }
2179
2180 // If no symbol of this name, or the symbol is for a different
2181 // file, load.
2182
2183 if (ov_code.is_undefined ())
2184 {
2185 try
2186 {
2187 ov_code = parse_fcn_file (m_interpreter, file_full_name,
2188 file_name, dir_name, "", "",
2189 require_file, true, false, false);
2190 }
2191 catch (execution_exception& ee)
2192 {
2193 std::string error_message = ee.message ();
2194 if (error_message.empty ())
2195 error (ee, "source: error sourcing file '%s'",
2196 file_full_name.c_str ());
2197 else
2198 error (ee, "%s", error_message.c_str ());
2199 }
2200 }
2201
2202 // Return or error if we don't have a valid script or function.
2203
2204 if (ov_code.is_undefined ())
2205 return;
2206
2207 if (! ov_code.is_user_code ())
2208 error ("source: %s is not a script", full_name.c_str ());
2209
2210 if (verbose)
2211 {
2212 octave_stdout << "executing commands from " << full_name << " ... ";
2213 octave_stdout.flush ();
2214 }
2215
2216 octave_user_code *code = ov_code.user_code_value ();
2217
2218 code->call (*this, 0, octave_value_list ());
2219
2220 if (verbose)
2221 {
2222 octave_stdout << "done." << std::endl;
2223 octave_stdout.flush ();
2224 }
2225}
2226
2227void
2229 const octave_value& val)
2230{
2231 m_call_stack.set_auto_fcn_var (avt, val);
2232}
2233
2234void
2236{
2237 m_call_stack.set_nargin (nargin);
2238}
2239
2240void
2242{
2243 m_call_stack.set_nargout (nargout);
2244}
2245
2248{
2249 return m_call_stack.get_auto_fcn_var (avt);
2250}
2251
2252void
2254 (tree_parameter_list *param_list, const octave_value_list& args)
2255{
2256 if (! param_list || param_list->varargs_only ())
2257 return;
2258
2259 int i = -1;
2260
2261 for (tree_decl_elt *elt : *param_list)
2262 {
2263 i++;
2264
2265 octave_lvalue ref = elt->lvalue (*this);
2266
2267 if (i < args.length ())
2268 {
2269 if (args(i).is_defined () && args(i).is_magic_colon ())
2270 {
2271 if (! eval_decl_elt (elt))
2272 error ("no default value for argument %d", i+1);
2273 }
2274 else
2275 ref.define (args(i));
2276 }
2277 else
2278 eval_decl_elt (elt);
2279 }
2280}
2281
2282void
2284{
2285 for (tree_decl_elt *elt : *param_list)
2286 {
2287 octave_lvalue ref = elt->lvalue (*this);
2288
2290 }
2291}
2292
2293DEFMETHOD (end, interp, args, ,
2294 doc: /* -*- texinfo -*-
2295@deftypefn {} {} end
2296Last element of an array or the end of any @code{for}, @code{parfor},
2297@code{if}, @code{do}, @code{while}, @code{function}, @code{switch},
2298@code{try}, or @code{unwind_protect} block.
2299
2300As an index of an array, the magic index @qcode{"end"} refers to the
2301last valid entry in an indexing operation.
2302
2303Example:
2304
2305@example
2306@group
2307@var{x} = [ 1 2 3; 4 5 6 ];
2308@var{x}(1,end)
2309 @xresult{} 3
2310@var{x}(end,1)
2311 @xresult{} 4
2312@var{x}(end,end)
2313 @xresult{} 6
2314@end group
2315@end example
2316
2317Programming notes:
2318@enumerate
2319@item
2320The @code{end} keyword cannot be used within @code{subsref},
2321@code{subsasgn}, or @code{substruct} for manual indexing operations.
2322
2323@item
2324For custom classes, to enable use of @code{end} in indexing expressions it
2325must be overloaded with a function definition such as:
2326
2327@example
2328@group
2329function last_index = end (obj, end_dim, ndim_obj)
2330  if (end_dim == ndim_obj)
2331    last_index = prod (size (obj)(end_dim:ndim_obj));
2332  else
2333    last_index = size (obj, end_dim);
2334  endif
2335endfunction
2336@end group
2337@end example
2338
2339For more information, @pxref{Object Oriented Programming}.
2340@end enumerate
2341
2342@seealso{for, parfor, if, do, while, function, switch, try, unwind_protect}
2343@end deftypefn */)
2344{
2345 tree_evaluator& tw = interp.get_evaluator ();
2346
2347 return tw.evaluate_end_expression (args);
2348}
2349
2350/*
2351%!test <*58830>
2352%! fail ("__undef_sym__ (end)",
2353%! "invalid use of 'end': may only be used to index existing value");
2354
2355%!test <*58953>
2356%! x = 1:10;
2357%! assert (x(end), 10);
2358%! assert (x(minus (end, 1)), 9);
2359%! assert (x(minus (minus (end, 1), 1)), 8);
2360*/
2361
2364{
2365 std::list<octave_value> arg_vals;
2366
2367 for (auto elt : *args)
2368 {
2369 // FIXME: is it possible for elt to be invalid?
2370
2371 if (! elt)
2372 break;
2373
2374 // Evaluate with unknown number of output arguments
2375 octave_value tmp = elt->evaluate (*this, -1);
2376
2377 if (tmp.is_cs_list ())
2378 {
2379 octave_value_list tmp_ovl = tmp.list_value ();
2380
2381 for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
2382 arg_vals.push_back (tmp_ovl(i));
2383 }
2384 else if (tmp.is_defined ())
2385 arg_vals.push_back (tmp);
2386 }
2387
2388 return octave_value_list (arg_vals);
2389}
2390
2393(tree_parameter_list *ret_list, int nargout, const Cell& varargout)
2394{
2395 octave_idx_type vlen = varargout.numel ();
2396 int len = ret_list->size ();
2397
2398 // Special case. Will do a shallow copy.
2399 if (len == 0)
2400 return varargout;
2401 else
2402 {
2403 int i = 0;
2404
2405 if (nargout <= len)
2406 {
2407 int nout = nargout > 0 ? nargout : 1;
2408 octave_value_list retval (nout);
2409
2410 for (tree_decl_elt *elt : *ret_list)
2411 {
2412 if (nargout == 0 && ! is_defined (elt->ident ()))
2413 break;
2414
2415 if (is_defined (elt->ident ()))
2416 retval(i) = evaluate (elt);
2417
2418 i++;
2419
2420 if (i == nout)
2421 break;
2422 }
2423
2424 return retval;
2425 }
2426 else
2427 {
2428 octave_value_list retval (len + vlen);
2429
2430 for (tree_decl_elt *elt : *ret_list)
2431 {
2432 if (is_defined (elt->ident ()))
2433 retval(i) = evaluate (elt);
2434
2435 i++;
2436 }
2437
2438 for (octave_idx_type j = 0; j < vlen; j++)
2439 retval(i++) = varargout(j);
2440
2441 return retval;
2442 }
2443 }
2444}
2445
2446bool
2448{
2449 bool retval = false;
2450
2451 tree_identifier *id = elt->ident ();
2452 tree_expression *expr = elt->expression ();
2453
2454 if (id && expr)
2455 {
2456 octave_lvalue ult = id->lvalue (*this);
2457
2458 octave_value init_val = expr->evaluate (*this);
2459
2460 ult.assign (octave_value::op_asn_eq, init_val);
2461
2462 retval = true;
2463 }
2464
2465 return retval;
2466}
2467
2468bool
2470 const octave_value& val)
2471{
2472 tree_expression *label = expr->case_label ();
2473
2474 octave_value label_value = label->evaluate (*this);
2475
2476 if (label_value.is_defined ())
2477 {
2478 if (label_value.iscell ())
2479 {
2480 Cell cell (label_value.cell_value ());
2481
2482 for (octave_idx_type i = 0; i < cell.rows (); i++)
2483 {
2484 for (octave_idx_type j = 0; j < cell.columns (); j++)
2485 {
2486 bool match = val.is_equal (cell(i,j));
2487
2488 if (match)
2489 return true;
2490 }
2491 }
2492 }
2493 else
2494 return val.is_equal (label_value);
2495 }
2496
2497 return false;
2498}
2499
2500void
2502{
2503 m_call_stack.push (scope);
2504}
2505
2506void
2508 const std::shared_ptr<stack_frame>& closure_frames)
2509{
2510 m_call_stack.push (fcn, closure_frames);
2511}
2512
2513void
2515 const stack_frame::local_vars_map& local_vars,
2516 const std::shared_ptr<stack_frame>& closure_frames)
2517{
2518 m_call_stack.push (fcn, local_vars, closure_frames);
2519}
2520
2521void
2523{
2524 m_call_stack.push (script);
2525}
2526
2527void
2529{
2530 m_call_stack.push (fcn);
2531}
2532
2533void
2535{
2536 m_call_stack.pop ();
2537}
2538
2539std::shared_ptr<stack_frame>
2541{
2542 return m_call_stack.pop_return ();
2543}
2544
2545int
2547{
2548 return m_call_stack.current_line ();
2549}
2550
2551int
2553{
2554 return m_call_stack.current_column ();
2555}
2556
2557int
2559{
2560 return m_call_stack.debug_user_code_line ();
2561}
2562
2563int
2565{
2566 return m_call_stack.debug_user_code_column ();
2567}
2568
2569void
2570tree_evaluator::debug_where (std::ostream& os) const
2571{
2572 std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
2573
2574 frm->display_stopped_in_message (os);
2575}
2576
2577void
2578tree_evaluator::debug_list (std::ostream& os, int num_lines) const
2579{
2580 std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
2581
2582 if (! (frm->is_user_script_frame () || frm->is_user_fcn_frame ()))
2583 error ("dblist: must be inside a user function or script to use dblist\n");
2584
2585 frm->debug_list (os, num_lines);
2586}
2587
2588void
2589tree_evaluator::debug_type (std::ostream& os, int start_line, int end_line) const
2590{
2591 std::shared_ptr<stack_frame> frm = m_call_stack.current_user_frame ();
2592
2593 if (! (frm->is_user_script_frame () || frm->is_user_fcn_frame ()))
2594 error ("dbtype: must be inside a user function or script to use dbtype\n");
2595
2596 frm->debug_type (os, start_line, end_line);
2597}
2598
2601{
2602 return m_call_stack.current_user_code ();
2603}
2604
2610
2613{
2614 return m_call_stack.debug_user_code ();
2615}
2616
2619{
2620 return m_call_stack.current_function (skip_first);
2621}
2622
2625{
2626 return m_call_stack.current_function (true);
2627}
2628
2629bool
2630tree_evaluator::goto_frame (std::size_t n, bool verbose)
2631{
2632 return m_call_stack.goto_frame (n, verbose);
2633}
2634
2635void
2637{
2638 m_call_stack.goto_caller_frame ();
2639}
2640
2641void
2643{
2644 m_call_stack.goto_base_frame ();
2645}
2646
2647void
2649{
2650 return m_call_stack.restore_frame (n);
2651}
2652
2653std::string
2655{
2656 return m_call_stack.get_dispatch_class ();
2657}
2658
2659void
2660tree_evaluator::set_dispatch_class (const std::string& class_name)
2661{
2662 m_call_stack.set_dispatch_class (class_name);
2663}
2664
2665bool
2667{
2668 return m_call_stack.is_class_method_executing (dclass);
2669}
2670
2671bool
2673{
2674 return m_call_stack.is_class_constructor_executing (dclass);
2675}
2676
2677std::list<std::shared_ptr<stack_frame>>
2679{
2680 return m_call_stack.backtrace_frames (curr_user_frame);
2681}
2682
2683std::list<std::shared_ptr<stack_frame>>
2685{
2686 return m_call_stack.backtrace_frames ();
2687}
2688
2689std::list<frame_info>
2691 bool print_subfn) const
2692{
2693 return m_call_stack.backtrace_info (curr_user_frame, print_subfn);
2694}
2695
2696std::list<frame_info>
2698{
2699 return m_call_stack.backtrace_info ();
2700}
2701
2704 bool print_subfn) const
2705{
2706 return m_call_stack.backtrace (curr_user_frame, print_subfn);
2707}
2708
2711{
2712 return m_call_stack.backtrace ();
2713}
2714
2717{
2718 return m_call_stack.empty_backtrace ();
2719}
2720
2721std::string
2723{
2724 std::list<frame_info> frames = backtrace_info ();
2725
2726 std::ostringstream buf;
2727
2728 for (const auto& frm : frames)
2729 {
2730 buf << " " << frm.fcn_name ();
2731
2732 int line = frm.line ();
2733
2734 if (line > 0)
2735 {
2736 buf << " at line " << line;
2737
2738 int column = frm.column ();
2739
2740 if (column > 0)
2741 buf << " column " << column;
2742
2743 buf << "\n";
2744 }
2745 }
2746
2747 return buf.str ();
2748}
2749
2750void
2751tree_evaluator::push_dummy_scope (const std::string& name)
2752{
2753 symbol_scope dummy_scope (name + "$dummy");
2754
2755 m_call_stack.push (dummy_scope);
2756}
2757
2758void
2760{
2761 m_call_stack.pop ();
2762}
2763
2766{
2767 return m_call_stack.top_scope ();
2768}
2769
2772{
2773 return m_call_stack.current_scope ();
2774}
2775
2776void
2777tree_evaluator::mlock (bool skip_first) const
2778{
2779 octave_function *fcn = m_call_stack.current_function (skip_first);
2780
2781 if (! fcn)
2782 error ("mlock: invalid use outside a function");
2783
2784 if (fcn->is_builtin_function ())
2785 {
2786 warning ("mlock: locking built-in function has no effect");
2787 return;
2788 }
2789
2790 fcn->lock ();
2791}
2792
2793void
2794tree_evaluator::munlock (bool skip_first) const
2795{
2796 octave_function *fcn = m_call_stack.current_function (skip_first);
2797
2798 if (! fcn)
2799 error ("munlock: invalid use outside a function");
2800
2801 if (fcn->is_builtin_function ())
2802 {
2803 warning ("munlock: unlocking built-in function has no effect");
2804 return;
2805 }
2806
2807 fcn->unlock ();
2808}
2809
2810bool
2811tree_evaluator::mislocked (bool skip_first) const
2812{
2813 octave_function *fcn = m_call_stack.current_function (skip_first);
2814
2815 if (! fcn)
2816 error ("mislocked: invalid use outside a function");
2817
2818 return fcn->islocked ();
2819}
2820
2823{
2824 return m_call_stack.max_stack_depth (args, nargout);
2825}
2826
2827void
2829{
2830 m_call_stack.display ();
2831}
2832
2834tree_evaluator::find (const std::string& name)
2835{
2836 std::shared_ptr<stack_frame> frame
2837 = m_call_stack.get_current_stack_frame ();
2838
2839 octave_value val = frame->varval (name);
2840
2841 if (val.is_defined ())
2842 return val;
2843
2844 // Subfunction. I think it only makes sense to check for
2845 // subfunctions if we are currently executing a function defined
2846 // from a .m file.
2847
2848 octave_value fcn = frame->find_subfunction (name);
2849
2850 if (fcn.is_defined ())
2851 return fcn;
2852
2853 symbol_table& symtab = m_interpreter.get_symbol_table ();
2854
2855 return symtab.fcn_table_find (name, ovl ());
2856}
2857
2858void
2860{
2861 std::shared_ptr<stack_frame> frame
2862 = m_call_stack.get_current_stack_frame ();
2863
2864 frame->clear_objects ();
2865}
2866
2867void
2868tree_evaluator::clear_variable (const std::string& name)
2869{
2870 std::shared_ptr<stack_frame> frame
2871 = m_call_stack.get_current_stack_frame ();
2872
2873 frame->clear_variable (name);
2874}
2875
2876void
2877tree_evaluator::clear_variable_pattern (const std::string& pattern)
2878{
2879 std::shared_ptr<stack_frame> frame
2880 = m_call_stack.get_current_stack_frame ();
2881
2882 frame->clear_variable_pattern (pattern);
2883}
2884
2885void
2886tree_evaluator::clear_variable_regexp (const std::string& pattern)
2887{
2888 std::shared_ptr<stack_frame> frame
2889 = m_call_stack.get_current_stack_frame ();
2890
2891 frame->clear_variable_regexp (pattern);
2892}
2893
2894void
2896{
2897 std::shared_ptr<stack_frame> frame
2898 = m_call_stack.get_current_stack_frame ();
2899
2900 frame->clear_variables ();
2901}
2902
2903void
2905{
2906 m_call_stack.clear_global_variable (name);
2907}
2908
2909void
2911{
2912 m_call_stack.clear_global_variable_pattern (pattern);
2913}
2914
2915void
2917{
2918 m_call_stack.clear_global_variable_regexp (pattern);
2919}
2920
2921void
2926
2927void
2929{
2930 // FIXME: should this also clear objects?
2931
2932 clear_variables ();
2934
2935 symbol_table& symtab = m_interpreter.get_symbol_table ();
2936
2937 symtab.clear_functions (force);
2938}
2939
2940void
2941tree_evaluator::clear_symbol (const std::string& name)
2942{
2943 // FIXME: are we supposed to do both here?
2944
2945 clear_variable (name);
2946
2947 symbol_table& symtab = m_interpreter.get_symbol_table ();
2948
2949 symtab.clear_function (name);
2950}
2951
2952void
2953tree_evaluator::clear_symbol_pattern (const std::string& pattern)
2954{
2955 // FIXME: are we supposed to do both here?
2956
2957 clear_variable_pattern (pattern);
2958
2959 symbol_table& symtab = m_interpreter.get_symbol_table ();
2960
2961 symtab.clear_function_pattern (pattern);
2962}
2963
2964void
2965tree_evaluator::clear_symbol_regexp (const std::string& pattern)
2966{
2967 // FIXME: are we supposed to do both here?
2968
2969 clear_variable_regexp (pattern);
2970
2971 symbol_table& symtab = m_interpreter.get_symbol_table ();
2972
2973 symtab.clear_function_regexp (pattern);
2974}
2975
2976std::list<std::string>
2978{
2979 return m_call_stack.global_variable_names ();
2980}
2981
2982std::list<std::string>
2984{
2985 return m_call_stack.top_level_variable_names ();
2986}
2987
2988std::list<std::string>
2990{
2991 return m_call_stack.variable_names ();
2992}
2993
2994// Return a pointer to the user-defined function FNAME. If FNAME is empty,
2995// search backward for the first user-defined function in the
2996// current call stack.
2997
2999tree_evaluator::get_user_code (const std::string& fname)
3000{
3001 octave_user_code *user_code = nullptr;
3002
3003 if (fname.empty ())
3004 user_code = m_call_stack.debug_user_code ();
3005 else
3006 {
3007 std::string name = fname;
3008
3009 if (sys::file_ops::dir_sep_char () != '/' && name[0] == '@')
3010 {
3011 auto beg = name.begin () + 2; // never have @/method
3012 auto end = name.end () - 1; // never have trailing '/'
3013 std::replace (beg, end, '/', sys::file_ops::dir_sep_char ());
3014 }
3015
3016 std::size_t name_len = name.length ();
3017
3018 if (name_len > 2 && name.substr (name_len-2) == ".m")
3019 name = name.substr (0, name_len-2);
3020
3021 if (name.empty ())
3022 return nullptr;
3023
3024 symbol_table& symtab = m_interpreter.get_symbol_table ();
3025
3026 octave_value fcn;
3027 std::size_t p2 = std::string::npos;
3028
3029 if (name[0] == '@')
3030 {
3031 std::size_t p1 = name.find (sys::file_ops::dir_sep_char (), 1);
3032
3033 if (p1 == std::string::npos)
3034 return nullptr;
3035
3036 std::string dispatch_type = name.substr (1, p1-1);
3037
3038 p2 = name.find ('>', p1);
3039
3040 std::string method = name.substr (p1+1, p2-1);
3041
3042 // first check for classdef method
3043 cdef_manager& cdm = m_interpreter.get_cdef_manager ();
3044
3045// fcn = cdm.find_method_symbol (method, dispatch_type);
3046
3047 cdef_class cls = cdm.find_class (dispatch_type, false);
3048 if (cls.ok () && cls.get_name () == dispatch_type)
3049 {
3050 if (! method.compare (0, 4, "get."))
3051 {
3052 // find get method of classdef property
3053 std::string prop_name = method.substr (4);
3054 cdef_property prop = cls.find_property (prop_name);
3055 if (prop.ok () && prop.get_name () == prop_name)
3056 {
3057 const octave_value& get_meth = prop.get ("GetMethod");
3058 if (get_meth.is_function_handle ())
3059 return get_meth.user_function_value ()->user_code_value ();
3060 else
3061 return nullptr;
3062 }
3063 }
3064 else if (! method.compare (0, 4, "set."))
3065 {
3066 // find set method of classdef property
3067 std::string prop_name = method.substr (4);
3068 cdef_property prop = cls.find_property (prop_name);
3069 if (prop.ok () && prop.get_name () == prop_name)
3070 {
3071 const octave_value& set_meth = prop.get ("SetMethod");
3072 if (set_meth.is_function_handle ())
3073 return set_meth.user_function_value ()->user_code_value ();
3074 else
3075 return nullptr;
3076 }
3077 }
3078 else
3079 {
3080 cdef_method meth = cls.find_method (method);
3081 if (meth.ok () && meth.get_name () == method)
3082 fcn = meth.get_function ();
3083 else
3084 return nullptr;
3085 }
3086 }
3087
3088 // If there is no classdef method, then try legacy classes.
3089 if (fcn.is_undefined ())
3090 fcn = symtab.find_method (method, dispatch_type);
3091 }
3092 else
3093 {
3094 p2 = name.find ('>');
3095
3096 std::string main_fcn = name.substr (0, p2);
3097
3098 fcn = symtab.find_function (main_fcn);
3099 }
3100
3101 // List of function names sub1>sub2>...
3102 std::string subfuns;
3103
3104 if (p2 != std::string::npos)
3105 subfuns = name.substr (p2+1);
3106
3107 if (fcn.is_defined () && fcn.is_user_code ())
3108 user_code = fcn.user_code_value ();
3109
3110 if (! user_code || subfuns.empty ())
3111 return user_code;
3112
3113 fcn = user_code->find_subfunction (subfuns);
3114
3115 if (fcn.is_undefined ())
3116 return nullptr;
3117
3118 user_code = fcn.user_code_value ();
3119 }
3120
3121 return user_code;
3122}
3123
3124std::string
3126{
3127 octave_function *curfcn = m_call_stack.current_function (skip_first);
3128
3129 if (curfcn)
3130 return curfcn->name ();
3131
3132 return "";
3133}
3134
3135bool
3137{
3138 return m_call_stack.current_user_code () != nullptr;
3139}
3140
3141void
3143{
3144 if (m_echo_state)
3145 {
3146 int line = cmd.line ();
3147 if (line < 0)
3148 line = 1;
3149 echo_code (line);
3150 m_echo_file_pos = line + 1;
3151 }
3152
3153 if (m_debug_mode)
3154 do_breakpoint (cmd.is_active_breakpoint (*this));
3155
3156 // FIXME: tree_decl_init_list is not derived from tree, so should it
3157 // really have an accept method?
3158
3159 tree_decl_init_list *init_list = cmd.initializer_list ();
3160
3161 if (init_list)
3162 init_list->accept (*this);
3163}
3164
3165void
3167{
3168 tree_identifier *id = elt.ident ();
3169
3170 if (id)
3171 {
3172 if (elt.is_global ())
3173 m_call_stack.make_global (id->symbol ());
3174 else if (elt.is_persistent ())
3175 m_call_stack.make_persistent (id->symbol ());
3176 else
3177 error ("declaration list element not global or persistent");
3178
3179 octave_lvalue ult = id->lvalue (*this);
3180
3181 if (ult.is_undefined ())
3182 {
3183 tree_expression *expr = elt.expression ();
3184
3185 octave_value init_val;
3186
3187 if (expr)
3188 init_val = expr->evaluate (*this);
3189 else
3190 init_val = Matrix ();
3191
3192 ult.assign (octave_value::op_asn_eq, init_val);
3193 }
3194 }
3195}
3196
3197template <typename T>
3198void
3199tree_evaluator::execute_range_loop (const range<T>& rng, int line,
3200 octave_lvalue& ult,
3201 tree_statement_list *loop_body)
3202{
3203 octave_idx_type steps = rng.numel ();
3204
3205 if (math::isinf (rng.limit ()) || math::isinf (rng.base ()))
3206 warning_with_id ("Octave:infinite-loop",
3207 "FOR loop limit is infinite, will stop after %"
3208 OCTAVE_IDX_TYPE_FORMAT " steps", steps);
3209
3210 for (octave_idx_type i = 0; i < steps; i++)
3211 {
3212 if (m_echo_state)
3213 m_echo_file_pos = line;
3214
3215 octave_value val (rng.elem (i));
3216
3218
3219 if (loop_body)
3220 loop_body->accept (*this);
3221
3222 if (quit_loop_now ())
3223 break;
3224 }
3225}
3226
3227void
3229{
3230 int line = cmd.line ();
3231 if (line < 0)
3232 line = 1;
3233
3234 if (m_echo_state)
3235 {
3236 echo_code (line);
3237 line++;
3238 }
3239
3240 if (m_debug_mode)
3241 do_breakpoint (cmd.is_active_breakpoint (*this));
3242
3243 // FIXME: need to handle PARFOR loops here using cmd.in_parallel ()
3244 // and cmd.maxproc_expr ();
3245
3246 unwind_protect_var<bool> upv (m_in_loop_command, true);
3247
3248 tree_expression *expr = cmd.control_expr ();
3249
3250 octave_value rhs = expr->evaluate (*this);
3251
3252 if (rhs.is_undefined ())
3253 return;
3254
3255 tree_expression *lhs = cmd.left_hand_side ();
3256
3257 octave_lvalue ult = lhs->lvalue (*this);
3258
3259 tree_statement_list *loop_body = cmd.body ();
3260
3261 if (rhs.is_range ())
3262 {
3263 // FIXME: is there a better way to dispatch here?
3264
3265 if (rhs.is_double_type ())
3266 {
3267 execute_range_loop (rhs.range_value (), line, ult, loop_body);
3268 return;
3269 }
3270
3271 // For now, enable only range<double>.
3272 }
3273
3274 if (rhs.is_scalar_type ())
3275 {
3276 if (m_echo_state)
3277 m_echo_file_pos = line;
3278
3280
3281 if (loop_body)
3282 loop_body->accept (*this);
3283
3284 // Maybe decrement break and continue states.
3285 quit_loop_now ();
3286
3287 return;
3288 }
3289
3290 // Also handle any range types not explicitly handled above, though
3291 // not as efficiently as the specialized code above.
3292
3293 if (rhs.is_range () || rhs.is_matrix_type () || rhs.iscell ()
3294 || rhs.is_string () || rhs.isstruct ())
3295 {
3296 // A matrix or cell is reshaped to 2 dimensions and iterated by
3297 // columns.
3298
3299 const dim_vector& dv = rhs.dims ().redim (2);
3300
3301 octave_idx_type nrows = dv(0);
3302 octave_idx_type steps = dv(1);
3303
3304 octave_value arg = rhs;
3305 if (rhs.ndims () > 2)
3306 arg = arg.reshape (dv);
3307
3308 if (steps > 0)
3309 {
3311 octave_idx_type iidx;
3312
3313 // for row vectors, use single index to speed things up.
3314 if (nrows == 1)
3315 {
3316 idx.resize (1);
3317 iidx = 0;
3318 }
3319 else
3320 {
3321 idx.resize (2);
3323 iidx = 1;
3324 }
3325
3326 for (octave_idx_type i = 1; i <= steps; i++)
3327 {
3328 if (m_echo_state)
3329 m_echo_file_pos = line;
3330
3331 // index_op expects one-based indices.
3332 idx(iidx) = i;
3333 octave_value val = arg.index_op (idx);
3334
3336
3337 if (loop_body)
3338 loop_body->accept (*this);
3339
3340 if (quit_loop_now ())
3341 break;
3342 }
3343 }
3344 else
3345 {
3346 // Handle empty cases, while still assigning to loop var.
3348 }
3349
3350 return;
3351 }
3352
3353 error ("invalid type in for loop expression near line %d, column %d",
3354 cmd.line (), cmd.column ());
3355}
3356
3357void
3359{
3360 int line = cmd.line ();
3361 if (line < 0)
3362 line = 1;
3363
3364 if (m_echo_state)
3365 {
3366 echo_code (line);
3367 line++;
3368 }
3369
3370 if (m_debug_mode)
3371 do_breakpoint (cmd.is_active_breakpoint (*this));
3372
3373 unwind_protect_var<bool> upv (m_in_loop_command, true);
3374
3375 tree_expression *expr = cmd.control_expr ();
3376
3377 octave_value rhs = expr->evaluate (*this);
3378
3379 if (rhs.is_undefined ())
3380 return;
3381
3382 if (! rhs.isstruct ())
3383 error ("in statement 'for [X, Y] = VAL', VAL must be a structure");
3384
3385 // Cycle through structure elements. First element of id_list
3386 // is set to value and the second is set to the name of the
3387 // structure element.
3388
3389 tree_argument_list *lhs = cmd.left_hand_side ();
3390
3391 auto p = lhs->begin ();
3392
3393 tree_expression *elt = *p++;
3394
3395 octave_lvalue val_ref = elt->lvalue (*this);
3396
3397 elt = *p;
3398
3399 octave_lvalue key_ref = elt->lvalue (*this);
3400
3401 const octave_map tmp_val = rhs.map_value ();
3402
3403 tree_statement_list *loop_body = cmd.body ();
3404
3405 string_vector keys = tmp_val.keys ();
3406
3407 octave_idx_type nel = keys.numel ();
3408
3409 for (octave_idx_type i = 0; i < nel; i++)
3410 {
3411 if (m_echo_state)
3412 m_echo_file_pos = line;
3413
3414 std::string key = keys[i];
3415
3416 const Cell val_lst = tmp_val.contents (key);
3417
3418 octave_idx_type n = val_lst.numel ();
3419
3420 octave_value val = (n == 1) ? val_lst(0) : octave_value (val_lst);
3421
3422 val_ref.assign (octave_value::op_asn_eq, val);
3423 key_ref.assign (octave_value::op_asn_eq, key);
3424
3425 if (loop_body)
3426 loop_body->accept (*this);
3427
3428 if (quit_loop_now ())
3429 break;
3430 }
3431}
3432
3433void
3435{
3436 // For now, we just execute the commands serially.
3437
3438 tree_statement_list *body = cmd.body ();
3439
3440 if (body)
3441 body->accept (*this);
3442}
3443
3446{
3447 // FIXME: should CMD_LIST be limited to a single expression?
3448 // I think that is what Matlab does.
3449
3450 symbol_scope scope = afh.scope ();
3451 symbol_scope new_scope = scope ? scope.dup () : symbol_scope::invalid ();
3452
3453 tree_parameter_list *param_list = afh.parameter_list ();
3454 tree_parameter_list *param_list_dup
3455 = param_list ? param_list->dup (new_scope) : nullptr;
3456
3457 tree_parameter_list *ret_list = nullptr;
3458
3459 tree_statement_list *stmt_list = nullptr;
3460
3461 symbol_scope parent_scope = get_current_scope ();
3462
3463 new_scope.set_parent (parent_scope);
3464 new_scope.set_primary_parent (parent_scope);
3465
3466 tree_expression *expr = afh.expression ();
3467 if (expr)
3468 {
3469 tree_expression *expr_dup = expr->dup (new_scope);
3470 tree_statement *stmt = new tree_statement (expr_dup);
3471 stmt_list = new tree_statement_list (stmt);
3472 }
3473
3474 tree_anon_scopes anon_fcn_ctx (afh);
3475
3476 std::set<std::string> free_vars = anon_fcn_ctx.free_variables ();
3477
3478 stack_frame::local_vars_map local_vars;
3479
3480 std::shared_ptr<stack_frame> frame
3481 = m_call_stack.get_current_stack_frame ();
3482
3483 for (auto& name : free_vars)
3484 {
3485 octave_value val = frame->varval (name);
3486
3487 if (val.is_defined ())
3488 local_vars[name] = val;
3489 }
3490
3491 octave_user_function *af = new octave_user_function (new_scope, nullptr, param_list_dup, ret_list, stmt_list);
3492
3493 octave_function *curr_fcn = m_call_stack.current_function ();
3494
3495 bool is_nested = false;
3496
3497 if (curr_fcn)
3498 {
3499 // FIXME: maybe it would be better to just stash curr_fcn
3500 // instead of individual bits of info about it?
3501
3502 // An anonymous function defined inside another nested function
3503 // or parent of a nested function also behaves like a nested
3504 // function.
3505
3506 if (curr_fcn->is_parent_function () || curr_fcn->is_nested_function ())
3507 {
3508 is_nested = true;
3510 new_scope.set_nesting_depth (parent_scope.nesting_depth () + 1);
3511 }
3512
3513 af->stash_dir_name (curr_fcn->dir_name ());
3514
3515 new_scope.cache_fcn_file_name (curr_fcn->fcn_file_name ());
3516 new_scope.cache_dir_name (curr_fcn->dir_name ());
3517
3518 // The following is needed so that class method dispatch works
3519 // properly for anonymous functions that wrap class methods.
3520
3521 if (curr_fcn->is_class_method () || curr_fcn->is_class_constructor ())
3522 af->stash_dispatch_class (curr_fcn->dispatch_class ());
3523
3524 af->stash_fcn_file_name (curr_fcn->fcn_file_name ());
3525 }
3526
3528
3529 octave_value ov_fcn (af);
3530
3531 return (is_nested
3532 ? octave_value (new octave_fcn_handle (ov_fcn, local_vars, frame))
3533 : octave_value (new octave_fcn_handle (ov_fcn, local_vars)));
3534}
3535
3538 int nargout,
3539 const octave_value_list& args)
3540{
3541 octave_value_list retval;
3542
3543 if (args.has_magic_colon ())
3544 error ("invalid use of colon in function argument list");
3545
3546 profiler::enter<octave_builtin> block (m_profiler, builtin_function);
3547
3548 octave_builtin::fcn fcn = builtin_function.function ();
3549
3550 // If number of outputs unknown (and this is not a complete statement),
3551 // pass nargout=1 to the function being called
3552 if (nargout < 0)
3553 nargout = 1;
3554
3555 if (fcn)
3556 retval = (*fcn) (args, nargout);
3557 else
3558 {
3559 octave_builtin::meth meth = builtin_function.method ();
3560
3561 retval = (*meth) (m_interpreter, args, nargout);
3562 }
3563
3564 // Do not allow null values to be returned from functions.
3565 // FIXME: perhaps true builtins should be allowed?
3566
3567 retval.make_storable_values ();
3568
3569 // Fix the case of a single undefined value.
3570 // This happens when a compiled function uses
3571 //
3572 // octave_value retval;
3573 //
3574 // instead of
3575 //
3576 // octave_value_list retval;
3577 //
3578 // the idiom is very common, so we solve that here.
3579
3580 if (retval.length () == 1 && retval.xelem (0).is_undefined ())
3581 retval.clear ();
3582
3583 return retval;
3584}
3585
3588 int nargout,
3589 const octave_value_list& args)
3590{
3591 octave_value_list retval;
3592
3593 if (args.has_magic_colon ())
3594 error ("invalid use of colon in function argument list");
3595
3596 profiler::enter<octave_mex_function> block (m_profiler, mex_function);
3597
3598 // If number of outputs unknown (and this is not a complete statement),
3599 // pass nargout=1 to the function being called
3600 if (nargout < 0)
3601 nargout = 1;
3602
3603 retval = call_mex (mex_function, args, nargout);
3604
3605 return retval;
3606}
3607
3610 int nargout,
3611 const octave_value_list& args)
3612{
3613 octave_value_list retval;
3614
3615 std::string file_name = user_script.fcn_file_name ();
3616
3617 if (args.length () != 0 || nargout != 0)
3618 error ("invalid call to script %s", file_name.c_str ());
3619
3620 tree_statement_list *cmd_list = user_script.body ();
3621
3622 if (! cmd_list)
3623 return retval;
3624
3625 // FIXME: Maybe this check belongs in the places where we push a new
3626 // stack frame? Or in the call_stack push method itself?
3627
3628 if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
3629 error ("max_recursion_depth exceeded");
3630
3631 unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_SCRIPT);
3632
3633 profiler::enter<octave_user_script> block (m_profiler, user_script);
3634
3635 if (echo ())
3637
3638 // FIXME: Should we be using tree_evaluator::eval here?
3639
3640 cmd_list->accept (*this);
3641
3642 if (m_returning)
3643 m_returning = 0;
3644
3645 if (m_breaking)
3646 m_breaking--;
3647
3648 return retval;
3649}
3650
3651void
3653{
3654 // ??
3655 error_unexpected ("tree_evaluator::visit_octave_user_script");
3656}
3657
3660 int nargout,
3661 const octave_value_list& xargs)
3662{
3663 octave_value_list retval;
3664
3665 // If this function is a classdef constructor, extract the first input
3666 // argument, which must be the partially constructed object instance.
3667
3668 octave_value_list args (xargs);
3669
3670 // FIXME: this probably shouldn't be a double-precision matrix.
3671 Matrix ignored_outputs = ignored_fcn_outputs ();
3672
3673 unwind_protect frame;
3674
3675 if (! user_function.is_anonymous_function ())
3676 {
3677 frame.protect_var (m_lvalue_list);
3678 m_lvalue_list = nullptr;
3679 }
3680
3681 octave_value_list ret_args;
3682
3683 int nargin = args.length ();
3684
3685 // If number of outputs unknown (and this is not a complete statement),
3686 // pass nargout=1 to the function being called
3687 if (nargout < 0)
3688 nargout = 1;
3689
3690 if (user_function.is_classdef_constructor ())
3691 {
3692 if (nargin > 0)
3693 {
3694 ret_args = args.slice (0, 1, true);
3695 --nargin;
3696 args = args.slice (1, nargin, true);
3697 }
3698 else
3699 error ("invalid call to classdef constructor in tree_evaluator::execute_user_function - please report this bug");
3700 }
3701
3702 tree_parameter_list *param_list = user_function.parameter_list ();
3703
3704 bool takes_varargs = false;
3705 int max_inputs = 0;
3706
3707 if (param_list)
3708 {
3709 takes_varargs = param_list->takes_varargs ();
3710 max_inputs = param_list->size ();
3711 }
3712
3713 if (! takes_varargs && nargin > max_inputs)
3714 {
3715 std::string name = user_function.name ();
3716
3717 if (name.empty ())
3718 name = "@<anonymous>";
3719
3720 error_with_id ("Octave:invalid-fun-call",
3721 "%s: function called with too many inputs",
3722 name.c_str ());
3723 }
3724
3725 define_parameter_list_from_arg_vector (param_list, args);
3726
3727 tree_parameter_list *ret_list = user_function.return_list ();
3728
3729 if (ret_list && ! ret_list->takes_varargs ())
3730 {
3731 int max_outputs = ret_list->size ();
3732
3733 if (nargout > max_outputs)
3734 {
3735 std::string name = user_function.name ();
3736
3737 error_with_id ("Octave:invalid-fun-call",
3738 "%s: function called with too many outputs",
3739 name.c_str ());
3740 }
3741 }
3742
3743 bind_auto_fcn_vars (xargs.name_tags (), ignored_outputs, nargin,
3744 nargout, user_function.takes_varargs (),
3745 user_function.all_va_args (args));
3746
3747 // For classdef constructor, pre-populate the output arguments
3748 // with the pre-initialized object instance, extracted above.
3749
3750 if (user_function.is_classdef_constructor ())
3751 {
3752 if (! ret_list)
3753 error ("%s: invalid classdef constructor, no output argument defined",
3754 user_function.dispatch_class ().c_str ());
3755
3756 define_parameter_list_from_arg_vector (ret_list, ret_args);
3757 }
3758
3759 // FIXME: Maybe this check belongs in the places where we push a
3760 // new stack frame? Or in the call_stack push method itself?
3761
3762 if (m_call_stack.size () >= static_cast<std::size_t> (m_max_recursion_depth))
3763 error ("max_recursion_depth exceeded");
3764
3765 unwind_action act2 ([&user_function] () {
3766 user_function.restore_warning_states ();
3767 });
3768
3769 // Evaluate the commands that make up the function.
3770
3771 unwind_protect_var<stmt_list_type> upv (m_statement_context, SC_FUNCTION);
3772
3773 tree_statement_list *cmd_list = user_function.body ();
3774
3775 if (cmd_list)
3776 {
3778 block (m_profiler, user_function);
3779
3780 if (echo ())
3782 user_function.fcn_file_name ());
3783
3784 if (user_function.is_special_expr ())
3785 {
3786 panic_if (cmd_list->size () != 1);
3787
3788 tree_statement *stmt = cmd_list->front ();
3789
3790 tree_expression *expr = stmt->expression ();
3791
3792 if (expr)
3793 {
3794 m_call_stack.set_location (stmt->line (), stmt->column ());
3795
3796 retval = expr->evaluate_n (*this, nargout);
3797
3798 // Don't allow a comma-separated list to escape (see bug #64783).
3799
3800 if (nargout <= 1 && retval.length () == 1 && retval(0).is_cs_list ())
3801 retval = retval(0).list_value ();
3802 }
3803 }
3804 else
3805 cmd_list->accept (*this);
3806
3807 if (m_returning)
3808 m_returning = 0;
3809
3810 if (m_breaking)
3811 m_breaking--;
3812 }
3813
3814 // Copy return values out.
3815
3816 if (ret_list && ! user_function.is_special_expr ())
3817 {
3818 Cell varargout;
3819
3820 if (ret_list->takes_varargs ())
3821 {
3822 octave_value varargout_varval = varval ("varargout");
3823
3824 if (varargout_varval.is_defined ())
3825 varargout = varargout_varval.xcell_value ("varargout must be a cell array object");
3826 }
3827
3828 retval = convert_return_list_to_const_vector (ret_list, nargout, varargout);
3829 }
3830
3831 return retval;
3832}
3833
3834void
3836{
3837 // ??
3838 error_unexpected ("tree_evaluator::visit_octave_user_function");
3839}
3840
3841void
3843{
3844 error_unexpected ("tree_evaluator::visit_octave_user_function_header");
3845}
3846
3847void
3849{
3850 error_unexpected ("tree_evaluator::visit_octave_user_function_trailer");
3851}
3852
3853void
3855{
3856 octave_value fcn = cmd.function ();
3857
3859
3860 if (f)
3861 {
3862 std::string nm = f->name ();
3863
3864 symbol_table& symtab = m_interpreter.get_symbol_table ();
3865
3866 symtab.install_cmdline_function (nm, fcn);
3867
3868 // Make sure that any variable with the same name as the new
3869 // function is cleared.
3870
3871 assign (nm);
3872 }
3873}
3874
3875void
3877{
3878 error_unexpected ("tree_evaluator::visit_identifier");
3879}
3880
3881void
3883{
3884 error_unexpected ("tree_evaluator::visit_if_clause");
3885}
3886
3887void
3889{
3890 if (m_echo_state)
3891 {
3892 int line = cmd.line ();
3893 if (line < 0)
3894 line = 1;
3895 echo_code (line);
3896 m_echo_file_pos = line + 1;
3897 }
3898
3899 // FIXME: tree_if_command_list is not derived from tree, so should it
3900 // really have an accept method?
3901
3902 tree_if_command_list *lst = cmd.cmd_list ();
3903
3904 if (lst)
3905 lst->accept (*this);
3906}
3907
3908void
3910{
3911 for (tree_if_clause *tic : lst)
3912 {
3913 tree_expression *expr = tic->condition ();
3914
3915 if (! (in_debug_repl ()
3916 && m_call_stack.current_frame () == m_debug_frame))
3917 m_call_stack.set_location (tic->line (), tic->column ());
3918
3919 if (m_debug_mode && ! tic->is_else_clause ())
3920 do_breakpoint (tic->is_active_breakpoint (*this));
3921
3922 if (tic->is_else_clause () || is_logically_true (expr, "if"))
3923 {
3924 tree_statement_list *stmt_lst = tic->commands ();
3925
3926 if (stmt_lst)
3927 stmt_lst->accept (*this);
3928
3929 break;
3930 }
3931 }
3932}
3933
3934void
3936{
3937 error_unexpected ("tree_evaluator::visit_index_expression");
3938}
3939
3940void
3942{
3943 error_unexpected ("tree_evaluator::visit_matrix");
3944}
3945
3946void
3948{
3949 error_unexpected ("tree_evaluator::visit_cell");
3950}
3951
3952void
3954{
3955 error_unexpected ("tree_evaluator::visit_multi_assignment");
3956}
3957
3958void
3960{
3961 if (m_echo_state)
3962 {
3963 int line = cmd.line ();
3964 if (line < 0)
3965 line = 1;
3966 echo_code (line);
3967 m_echo_file_pos = line + 1;
3968 }
3969
3970 if (m_debug_mode && cmd.is_end_of_fcn_or_script ())
3971 do_breakpoint (cmd.is_active_breakpoint (*this), true);
3972}
3973
3974void
3976{
3977 error_unexpected ("tree_evaluator::visit_constant");
3978}
3979
3980void
3982{
3983 error_unexpected ("tree_evaluator::visit_fcn_handle");
3984}
3985
3986void
3988{
3989 error_unexpected ("tree_evaluator::visit_parameter_list");
3990}
3991
3992void
3994{
3995 error_unexpected ("tree_evaluator::visit_postfix_expression");
3996}
3997
3998void
4000{
4001 error_unexpected ("tree_evaluator::visit_prefix_expression");
4002}
4003
4004void
4006{
4007 if (m_echo_state)
4008 {
4009 int line = cmd.line ();
4010 if (line < 0)
4011 line = 1;
4012 echo_code (line);
4013 m_echo_file_pos = line + 1;
4014 }
4015
4016 if (m_debug_mode)
4017 do_breakpoint (cmd.is_active_breakpoint (*this));
4018
4019 // Act like dbcont.
4020
4021 if (in_debug_repl () && m_call_stack.current_frame () == m_debug_frame)
4022 dbcont ();
4023 else if (m_statement_context == SC_FUNCTION
4024 || m_statement_context == SC_SCRIPT
4025 || m_in_loop_command)
4026 m_returning = 1;
4027}
4028
4029void
4031{
4032 error_unexpected ("tree_evaluator::visit_simple_assignment");
4033}
4034
4035void
4037{
4038 tree_command *cmd = stmt.command ();
4039 tree_expression *expr = stmt.expression ();
4040
4041 if (cmd || expr)
4042 {
4043 if (! (in_debug_repl ()
4044 && m_call_stack.current_frame () == m_debug_frame))
4045 m_call_stack.set_location (stmt.line (), stmt.column ());
4046
4047 try
4048 {
4049 if (cmd)
4050 {
4052 upv (m_lvalue_list, nullptr);
4053
4054 cmd->accept (*this);
4055 }
4056 else
4057 {
4058 if (m_echo_state)
4059 {
4060 int line = stmt.line ();
4061 if (line < 0)
4062 line = 1;
4063 echo_code (line);
4064 m_echo_file_pos = line + 1;
4065 }
4066
4067 if (m_debug_mode)
4068 do_breakpoint (expr->is_active_breakpoint (*this));
4069
4070 // FIXME: maybe all of this should be packaged in
4071 // one virtual function that returns a flag saying whether
4072 // or not the expression will take care of binding ans and
4073 // printing the result.
4074
4075 // FIXME: it seems that we should just have to
4076 // evaluate the expression and that should take care of
4077 // everything, binding ans as necessary?
4078
4079 octave_value tmp_result = expr->evaluate (*this, 0);
4080
4081 if (tmp_result.is_defined ())
4082 {
4083 bool do_bind_ans = false;
4084
4085 if (expr->is_identifier ())
4086 do_bind_ans = ! is_variable (expr);
4087 else
4088 do_bind_ans = ! expr->is_assignment_expression ();
4089
4090 if (do_bind_ans)
4091 bind_ans (tmp_result, expr->print_result ()
4093 }
4094 }
4095 }
4096 catch (const std::bad_alloc&)
4097 {
4098 // FIXME: We want to use error_with_id here so that give users
4099 // control over this error message but error_with_id will
4100 // require some memory allocations. Is there anything we can
4101 // do to make those more likely to succeed?
4102
4103 error_with_id ("Octave:bad-alloc",
4104 "out of memory or dimension too large for Octave's index type");
4105 }
4106 catch (const interrupt_exception&)
4107 {
4108 // If we are debugging, then continue with next statement.
4109 // Otherwise, jump out of here.
4110
4111 if (m_debug_mode)
4112 m_interpreter.recover_from_exception ();
4113 else
4114 throw;
4115 }
4116 catch (const execution_exception& ee)
4117 {
4118 error_system& es = m_interpreter.get_error_system ();
4119
4120 if ((m_interpreter.interactive ()
4122 && ((es.debug_on_error ()
4123 && m_bp_table.debug_on_err (es.last_error_id ()))
4124 || (es.debug_on_caught ()
4125 && m_bp_table.debug_on_caught (es.last_error_id ())))
4126 && in_user_code ())
4127 {
4128 es.save_exception (ee);
4129 es.display_exception (ee);
4130
4131 enter_debugger ();
4132
4133 // It doesn't make sense to continue execution after an
4134 // error occurs so force the debugger to quit all debug
4135 // levels and return the the top prompt.
4136
4137 throw quit_debug_exception (true);
4138 }
4139 else
4140 throw;
4141 }
4142 }
4143}
4144
4145void
4147{
4148 // FIXME: commented out along with else clause below.
4149 // static octave_value_list empty_list;
4150
4151 auto p = lst.begin ();
4152
4153 if (p != lst.end ())
4154 {
4155 while (true)
4156 {
4157 tree_statement *elt = *p++;
4158
4159 if (! elt)
4160 error ("invalid statement found in statement list!");
4161
4162 octave_quit ();
4163
4164 elt->accept (*this);
4165
4166 if (m_breaking || m_continuing)
4167 break;
4168
4169 if (m_returning)
4170 break;
4171
4172 if (p == lst.end ())
4173 break;
4174 else
4175 {
4176 // Clear previous values before next statement is
4177 // evaluated so that we aren't holding an extra
4178 // reference to a value that may be used next. For
4179 // example, in code like this:
4180 //
4181 // X = rand (N); # refcount for X should be 1
4182 // # after this statement
4183 //
4184 // X(idx) = val; # no extra copy of X should be
4185 // # needed, but we will be faked
4186 // # out if retval is not cleared
4187 // # between statements here
4188
4189 // result_values = empty_list;
4190 }
4191 }
4192 }
4193}
4194
4195void
4197{
4198 error_unexpected ("tree_evaluator::visit_switch_case");
4199}
4200
4201void
4203{
4204 error_unexpected ("tree_evaluator::visit_switch_case_list");
4205}
4206
4207void
4209{
4210 if (m_echo_state)
4211 {
4212 int line = cmd.line ();
4213 if (line < 0)
4214 line = 1;
4215 echo_code (line);
4216 m_echo_file_pos = line + 1;
4217 }
4218
4219 if (m_debug_mode)
4220 do_breakpoint (cmd.is_active_breakpoint (*this));
4221
4222 tree_expression *expr = cmd.switch_value ();
4223
4224 if (! expr)
4225 error ("missing value in switch command near line %d, column %d",
4226 cmd.line (), cmd.column ());
4227
4228 octave_value val = expr->evaluate (*this);
4229
4230 tree_switch_case_list *lst = cmd.case_list ();
4231
4232 if (lst)
4233 {
4234 for (tree_switch_case *t : *lst)
4235 {
4236 if (t->is_default_case () || switch_case_label_matches (t, val))
4237 {
4238 tree_statement_list *stmt_lst = t->commands ();
4239
4240 if (stmt_lst)
4241 stmt_lst->accept (*this);
4242
4243 break;
4244 }
4245 }
4246 }
4247}
4248
4249void
4251{
4252 if (m_echo_state)
4253 {
4254 int line = cmd.line ();
4255 if (line < 0)
4256 line = 1;
4257 echo_code (line);
4258 m_echo_file_pos = line + 1;
4259 }
4260
4261 bool execution_error = false;
4262 octave_scalar_map err_map;
4263
4264 tree_statement_list *try_code = cmd.body ();
4265
4266 if (try_code)
4267 {
4268 // unwind frame before catch block
4269
4270 unwind_protect frame;
4271
4272 interpreter_try (frame);
4273
4274 // The catch code is *not* added to unwind_protect stack; it
4275 // doesn't need to be run on interrupts.
4276
4277 try
4278 {
4279 try_code->accept (*this);
4280 }
4281 catch (const execution_exception& ee)
4282 {
4283 execution_error = true;
4284
4285 error_system& es = m_interpreter.get_error_system ();
4286
4287 es.save_exception (ee);
4288
4289 err_map.assign ("message", es.last_error_message ());
4290 err_map.assign ("identifier", es.last_error_id ());
4291 err_map.assign ("stack", es.last_error_stack ());
4292
4293 m_interpreter.recover_from_exception ();
4294 }
4295
4296 // Actions attached to unwind_protect frame will run here, prior
4297 // to executing the catch block.
4298 }
4299
4300 if (execution_error)
4301 {
4302 tree_statement_list *catch_code = cmd.cleanup ();
4303
4304 if (catch_code)
4305 {
4306 tree_identifier *expr_id = cmd.identifier ();
4307
4308 if (expr_id)
4309 {
4310 octave_lvalue ult = expr_id->lvalue (*this);
4311
4312 ult.assign (octave_value::op_asn_eq, err_map);
4313 }
4314
4315 // perform actual "catch" block
4316 catch_code->accept (*this);
4317 }
4318 }
4319}
4320
4321void
4323{
4324 unwind_protect frame;
4325
4328
4329 // We want to preserve the last location info for possible
4330 // backtracking.
4331
4332 frame.add (&call_stack::set_line, &m_call_stack,
4333 m_call_stack.current_line ());
4334
4335 frame.add (&call_stack::set_column, &m_call_stack,
4336 m_call_stack.current_column ());
4337
4338 // Similarly, if we have seen a return or break statement, allow all
4339 // the cleanup code to run before returning or handling the break.
4340 // We don't have to worry about continue statements because they can
4341 // only occur in loops.
4342
4343 frame.protect_var (m_returning);
4344 m_returning = 0;
4345
4346 frame.protect_var (m_breaking);
4347 m_breaking = 0;
4348
4349 try
4350 {
4351 if (list)
4352 list->accept (*this);
4353 }
4354 catch (const execution_exception& ee)
4355 {
4356 error_system& es = m_interpreter.get_error_system ();
4357
4358 es.save_exception (ee);
4359 m_interpreter.recover_from_exception ();
4360
4361 if (m_breaking || m_returning)
4362 frame.discard (2);
4363 else
4364 frame.run (2);
4365
4366 frame.discard (2);
4367
4368 throw;
4369 }
4370
4371 // The unwind_protects are popped off the stack in the reverse of
4372 // the order they are pushed on.
4373
4374 // FIXME: these statements say that if we see a break or
4375 // return statement in the cleanup block, that we want to use the
4376 // new value of the breaking or returning flag instead of restoring
4377 // the previous value. Is that the right thing to do? I think so.
4378 // Consider the case of
4379 //
4380 // function foo ()
4381 // unwind_protect
4382 // fprintf (stderr, "1: this should always be executed\n");
4383 // break;
4384 // fprintf (stderr, "1: this should never be executed\n");
4385 // unwind_protect_cleanup
4386 // fprintf (stderr, "2: this should always be executed\n");
4387 // return;
4388 // fprintf (stderr, "2: this should never be executed\n");
4389 // end_unwind_protect
4390 // endfunction
4391 //
4392 // If we reset the value of the breaking flag, both the returning
4393 // flag and the breaking flag will be set, and we shouldn't have
4394 // both. So, use the most recent one. If there is no return or
4395 // break in the cleanup block, the values should be reset to
4396 // whatever they were when the cleanup block was entered.
4397
4398 if (m_breaking || m_returning)
4399 frame.discard (2);
4400 else
4401 frame.run (2);
4402}
4403
4404void
4406{
4407 if (m_echo_state)
4408 {
4409 int line = cmd.line ();
4410 if (line < 0)
4411 line = 1;
4412 echo_code (line);
4413 m_echo_file_pos = line + 1;
4414 }
4415
4416 tree_statement_list *cleanup_code = cmd.cleanup ();
4417
4418 tree_statement_list *unwind_protect_code = cmd.body ();
4419
4420 if (unwind_protect_code)
4421 {
4422 try
4423 {
4424 unwind_protect_code->accept (*this);
4425 }
4426 catch (const execution_exception& ee)
4427 {
4428 error_system& es = m_interpreter.get_error_system ();
4429
4430 // FIXME: Maybe we should be able to temporarily set the
4431 // interpreter's exception handling state to something "safe"
4432 // while the cleanup block runs instead of just resetting it
4433 // here?
4434 es.save_exception (ee);
4435 m_interpreter.recover_from_exception ();
4436
4437 // Run the cleanup code on exceptions, so that it is run even
4438 // in case of interrupt or out-of-memory.
4439 do_unwind_protect_cleanup_code (cleanup_code);
4440
4441 // If an error occurs inside the cleanup code, a new
4442 // exception will be thrown instead of the original.
4443 throw;
4444 }
4445 catch (const interrupt_exception&)
4446 {
4447 // The comments above apply here as well.
4448 m_interpreter.recover_from_exception ();
4449 do_unwind_protect_cleanup_code (cleanup_code);
4450 throw;
4451 }
4452
4453 // Also execute the unwind_protect_cleanump code if the
4454 // unwind_protect block runs without error.
4455 do_unwind_protect_cleanup_code (cleanup_code);
4456 }
4457}
4458
4459void
4461{
4462 int line = cmd.line ();
4463 if (line < 0)
4464 line = 1;
4465
4466 if (m_echo_state)
4467 {
4468 echo_code (line);
4469 line++;
4470 }
4471
4472 unwind_protect_var<bool> upv (m_in_loop_command, true);
4473
4474 tree_expression *expr = cmd.condition ();
4475
4476 if (! expr)
4477 error ("unexpected: while condition is nullptr - please report this bug");
4478
4479 for (;;)
4480 {
4481 if (m_echo_state)
4482 m_echo_file_pos = line;
4483
4484 if (m_debug_mode)
4485 do_breakpoint (cmd.is_active_breakpoint (*this));
4486
4487 if (is_logically_true (expr, "while"))
4488 {
4489 tree_statement_list *loop_body = cmd.body ();
4490
4491 if (loop_body)
4492 loop_body->accept (*this);
4493
4494 if (quit_loop_now ())
4495 break;
4496 }
4497 else
4498 break;
4499 }
4500}
4501
4502void
4504{
4505 int line = cmd.line ();
4506 if (line < 0)
4507 line = 1;
4508
4509 if (m_echo_state)
4510 {
4511 echo_code (line);
4512 line++;
4513 }
4514
4515 unwind_protect_var<bool> upv (m_in_loop_command, true);
4516
4517 tree_expression *expr = cmd.condition ();
4518
4519 if (! expr)
4520 error ("unexpected: do-until condition is nullptr - please report this bug");
4521
4522 for (;;)
4523 {
4524 if (m_echo_state)
4525 m_echo_file_pos = line;
4526
4527 tree_statement_list *loop_body = cmd.body ();
4528
4529 if (loop_body)
4530 loop_body->accept (*this);
4531
4532 if (quit_loop_now ())
4533 break;
4534
4535 if (m_debug_mode)
4536 do_breakpoint (cmd.is_active_breakpoint (*this));
4537
4538 if (is_logically_true (expr, "do-until"))
4539 break;
4540 }
4541}
4542
4543void
4545{
4546 error_unexpected ("tree_evaluator::visit_superclass_ref");
4547}
4548
4549void
4551{
4552 error_unexpected ("tree_evaluator::visit_metaclass_query");
4553}
4554
4555void
4557{
4558 static std::string ans = "ans";
4559
4560 if (val.is_defined ())
4561 {
4562 if (val.is_cs_list ())
4563 {
4564 octave_value_list lst = val.list_value ();
4565
4566 for (octave_idx_type i = 0; i < lst.length (); i++)
4567 bind_ans (lst(i), print);
4568 }
4569 else
4570 {
4571 // FIXME: Maybe assign could also return the assigned value,
4572 // just for convenience?
4573
4574 assign (ans, val);
4575
4576 if (print)
4577 {
4578 // Use varval instead of displaying VAL directly so that
4579 // we get the right type and value for things like
4580 // magic_int values that may mutate when stored.
4581
4582 octave_value_list args = ovl (varval (ans));
4583 args.stash_name_tags (string_vector (ans));
4584 m_interpreter.feval ("display", args);
4585 }
4586 }
4587 }
4588}
4589
4590void
4591tree_evaluator::do_breakpoint (tree_statement& stmt)
4592{
4593 do_breakpoint (stmt.is_active_breakpoint (*this),
4594 stmt.is_end_of_fcn_or_script ());
4595}
4596
4597void
4598tree_evaluator::do_breakpoint (bool is_breakpoint,
4599 bool is_end_of_fcn_or_script)
4600{
4601 bool break_on_this_statement = false;
4602
4603 if (is_breakpoint)
4604 break_on_this_statement = true;
4605 else if (m_dbstep_flag > 0)
4606 {
4607 if (m_call_stack.current_frame () == m_debug_frame)
4608 {
4609 if (m_dbstep_flag == 1 || is_end_of_fcn_or_script)
4610 {
4611 // We get here if we are doing a "dbstep" or a "dbstep N" and
4612 // the count has reached 1 so that we must stop and return to
4613 // debug prompt. Alternatively, "dbstep N" has been used but
4614 // the end of the frame has been reached so we stop at the last
4615 // line and return to prompt.
4616
4617 break_on_this_statement = true;
4618 }
4619 else
4620 {
4621 // Executing "dbstep N". Decrease N by one and continue.
4622
4623 m_dbstep_flag--;
4624 }
4625
4626 }
4627 else if (m_dbstep_flag == 1
4628 && m_call_stack.current_frame () < m_debug_frame)
4629 {
4630 // We stepped out from the end of a function.
4631
4632 m_debug_frame = m_call_stack.current_frame ();
4633
4634 break_on_this_statement = true;
4635 }
4636 }
4637 else if (m_dbstep_flag == -1)
4638 {
4639 // We get here if we are doing a "dbstep in".
4640
4641 break_on_this_statement = true;
4642
4643 m_debug_frame = m_call_stack.current_frame ();
4644 }
4645 else if (m_dbstep_flag == -2)
4646 {
4647 // We get here if we are doing a "dbstep out". Check for end of
4648 // function and whether the current frame is the same as the
4649 // cached value because we want to step out from the frame where
4650 // "dbstep out" was evaluated, not from any functions called from
4651 // that frame.
4652
4653 if (is_end_of_fcn_or_script
4654 && m_call_stack.current_frame () == m_debug_frame)
4655 m_dbstep_flag = -1;
4656 }
4657
4658 if (! break_on_this_statement)
4659 break_on_this_statement = m_break_on_next_stmt;
4660
4661 m_break_on_next_stmt = false;
4662
4663 if (break_on_this_statement)
4664 {
4665 m_dbstep_flag = 0;
4666
4667 enter_debugger ();
4668 }
4669}
4670
4671bool
4672tree_evaluator::is_logically_true (tree_expression *expr,
4673 const char *warn_for)
4674{
4675 bool expr_value = false;
4676
4677 m_call_stack.set_location (expr->line (), expr->column ());
4678
4679 octave_value t1 = expr->evaluate (*this);
4680
4681 if (t1.is_defined ())
4682 return t1.is_true ();
4683 else
4684 error ("%s: undefined value used in conditional expression", warn_for);
4685
4686 return expr_value;
4687}
4688
4691 int nargout)
4692{
4693 return set_internal_variable (m_max_recursion_depth, args, nargout,
4694 "max_recursion_depth", 0);
4695}
4696
4698tree_evaluator::glob_symbol_info (const std::string& pattern) const
4699{
4700 return m_call_stack.glob_symbol_info (pattern);
4701}
4702
4704tree_evaluator::regexp_symbol_info (const std::string& pattern) const
4705{
4706 return m_call_stack.regexp_symbol_info (pattern);
4707}
4708
4711{
4712 return m_call_stack.get_symbol_info ();
4713}
4714
4717{
4718 return m_call_stack.top_scope_symbol_info ();
4719}
4720
4723{
4724 Cell fcn_names (dim_vector (m_autoload_map.size (), 1));
4725 Cell file_names (dim_vector (m_autoload_map.size (), 1));
4726
4727 octave_idx_type i = 0;
4728 for (const auto& fcn_fname : m_autoload_map)
4729 {
4730 fcn_names(i) = fcn_fname.first;
4731 file_names(i) = fcn_fname.second;
4732
4733 i++;
4734 }
4735
4736 octave_map m;
4737
4738 m.assign ("function", fcn_names);
4739 m.assign ("file", file_names);
4740
4741 return m;
4742}
4743
4744std::string
4745tree_evaluator::lookup_autoload (const std::string& nm) const
4746{
4747 std::string retval;
4748
4749 auto p = m_autoload_map.find (nm);
4750
4751 if (p != m_autoload_map.end ())
4752 {
4753 load_path& lp = m_interpreter.get_load_path ();
4754
4755 retval = lp.find_file (p->second);
4756 }
4757
4758 return retval;
4759}
4760
4761std::list<std::string>
4763{
4764 std::list<std::string> names;
4765
4766 for (const auto& fcn_fname : m_autoload_map)
4767 names.push_back (fcn_fname.first);
4768
4769 return names;
4770}
4771
4772std::list<std::string>
4773tree_evaluator::reverse_lookup_autoload (const std::string& nm) const
4774{
4775 std::list<std::string> names;
4776
4777 for (const auto& fcn_fname : m_autoload_map)
4778 if (nm == fcn_fname.second)
4779 names.push_back (fcn_fname.first);
4780
4781 return names;
4782}
4783
4784void
4785tree_evaluator::add_autoload (const std::string& fcn,
4786 const std::string& nm)
4787{
4788 m_autoload_map[fcn] = check_autoload_file (nm);
4789}
4790
4791void
4792tree_evaluator::remove_autoload (const std::string& fcn,
4793 const std::string& nm)
4794{
4795 check_autoload_file (nm);
4796
4797 // Remove function from symbol table and autoload map.
4798 symbol_table& symtab = m_interpreter.get_symbol_table ();
4799
4800 symtab.clear_dld_function (fcn);
4801
4802 m_autoload_map.erase (fcn);
4803}
4804
4807{
4808 return set_internal_variable (m_whos_line_format, args, nargout,
4809 "whos_line_format");
4810}
4811
4814{
4815 return set_internal_variable (m_silent_functions, args, nargout,
4816 "silent_functions");
4817}
4818
4821{
4822 return set_internal_variable (m_string_fill_char, args, nargout,
4823 "string_fill_char");
4824}
4825
4826// Final step of processing an indexing error. Add the name of the
4827// variable being indexed, if any, then issue an error. (Will this also
4828// be needed by pt-lvalue, which calls subsref?)
4829
4830void
4832 const tree_expression *expr)
4833{
4834 std::string extra_message;
4835
4836 if (is_variable (expr))
4837 {
4838 std::string var = expr->name ();
4839
4840 ie.set_var (var);
4841
4842 symbol_table& symtab = m_interpreter.get_symbol_table ();
4843
4844 octave_value fcn = symtab.find_function (var);
4845
4846 if (fcn.is_function ())
4847 {
4848 octave_function *fp = fcn.function_value ();
4849
4850 if (fp && fp->name () == var)
4851 extra_message
4852 = " (note: variable '" + var + "' shadows function)";
4853 }
4854 }
4855
4856 std::string msg = ie.message () + extra_message;
4857
4858 error_with_id (ie.err_id (), "%s", msg.c_str ());
4859}
4860
4863 bool return_list, bool verbose)
4864{
4865 return m_call_stack.do_who (argc, argv, return_list, verbose);
4866}
4867
4870 const string_vector& arg_nm)
4871{
4872 octave_value_list retval;
4873
4874 if (args)
4875 {
4877 upv (m_lvalue_list, nullptr);
4878
4879 int len = args->size ();
4880
4881 unwind_protect_var<int> upv2 (m_index_position);
4882 unwind_protect_var<int> upv3 (m_num_indices);
4883
4884 m_num_indices = len;
4885
4886 std::list<octave_value> arg_vals;
4887
4888 int k = 0;
4889
4890 for (auto elt : *args)
4891 {
4892 // FIXME: is it possible for elt to be invalid?
4893
4894 if (! elt)
4895 break;
4896
4897 m_index_position = k++;
4898
4899 octave_value tmp = elt->evaluate (*this);
4900
4901 if (tmp.is_cs_list ())
4902 {
4903 octave_value_list tmp_ovl = tmp.list_value ();
4904
4905 for (octave_idx_type i = 0; i < tmp_ovl.length (); i++)
4906 arg_vals.push_back (tmp_ovl(i));
4907 }
4908 else if (tmp.is_defined ())
4909 arg_vals.push_back (tmp);
4910 }
4911
4912 retval = octave_value_list (arg_vals);
4913 }
4914
4915 octave_idx_type n = retval.length ();
4916
4917 if (n > 0)
4918 retval.stash_name_tags (arg_nm);
4919
4920 return retval;
4921}
4922
4923std::list<octave_lvalue>
4925{
4926 std::list<octave_lvalue> retval;
4927
4928 for (tree_expression *elt : *lhs)
4929 retval.push_back (elt->lvalue (*this));
4930
4931 return retval;
4932}
4933
4934void
4935tree_evaluator::push_echo_state (int type, const std::string& file_name,
4936 int pos)
4937{
4938 unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
4939
4940 if (frame)
4941 {
4942 push_echo_state_cleanup (*frame);
4943
4944 set_echo_state (type, file_name, pos);
4945 }
4946}
4947
4948void
4949tree_evaluator::set_echo_state (int type, const std::string& file_name,
4950 int pos)
4951{
4952 m_echo_state = echo_this_file (file_name, type);
4953
4954 m_echo_file_name = file_name;
4955 m_echo_file_pos = pos;
4956}
4957
4958void
4959tree_evaluator::uwp_set_echo_state (bool state, const std::string& file_name,
4960 int pos)
4961{
4962 m_echo_state = state;
4963
4964 m_echo_file_name = file_name;
4965 m_echo_file_pos = pos;
4966}
4967
4968void
4969tree_evaluator::maybe_set_echo_state ()
4970{
4971 octave_function *caller = caller_function ();
4972
4973 if (caller && caller->is_user_code ())
4974 {
4975 octave_user_code *fcn = dynamic_cast<octave_user_code *> (caller);
4976
4977 int type = fcn->is_user_function () ? ECHO_FUNCTIONS : ECHO_SCRIPTS;
4978
4979 std::string file_name = fcn->fcn_file_name ();
4980
4981 // We want the line where "echo" was called, not the line number
4982 // stored in the stack frame that was created for the echo
4983 // function (that will always be -1).
4984
4985 int pos = m_call_stack.current_user_code_line ();
4986
4987 if (pos < 0)
4988 pos = 1;
4989
4990 set_echo_state (type, file_name, pos);
4991 }
4992}
4993
4994void
4995tree_evaluator::push_echo_state_cleanup (unwind_protect& frame)
4996{
4997 frame.add (&tree_evaluator::uwp_set_echo_state, this,
4998 m_echo_state, m_echo_file_name, m_echo_file_pos);
4999}
5000
5001bool
5002tree_evaluator::maybe_push_echo_state_cleanup ()
5003{
5004 // This function is expected to be called from ECHO, which would be
5005 // the top of the call stack. If the caller of ECHO is a
5006 // user-defined function or script, then set up unwind-protect
5007 // elements to restore echo state.
5008
5009 unwind_protect *frame = m_call_stack.curr_fcn_unwind_protect_frame ();
5010
5011 if (frame)
5012 {
5013 push_echo_state_cleanup (*frame);
5014 return true;
5015 }
5016
5017 return false;
5018}
5019
5020
5023{
5024 bool cleanup_pushed = maybe_push_echo_state_cleanup ();
5025
5026 string_vector argv = args.make_argv ();
5027
5028 switch (args.length ())
5029 {
5030 case 0:
5031 if ((m_echo & ECHO_SCRIPTS) || (m_echo & ECHO_FUNCTIONS))
5032 {
5033 m_echo = ECHO_OFF;
5034 m_echo_files.clear ();
5035 }
5036 else
5037 m_echo = ECHO_SCRIPTS;
5038 break;
5039
5040 case 1:
5041 {
5042 std::string arg0 = argv[0];
5043
5044 if (arg0 == "on")
5045 m_echo = ECHO_SCRIPTS;
5046 else if (arg0 == "off")
5047 m_echo = ECHO_OFF;
5048 else
5049 {
5050 std::string file = fcn_file_in_path (arg0);
5051 file = sys::env::make_absolute (file);
5052
5053 if (file.empty ())
5054 error ("echo: no such file %s", arg0.c_str ());
5055
5056 if (m_echo & ECHO_ALL)
5057 {
5058 // Echo is enabled for all functions, so turn it off
5059 // for this one.
5060
5061 m_echo_files[file] = false;
5062 }
5063 else
5064 {
5065 // Echo may be enabled for specific functions.
5066
5067 auto p = m_echo_files.find (file);
5068
5069 if (p == m_echo_files.end ())
5070 {
5071 // Not this one, so enable it.
5072
5073 m_echo |= ECHO_FUNCTIONS;
5074 m_echo_files[file] = true;
5075 }
5076 else
5077 {
5078 // This one is already in the list. Flip the
5079 // status for it.
5080
5081 p->second = ! p->second;
5082 }
5083 }
5084 }
5085 }
5086 break;
5087
5088 case 2:
5089 {
5090 std::string arg0 = argv[0];
5091 std::string arg1 = argv[1];
5092
5093 if (arg1 == "on" || arg1 == "off")
5094 std::swap (arg0, arg1);
5095
5096 if (arg0 == "on")
5097 {
5098 if (arg1 == "all")
5099 {
5100 m_echo = (ECHO_SCRIPTS | ECHO_FUNCTIONS | ECHO_ALL);
5101 m_echo_files.clear ();
5102 }
5103 else
5104 {
5105 std::string file = fcn_file_in_path (arg1);
5106 file = sys::env::make_absolute (file);
5107
5108 if (file.empty ())
5109 error ("echo: no such file %s", arg1.c_str ());
5110
5111 m_echo |= ECHO_FUNCTIONS;
5112 m_echo_files[file] = true;
5113 }
5114 }
5115 else if (arg0 == "off")
5116 {
5117 if (arg1 == "all")
5118 {
5119 m_echo = ECHO_OFF;
5120 m_echo_files.clear ();
5121 }
5122 else
5123 {
5124 std::string file = fcn_file_in_path (arg1);
5125 file = sys::env::make_absolute (file);
5126
5127 if (file.empty ())
5128 error ("echo: no such file %s", arg1.c_str ());
5129
5130 m_echo_files[file] = false;
5131 }
5132 }
5133 else
5134 print_usage ();
5135 }
5136 break;
5137
5138 default:
5139 print_usage ();
5140 break;
5141 }
5142
5143 if (cleanup_pushed)
5144 maybe_set_echo_state ();
5145
5146 return octave_value ();
5147}
5148
5149bool
5151{
5152 return (m_debugger_stack.empty ()
5153 ? false : m_debugger_stack.top()->in_debug_repl ());
5154}
5155
5156void
5158{
5159 if (! m_debugger_stack.empty ())
5160 m_debugger_stack.top()->dbcont ();
5161}
5162
5163void
5165{
5166 if (! m_debugger_stack.empty ())
5167 m_debugger_stack.top()->dbquit (all);
5168}
5169
5172{
5173 int nargin = args.length ();
5174
5175 if (nargin != 0 && nargin != 3)
5176 print_usage ();
5177
5178 if (nargin == 3)
5179 {
5181 = args(1).strict_idx_type_value ("end: K must be integer value");
5182
5183 if (index_position < 1)
5184 error ("end: K must be greater than zero");
5185
5187 = args(2).strict_idx_type_value ("end: N must be integer value");
5188
5189 if (num_indices < 1)
5190 error ("end: N must be greater than zero");
5191
5192 return octave_value (args(0).end_index (index_position-1, num_indices));
5193 }
5194
5195 // If m_indexed_object is undefined, then this use of 'end' is
5196 // either appearing in a function call argument list or in an
5197 // attempt to index an undefined symbol. There seems to be no
5198 // reasonable way to provide a better error message. So just fail
5199 // with an invalid use message. See bug #58830.
5200
5201 if (m_indexed_object.is_undefined ())
5202 error ("invalid use of 'end': may only be used to index existing value");
5203
5204 octave_value expr_result;
5205
5206 if (m_index_list.empty ())
5207 expr_result = m_indexed_object;
5208 else
5209 {
5210 try
5211 {
5212 // When evaluating "end" with no arguments, we should have
5213 // been called from the built-in Fend function that appears
5214 // in the context of an argument list. Fend will be
5215 // evaluated in its own stack frame. But we need to
5216 // evaluate the partial expression that the special "end"
5217 // token applies to in the calling stack frame.
5218
5219 unwind_action act ([this] (std::size_t frm)
5220 {
5221 m_call_stack.restore_frame (frm);
5222 }, m_call_stack.current_frame ());
5223
5224 std::size_t n = m_call_stack.find_current_user_frame ();
5225 m_call_stack.goto_frame (n);
5226
5227 // End is only valid inside argument lists used for
5228 // indexing. The dispatch class is set by the function that
5229 // evaluates the argument list.
5230
5231 // Silently ignore extra output values.
5232
5234 = m_indexed_object.subsref (m_index_type, m_index_list, 1);
5235
5236 expr_result = tmp.length () ? tmp(0) : octave_value ();
5237
5238 if (expr_result.is_cs_list ())
5240 }
5241 catch (const index_exception&)
5242 {
5243 error ("error evaluating partial expression for END");
5244 }
5245 }
5246
5247 if (expr_result.isobject ())
5248 {
5249 // FIXME: is there a better way to lookup and execute a method
5250 // that handles all the details like setting the dispatch class
5251 // appropriately?
5252
5253 std::string dispatch_class = expr_result.class_name ();
5254
5255 symbol_table& symtab = m_interpreter.get_symbol_table ();
5256
5257 octave_value meth = symtab.find_method ("end", dispatch_class);
5258
5259 if (meth.is_defined ())
5260 return m_interpreter.feval
5261 (meth, ovl (expr_result, m_index_position+1, m_num_indices), 1);
5262 }
5263
5264 return octave_value (expr_result.end_index (m_index_position, m_num_indices));
5265}
5266
5268tree_evaluator::PS4 (const octave_value_list& args, int nargout)
5269{
5270 return set_internal_variable (m_PS4, args, nargout, "PS4");
5271}
5272
5273bool
5274tree_evaluator::echo_this_file (const std::string& file, int type) const
5275{
5276 if ((type & m_echo) == ECHO_SCRIPTS)
5277 {
5278 // Asking about scripts and echo is enabled for them.
5279 return true;
5280 }
5281
5282 if ((type & m_echo) == ECHO_FUNCTIONS)
5283 {
5284 // Asking about functions and echo is enabled for functions.
5285 // Now, which ones?
5286
5287 auto p = m_echo_files.find (file);
5288
5289 if (m_echo & ECHO_ALL)
5290 {
5291 // Return true ulness echo was turned off for a specific
5292 // file.
5293
5294 return (p == m_echo_files.end () || p->second);
5295 }
5296 else
5297 {
5298 // Return true if echo is specifically enabled for this file.
5299
5300 return p != m_echo_files.end () && p->second;
5301 }
5302 }
5303
5304 return false;
5305}
5306
5307void
5308tree_evaluator::echo_code (int line)
5309{
5310 std::string prefix = command_editor::decode_prompt_string (m_PS4);
5311
5312 octave_function *curr_fcn = m_call_stack.current_function ();
5313
5314 if (curr_fcn && curr_fcn->is_user_code ())
5315 {
5316 octave_user_code *code = dynamic_cast<octave_user_code *> (curr_fcn);
5317
5318 int num_lines = line - m_echo_file_pos + 1;
5319
5320 std::deque<std::string> lines
5321 = code->get_code_lines (m_echo_file_pos, num_lines);
5322
5323 for (auto& elt : lines)
5324 octave_stdout << prefix << elt << std::endl;
5325 }
5326}
5327
5328// Decide if it's time to quit a for or while loop.
5329bool
5330tree_evaluator::quit_loop_now ()
5331{
5332 octave_quit ();
5333
5334 // Maybe handle 'continue N' someday...
5335
5336 if (m_continuing)
5337 m_continuing--;
5338
5339 bool quit = (m_returning || m_breaking || m_continuing);
5340
5341 if (m_breaking)
5342 m_breaking--;
5343
5344 return quit;
5345}
5346
5347void
5348tree_evaluator::bind_auto_fcn_vars (const string_vector& arg_names,
5349 const Matrix& ignored_outputs,
5350 int nargin, int nargout,
5351 bool takes_varargs,
5352 const octave_value_list& va_args)
5353{
5355 set_auto_fcn_var (stack_frame::IGNORED, ignored_outputs);
5359
5360 if (takes_varargs)
5361 assign ("varargin", va_args.cell_value ());
5362}
5363
5364std::string
5365tree_evaluator::check_autoload_file (const std::string& nm) const
5366{
5367 if (sys::env::absolute_pathname (nm))
5368 return nm;
5369
5370 std::string full_name = nm;
5371
5372 octave_user_code *fcn = m_call_stack.current_user_code ();
5373
5374 bool found = false;
5375
5376 if (fcn)
5377 {
5378 std::string fname = fcn->fcn_file_name ();
5379
5380 if (! fname.empty ())
5381 {
5382 fname = sys::env::make_absolute (fname);
5383 fname = fname.substr (0, fname.find_last_of (sys::file_ops::dir_sep_str ()) + 1);
5384
5385 sys::file_stat fs (fname + nm);
5386
5387 if (fs.exists ())
5388 {
5389 full_name = fname + nm;
5390 found = true;
5391 }
5392 }
5393 }
5394
5395 if (! found)
5396 warning_with_id ("Octave:autoload-relative-file-name",
5397 "autoload: '%s' is not an absolute filename",
5398 nm.c_str ());
5399
5400 return full_name;
5401}
5402
5403DEFMETHOD (max_recursion_depth, interp, args, nargout,
5404 doc: /* -*- texinfo -*-
5405@deftypefn {} {@var{val} =} max_recursion_depth ()
5406@deftypefnx {} {@var{old_val} =} max_recursion_depth (@var{new_val})
5407@deftypefnx {} {@var{old_val} =} max_recursion_depth (@var{new_val}, "local")
5408Query or set the internal limit on the number of times a function may
5409be called recursively.
5410
5411If the limit is exceeded, an error message is printed and control returns to
5412the top level.
5413
5414When called from inside a function with the @qcode{"local"} option, the
5415variable is changed locally for the function and any subroutines it calls.
5416The original variable value is restored when exiting the function.
5417
5418@seealso{max_stack_depth}
5419@end deftypefn */)
5420{
5421 tree_evaluator& tw = interp.get_evaluator ();
5422
5423 return tw.max_recursion_depth (args, nargout);
5424}
5425
5426/*
5427%!test
5428%! orig_val = max_recursion_depth ();
5429%! old_val = max_recursion_depth (2*orig_val);
5430%! assert (orig_val, old_val);
5431%! assert (max_recursion_depth (), 2*orig_val);
5432%! max_recursion_depth (orig_val);
5433%! assert (max_recursion_depth (), orig_val);
5434
5435%!error max_recursion_depth (1, 2)
5436*/
5437
5438DEFMETHOD (whos_line_format, interp, args, nargout,
5439 doc: /* -*- texinfo -*-
5440@deftypefn {} {@var{val} =} whos_line_format ()
5441@deftypefnx {} {@var{old_val} =} whos_line_format (@var{new_val})
5442@deftypefnx {} {@var{old_val} =} whos_line_format (@var{new_val}, "local")
5443Query or set the format string used by the command @code{whos}.
5444
5445A full format string is:
5446@c Set example in small font to prevent overfull line
5447
5448@smallexample
5449%[modifier]<command>[:width[:left-min[:balance]]];
5450@end smallexample
5451
5452The following command sequences are available:
5453
5454@table @code
5455@item %a
5456Prints attributes of variables (c=complex, s=sparse, f=formal parameter,
5457g=global, p=persistent).
5458
5459@item %b
5460Prints number of bytes occupied by variables.
5461
5462@item %c
5463Prints class names of variables.
5464
5465@item %e
5466Prints elements held by variables.
5467
5468@item %n
5469Prints variable names.
5470
5471@item %s
5472Prints dimensions of variables.
5473
5474@item %t
5475Prints type names of variables.
5476@end table
5477
5478Every command may also have an alignment modifier:
5479
5480@table @code
5481@item l
5482Left alignment.
5483
5484@item r
5485Right alignment (default).
5486
5487@item c
5488Column-aligned (only applicable to command %s).
5489@end table
5490
5491The @code{width} parameter is a positive integer specifying the minimum
5492number of columns used for printing. No maximum is needed as the field will
5493auto-expand as required.
5494
5495The parameters @code{left-min} and @code{balance} are only available when
5496the column-aligned modifier is used with the command @samp{%s}.
5497@code{balance} specifies the column number within the field width which
5498will be aligned between entries. Numbering starts from 0 which indicates
5499the leftmost column. @code{left-min} specifies the minimum field width to
5500the left of the specified balance column.
5501
5502The default format is:
5503
5504@example
5505" %la:5; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;@backslashchar{}n"
5506@end example
5507
5508When called from inside a function with the @qcode{"local"} option, the
5509variable is changed locally for the function and any subroutines it calls.
5510The original variable value is restored when exiting the function.
5511@seealso{whos}
5512@end deftypefn */)
5513{
5514 tree_evaluator& tw = interp.get_evaluator ();
5515
5516 return tw.whos_line_format (args, nargout);
5517}
5518
5519DEFMETHOD (silent_functions, interp, args, nargout,
5520 doc: /* -*- texinfo -*-
5521@deftypefn {} {@var{val} =} silent_functions ()
5522@deftypefnx {} {@var{old_val} =} silent_functions (@var{new_val})
5523@deftypefnx {} {@var{old_val} =} silent_functions (@var{new_val}, "local")
5524Query or set the internal variable that controls whether internal
5525output from a function is suppressed.
5526
5527If this option is disabled, Octave will display the results produced by
5528evaluating expressions within a function body that are not terminated with
5529a semicolon.
5530
5531When called from inside a function with the @qcode{"local"} option, the
5532variable is changed locally for the function and any subroutines it calls.
5533The original variable value is restored when exiting the function.
5534@end deftypefn */)
5535{
5536 tree_evaluator& tw = interp.get_evaluator ();
5537
5538 return tw.silent_functions (args, nargout);
5539}
5540
5541/*
5542%!test
5543%! orig_val = silent_functions ();
5544%! old_val = silent_functions (! orig_val);
5545%! assert (orig_val, old_val);
5546%! assert (silent_functions (), ! orig_val);
5547%! silent_functions (orig_val);
5548%! assert (silent_functions (), orig_val);
5549
5550%!error silent_functions (1, 2)
5551*/
5552
5553DEFMETHOD (string_fill_char, interp, args, nargout,
5554 doc: /* -*- texinfo -*-
5555@deftypefn {} {@var{val} =} string_fill_char ()
5556@deftypefnx {} {@var{old_val} =} string_fill_char (@var{new_val})
5557@deftypefnx {} {@var{old_val} =} string_fill_char (@var{new_val}, "local")
5558Query or set the internal variable used to pad all rows of a character
5559matrix to the same length.
5560
5561The value must be a single character and the default is @qcode{" "} (a
5562single space). For example:
5563
5564@example
5565@group
5566string_fill_char ("X");
5567[ "these"; "are"; "strings" ]
5568 @xresult{} "theseXX"
5569 "areXXXX"
5570 "strings"
5571@end group
5572@end example
5573
5574When called from inside a function with the @qcode{"local"} option, the
5575variable is changed locally for the function and any subroutines it calls.
5576The original variable value is restored when exiting the function.
5577@end deftypefn */)
5578{
5579 tree_evaluator& tw = interp.get_evaluator ();
5580
5581 return tw.string_fill_char (args, nargout);
5582}
5583
5584/*
5585## string_fill_char() function call must be outside of %!test block
5586## due to the way a %!test block is wrapped inside a function
5587%!shared orig_val, old_val
5588%! orig_val = string_fill_char ();
5589%! old_val = string_fill_char ("X");
5590%!test
5591%! assert (orig_val, old_val);
5592%! assert (string_fill_char (), "X");
5593%! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]);
5594%! string_fill_char (orig_val);
5595%! assert (string_fill_char (), orig_val);
5596
5597%!assert ( [ [], {1} ], {1} )
5598
5599%!error string_fill_char (1, 2)
5600*/
5601
5602DEFMETHOD (PS4, interp, args, nargout,
5603 doc: /* -*- texinfo -*-
5604@deftypefn {} {@var{val} =} PS4 ()
5605@deftypefnx {} {@var{old_val} =} PS4 (@var{new_val})
5606@deftypefnx {} {@var{old_val} =} PS4 (@var{new_val}, "local")
5607Query or set the character string used to prefix output produced
5608when echoing commands is enabled.
5609
5610The default value is @qcode{"+ "}.
5611@xref{Diary and Echo Commands}, for a description of echoing commands.
5612
5613When called from inside a function with the @qcode{"local"} option, the
5614variable is changed locally for the function and any subroutines it calls.
5615The original variable value is restored when exiting the function.
5616@seealso{echo, PS1, PS2}
5617@end deftypefn */)
5618{
5619 return interp.PS4 (args, nargout);
5620}
5621
5622DEFMETHOD (echo, interp, args, nargout,
5623 doc: /* -*- texinfo -*-
5624@deftypefn {} {} echo
5625@deftypefnx {} {} echo on
5626@deftypefnx {} {} echo off
5627@deftypefnx {} {} echo on all
5628@deftypefnx {} {} echo off all
5629@deftypefnx {} {} echo @var{function} on
5630@deftypefnx {} {} echo @var{function} off
5631Control whether commands are displayed as they are executed.
5632
5633Valid options are:
5634
5635@table @code
5636@item on
5637Enable echoing of commands as they are executed in script files.
5638
5639@item off
5640Disable echoing of commands as they are executed in script and function files.
5641
5642@item on all
5643Enable echoing of commands as they are executed in script files and functions.
5644
5645@item off all
5646Disable echoing of commands as they are executed in script files and functions.
5647
5648@item @var{function} on
5649Enable echoing of commands as they are executed in the named function.
5650
5651@item @var{function} off
5652Disable echoing of commands as they are executed in the named function.
5653@end table
5654
5655@noindent
5656With no arguments, @code{echo} toggles the current echo state.
5657
5658Programming Note: Echoing all commands can be a simple way to debug an easy
5659coding problem. However, the amount of output can grow quite quickly. For
5660more difficult problems the built-in debugger (@code{help debug}) is more
5661useful.
5662@seealso{PS4}
5663@end deftypefn */)
5664{
5665 tree_evaluator& tw = interp.get_evaluator ();
5666
5667 return tw.echo (args, nargout);
5668}
5669
5670/*
5671%!error echo ([])
5672%!error echo (0)
5673%!error echo ("")
5674%!error echo ("Octave")
5675%!error echo ("off", "invalid")
5676%!error echo ("on", "invalid")
5677%!error echo ("on", "all", "all")
5678*/
5679
5680/*
5681FIXME: Actually, it probably *isn't* worth fixing, but there is one small
5682difference between Octave and Matlab.
5683
5684If inputname is not called from a function, Matlab walks up the stack until it
5685finds some valid code and then works from there. This could be relevant for
5686mex files or anonymous functions.
5687
5688fcn = @(x) inputname (x);
5689a = 1:4;
5690arrayfun (fcn, a, 'uniformoutput', false)
5691% output is {'fcn', 'a', '', ''}
5692*/
5693DEFMETHOD (inputname, interp, args, ,
5694 doc: /* -*- texinfo -*-
5695@deftypefn {} {@var{namestr} =} inputname (@var{n})
5696@deftypefnx {} {@var{namestr} =} inputname (@var{n}, @var{ids_only})
5697Return the name of the @var{n}-th argument to the calling function.
5698
5699If the argument is not a simple variable name, return an empty string.
5700Examples which will return @qcode{""} are numbers (@code{5.1}), expressions
5701(@code{@var{y}/2}), and cell or structure indexing (@code{@var{c}@{1@}} or
5702@code{@var{s}.@var{field}}).
5703
5704@code{inputname} is only useful within a function. When used at the command
5705line or within a script it always returns an empty string.
5706
5707By default, return an empty string if the @var{n}-th argument is not a valid
5708variable name. If the optional argument @var{ids_only} is false, return the
5709text of the argument even if it is not a valid variable name. This is an
5710Octave extension that allows the programmer to view exactly how the function
5711was invoked even when the inputs are complex expressions.
5712@seealso{nargin, narginchk}
5713@end deftypefn */)
5714{
5715 int nargin = args.length ();
5716
5717 if (nargin < 1)
5718 print_usage ();
5719
5720 dim_vector dims = args(0).dims ();
5721 if (! dims.all_ones ())
5722 error ("inputname: N must be a scalar index");
5723
5724 int n = args(0).strict_int_value ("inputname: N must be a scalar index");
5725
5726 if (n < 1)
5727 error ("inputname: N must be a scalar index");
5728
5729 bool ids_only = true;
5730
5731 if (nargin == 2)
5732 ids_only = args(1).strict_bool_value ("inputname: IDS_ONLY must be a logical value");
5733
5734 // Use zero-based indexing internally.
5735 return ovl (interp.inputname (n-1, ids_only));
5736}
5737
5738/*
5739%!function name = __iname1__ (arg1, arg2, arg3)
5740%! name = inputname (1);
5741%!endfunction
5742
5743%!function name = __iname1_ID__ (arg1, arg2, arg3)
5744%! name = inputname (1, false);
5745%!endfunction
5746
5747%!function name = __iname2__ (arg1, arg2, arg3)
5748%! name = inputname (2);
5749%!endfunction
5750
5751%!function names = __iname3__ (arg1, arg2, arg3)
5752%! names = cell (1, 3);
5753%! for i = 1:3
5754%! names{i} = inputname (i);
5755%! endfor
5756%!endfunction
5757
5758%!test
5759%! assert (__iname1__ ('xvar'), "");
5760%! xvar = 1;
5761%! assert (__iname1__ (xvar), "xvar");
5762
5763%!test
5764%! xvar = 1; yvar = 2;
5765%! assert (__iname2__ (xvar), "");
5766%! assert (__iname2__ (xvar, yvar), "yvar");
5767
5768%!test
5769%! xvar = 1; yvar = 2;
5770%! assert (__iname3__ (xvar), {"xvar", "", ""});
5771%! assert (__iname3__ (xvar, yvar), {"xvar", "yvar", ""});
5772%! assert (__iname3__ (xvar, 3, yvar), {"xvar", "", "yvar"});
5773
5774## Test numbers, expressions, indexing operations
5775%!test
5776%! assert (__iname1__ (1.0), "");
5777%! x = 1;
5778%! assert (__iname1__ (x / 2), "");
5779%! assert (__iname1__ (Inf), "");
5780
5781%!test
5782%! assert (__iname1_ID__ (1.0), "1.0");
5783%! x = 1;
5784%! assert (__iname1_ID__ (x / 2), "x / 2");
5785%! assert (__iname1_ID__ (Inf), "Inf");
5786
5787%!error <Invalid call> inputname ()
5788%!error <N must be a scalar> inputname (ones (2,2))
5789%!error <N must be a scalar index> inputname (-1)
5790*/
5791
5792OCTAVE_END_NAMESPACE(octave)
octave_idx_type rows() const
Definition Array-base.h:485
octave_idx_type columns() const
Definition Array-base.h:497
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
Definition Cell.h:41
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition dMatrix.h:156
void add(F &&fcn, Args &&... args)
void discard(std::size_t num)
void run(std::size_t num)
void protect_var(T &var)
void forced_interactive(bool arg)
Definition octave.h:312
static application * app()
Definition octave.h:318
static bool forced_interactive()
Definition octave.cc:342
void statement_list(std::shared_ptr< tree_statement_list > &lst)
void disallow_command_syntax()
bool at_end_of_input() const
Definition parse.h:167
bool debug_on_err(const std::string &id)
Definition bp-table.h:142
bool have_breakpoints()
Definition bp-table.h:139
bool debug_on_caught(const std::string &id)
Definition bp-table.h:148
void set_dispatch_class(const std::string &class_name)
std::shared_ptr< stack_frame > get_current_stack_frame() const
Definition call-stack.h:89
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
octave_value get_top_level_value(const std::string &name) const
octave_value global_varval(const std::string &name) const
std::size_t find_current_user_frame() const
std::list< frame_info > backtrace_info(octave_idx_type &curr_user_frame, bool print_subfn=true) const
void set_column(int c)
Definition call-stack.h:188
octave_map backtrace(octave_idx_type &curr_user_frame, bool print_subfn=true) const
octave_value & global_varref(const std::string &name)
void set_top_level_value(const std::string &name, const octave_value &value)
int current_line() const
Definition call-stack.cc:93
void display() const
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
std::list< std::string > variable_names() const
symbol_info_list regexp_symbol_info(const std::string &pattern) const
void make_global(const symbol_record &sym)
std::shared_ptr< stack_frame > current_user_frame() const
std::size_t size() const
Definition call-stack.h:87
std::shared_ptr< stack_frame > pop_return()
void clear_global_variables()
symbol_info_list glob_symbol_info(const std::string &pattern) const
void restore_frame(std::size_t n)
Definition call-stack.h:200
bool at_top_level() const
Definition call-stack.h:106
bool is_class_method_executing(std::string &dispatch_class) const
bool goto_frame(std::size_t n=0, bool verbose=false)
int debug_user_code_column() const
std::size_t current_frame() const
Definition call-stack.h:85
void set_auto_fcn_var(stack_frame::auto_var_type avt, const octave_value &val)
symbol_info_list get_symbol_info()
symbol_info_list top_scope_symbol_info() const
std::list< std::string > global_variable_names() const
std::list< std::shared_ptr< stack_frame > > backtrace_frames(octave_idx_type &curr_user_frame) const
void set_location(int l, int c)
Definition call-stack.h:167
bool is_class_constructor_executing(std::string &dispatch_class) const
void goto_caller_frame()
symbol_scope current_scope() const
Definition call-stack.h:99
octave_map empty_backtrace() const
octave_function * current_function(bool skip_first=false) const
Definition call-stack.cc:67
void clear_global_variable_pattern(const std::string &pattern)
unwind_protect * curr_fcn_unwind_protect_frame()
int debug_user_code_line() const
octave_user_code * debug_user_code() const
void set_line(int l)
Definition call-stack.h:178
void push(const symbol_scope &scope)
std::list< std::string > top_level_variable_names() const
void set_nargin(int nargin)
void clear_global_variable(const std::string &name)
octave_user_code * current_user_code() const
void goto_base_frame()
symbol_scope top_scope() const
Definition call-stack.h:94
void set_nargout(int nargout)
int current_user_code_line() const
std::size_t dbupdown(std::size_t start, int n, bool verbose)
int current_column() const
std::string get_dispatch_class() const
void clear_global_variable_regexp(const std::string &pattern)
void make_persistent(const symbol_record &sym)
octave_value max_stack_depth(const octave_value_list &args, int nargout)
cdef_method find_method(const std::string &nm, bool local=false)
Definition cdef-class.h:473
std::string get_name() const
Definition cdef-class.h:332
cdef_property find_property(const std::string &nm)
Definition cdef-class.h:479
cdef_class find_class(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
bool is_static() const
octave_value get_function() const
std::string get_name() const
cdef_class get_class() const
bool ok() const
octave_value get(const std::string &pname) const
std::string get_name() const
static void run_event_hooks()
Definition cmd-edit.cc:1576
static void increment_current_command_number()
Definition cmd-edit.cc:1292
static bool interrupt(bool=true)
Definition cmd-edit.cc:1620
static bool erase_empty_line(bool flag)
Definition cmd-edit.cc:1313
static std::string decode_prompt_string(const std::string &s)
Definition cmd-edit.cc:1273
static bool ignoring_entries()
Definition cmd-hist.cc:610
static bool add(const std::string &)
Definition cmd-hist.cc:616
static void ignore_entries(bool=true)
Definition cmd-hist.cc:603
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
bool all_ones() const
Definition dim-vector.h:330
octave_value last_error_id(const octave_value_list &args, int nargout)
Definition error.cc:359
octave_map last_error_stack() const
Definition error.h:254
octave_value debug_on_warning(const octave_value_list &args, int nargout)
Definition error.cc:293
void set_debug_on_warning(bool flag)
Definition error.h:90
octave_value debug_on_caught(const octave_value_list &args, int nargout)
Definition error.cc:286
void save_exception(const execution_exception &ee)
Definition error.cc:932
octave_value debug_on_error(const octave_value_list &args, int nargout)
Definition error.cc:279
octave_value last_error_message(const octave_value_list &args, int nargout)
Definition error.cc:337
void display_exception(const execution_exception &ee) const
Definition error.cc:944
void set_debug_on_error(bool flag)
Definition error.h:62
Provides threadsafe access to octave.
void append_history(const std::string &hist_entry)
void enter_debugger_event(const std::string &fcn_name, const std::string &fcn_file_name, int line)
void post_event(const fcn_callback &fcn)
void pre_input_event()
void execute_in_debugger_event(const std::string &file, int line)
void push_event_queue()
void set_var(const std::string &var_arg="")
virtual const char * err_id() const =0
octave_value auto_repeat_debug_command(const octave_value_list &args, int nargout)
octave_value gud_mode(const octave_value_list &args, int nargout)
cdef_manager & get_cdef_manager()
error_system & get_error_system()
load_path & get_load_path()
void set_PS1(const std::string &s)
octave_value PS1(const octave_value_list &args, int nargout)
void parse_and_execute(const std::string &input, bool &incomplete_parse)
bool interactive() const
tree_evaluator & get_evaluator()
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
void recover_from_exception()
octave_value PS2(const octave_value_list &args, int nargout)
event_manager & get_event_manager()
symbol_table & get_symbol_table()
Definition lex.h:725
std::string find_file(const std::string &file) const
Definition load-path.cc:585
virtual bool is_user_code() const
Definition ov-base.h:549
virtual bool is_user_function() const
Definition ov-base.h:547
virtual bool is_builtin_function() const
Definition ov-base.h:551
meth method() const
Definition ov-builtin.cc:59
octave_value_list(* fcn)(const octave_value_list &, int)
Definition ov-builtin.h:61
octave_value_list(* meth)(octave::interpreter &, const octave_value_list &, int)
Definition ov-builtin.h:58
fcn function() const
Definition ov-builtin.cc:53
octave_classdef * classdef_object_value(bool=false)
Definition ov-classdef.h:70
octave::cdef_object get_object() const
Definition ov-classdef.h:72
std::string class_name() const
virtual bool is_nested_function() const
Definition ov-fcn.h:108
virtual bool is_subfunction() const
Definition ov-fcn.h:112
std::string dispatch_class() const
Definition ov-fcn.h:154
bool islocked() const
Definition ov-fcn.h:192
bool is_class_method(const std::string &cname="") const
Definition ov-fcn.h:121
bool is_class_constructor(const std::string &cname="") const
Definition ov-fcn.h:116
bool is_private_function() const
Definition ov-fcn.h:167
virtual std::string parent_fcn_name() const
Definition ov-fcn.h:88
void unlock()
Definition ov-fcn.h:186
void stash_dir_name(const std::string &dir)
Definition ov-fcn.h:178
virtual bool is_parent_function() const
Definition ov-fcn.h:110
void lock()
Definition ov-fcn.h:180
virtual octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition ov-fcn.cc:79
virtual std::list< std::string > parent_fcn_names() const
Definition ov-fcn.h:93
void stash_dispatch_class(const std::string &nm)
Definition ov-fcn.h:152
virtual std::string fcn_file_name() const
Definition ov-fcn.h:75
std::string name() const
Definition ov-fcn.h:212
std::string dir_name() const
Definition ov-fcn.h:176
bool is_undefined() const
Definition oct-lvalue.cc:46
void assign(octave_value::assign_op, const octave_value &)
Definition oct-lvalue.cc:58
void define(const octave_value &v)
Definition oct-lvalue.cc:52
string_vector keys() const
Definition oct-map.h:335
const Cell & contents(const_iterator p) const
Definition oct-map.h:310
void assign(const std::string &k, const Cell &val)
Definition oct-map.h:344
void assign(const std::string &k, const octave_value &val)
Definition oct-map.h:230
void stash_fcn_file_name(const std::string &nm)
Definition ov-usr-fcn.h:104
std::string get_code_line(std::size_t line)
std::string fcn_file_name() const
Definition ov-usr-fcn.h:115
std::deque< std::string > get_code_lines(std::size_t line, std::size_t num_lines)
virtual octave_value find_subfunction(const std::string &) const
Definition ov-usr-fcn.h:121
octave::tree_statement_list * body()
Definition ov-usr-fcn.h:128
octave_user_code * user_code_value(bool=false)
Definition ov-usr-fcn.h:235
octave::tree_parameter_list * parameter_list()
Definition ov-usr-fcn.h:394
bool takes_varargs() const
bool is_special_expr() const
Definition ov-usr-fcn.h:338
octave_value_list all_va_args(const octave_value_list &args)
bool is_classdef_constructor(const std::string &cname="") const
Definition ov-usr-fcn.h:359
octave::tree_parameter_list * return_list()
Definition ov-usr-fcn.h:396
bool is_anonymous_function() const
Definition ov-usr-fcn.h:323
void mark_as_anonymous_function()
Definition ov-usr-fcn.h:321
void mark_as_nested_function()
Definition ov-usr-fcn.h:343
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition ovl.h:115
void stash_name_tags(const string_vector &nm)
Definition ovl.h:163
bool has_magic_colon() const
Definition ovl.cc:215
bool empty() const
Definition ovl.h:113
octave_value & xelem(octave_idx_type i)
Definition ovl.h:169
Cell cell_value() const
Definition ovl.h:103
string_vector name_tags() const
Definition ovl.h:165
octave_value_list slice(octave_idx_type offset, octave_idx_type len, bool tags=false) const
Definition ovl.h:129
void clear()
Definition ovl.h:171
string_vector make_argv(const std::string &="") const
Definition ovl.cc:227
octave_idx_type length() const
Definition ovl.h:111
void make_storable_values()
Definition ovl.cc:277
bool is_function_handle() const
Definition ov.h:766
octave_value_list list_value() const
bool is_undefined() const
Definition ov.h:593
Cell xcell_value(const char *fmt,...) const
std::string class_name() const
Definition ov.h:1360
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition ov.h:474
octave_function * function_value(bool silent=false) const
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition ov.h:502
bool is_true() const
Definition ov.h:756
Cell cell_value() const
int ndims() const
Definition ov.h:549
bool is_scalar_type() const
Definition ov.h:742
bool is_string() const
Definition ov.h:635
octave_idx_type end_index(octave_idx_type index_position, octave_idx_type num_indices) const
bool is_range() const
Definition ov.h:644
bool is_defined() const
Definition ov.h:590
bool is_function() const
Definition ov.h:775
bool is_equal(const octave_value &) const
@ op_asn_eq
Definition ov.h:135
octave_value storable_value() const
octave_value reshape(const dim_vector &dv) const
Definition ov.h:569
bool iscell() const
Definition ov.h:602
octave_map map_value() const
@ magic_colon_t
Definition ov.h:170
bool is_matrix_type() const
Definition ov.h:745
bool is_double_type() const
Definition ov.h:693
bool is_cs_list() const
Definition ov.h:668
octave_user_function * user_function_value(bool silent=false) const
bool is_user_code() const
Definition ov.h:784
std::string xstring_value(const char *fmt,...) const
bool isstruct() const
Definition ov.h:647
octave_user_code * user_code_value(bool silent=false) const
octave::range< double > range_value() const
Definition ov.h:992
bool isobject() const
Definition ov.h:662
dim_vector dims() const
Definition ov.h:539
int run()
std::map< std::string, octave_value > local_vars_map
octave_idx_type numel() const
Definition str-vec.h:98
static symbol_scope invalid()
Definition symscope.h:400
void set_parent(const symbol_scope &p)
Definition symscope.h:624
void cache_fcn_file_name(const std::string &name)
Definition symscope.h:636
void set_nesting_depth(std::size_t depth)
Definition symscope.h:440
void set_primary_parent(const symbol_scope &p)
Definition symscope.h:630
symbol_scope dup() const
Definition symscope.h:472
void cache_dir_name(const std::string &name)
Definition symscope.h:642
std::size_t nesting_depth() const
Definition symscope.h:446
octave_value find_scoped_function(const std::string &name, const symbol_scope &search_scope)
Definition symtab.cc:77
octave_value find_method(const std::string &name, const std::string &dispatch_type)
Definition symtab.cc:128
void clear_function(const std::string &name)
Definition symtab.cc:446
void clear_function_pattern(const std::string &pat)
Definition symtab.cc:452
void clear_functions(bool force=false)
Definition symtab.cc:437
void install_cmdline_function(const std::string &name, const octave_value &fcn)
Definition symtab.cc:339
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition symtab.cc:254
void clear_dld_function(const std::string &name)
Definition symtab.cc:501
octave_value fcn_table_find(const std::string &name, const octave_value_list &args=ovl(), const symbol_scope &search_scope=symbol_scope::invalid())
Definition symtab.cc:224
octave_value find_user_function(const std::string &name)
Definition symtab.cc:293
void clear_function_regexp(const std::string &pat)
Definition symtab.cc:468
tree_parameter_list * parameter_list() const
symbol_scope scope() const
tree_expression * expression() const
std::set< std::string > free_variables() const
tree_argument_list * left_hand_side()
Definition pt-loop.h:234
tree_statement_list * body()
Definition pt-loop.h:238
tree_expression * control_expr()
Definition pt-loop.h:236
tree_decl_init_list * initializer_list()
Definition pt-decl.h:236
tree_expression * expression()
Definition pt-decl.h:93
bool is_global() const
Definition pt-decl.h:84
tree_identifier * ident()
Definition pt-decl.h:89
bool is_persistent() const
Definition pt-decl.h:87
void accept(tree_walker &tw)
Definition pt-decl.h:196
tree_expression * condition()
Definition pt-loop.h:115
tree_statement_list * body()
Definition pt-loop.h:111
octave_value_list eval_string(const std::string &eval_str, bool silent, int &parse_status, int nargout)
Definition pt-eval.cc:1034
bool switch_case_label_matches(tree_switch_case *expr, const octave_value &val)
Definition pt-eval.cc:2469
octave_value_list execute_user_function(octave_user_function &user_function, int nargout, const octave_value_list &args)
Definition pt-eval.cc:3659
void visit_break_command(tree_break_command &)
Definition pt-eval.cc:1337
bool is_global(const std::string &name) const
Definition pt-eval.cc:1954
void visit_octave_user_function(octave_user_function &)
Definition pt-eval.cc:3835
void pop_stack_frame()
Definition pt-eval.cc:2534
void visit_unwind_protect_command(tree_unwind_protect_command &)
Definition pt-eval.cc:4405
bool mislocked(bool skip_first=false) const
Definition pt-eval.cc:2811
void bind_ans(const octave_value &val, bool print)
Definition pt-eval.cc:4556
void visit_return_command(tree_return_command &)
Definition pt-eval.cc:4005
octave_value_list execute_builtin_function(octave_builtin &builtin_function, int nargout, const octave_value_list &args)
Definition pt-eval.cc:3537
void clear_all(bool force=false)
Definition pt-eval.cc:2928
int max_recursion_depth() const
Definition pt-eval.h:602
void visit_statement_list(tree_statement_list &)
Definition pt-eval.cc:4146
void reset_debug_state()
Definition pt-eval.cc:1390
octave_value evaluate(tree_decl_elt *)
Definition pt-eval.cc:1877
void visit_anon_fcn_handle(tree_anon_fcn_handle &)
Definition pt-eval.cc:1271
octave_user_code * current_user_code() const
Definition pt-eval.cc:2600
void source_file(const std::string &file_name, const std::string &context="", bool verbose=false, bool require_file=true)
Definition pt-eval.cc:2069
symbol_scope get_current_scope() const
Definition pt-eval.cc:2771
void visit_cell(tree_cell &)
Definition pt-eval.cc:3947
octave_value echo(const octave_value_list &args, int nargout)
Definition pt-eval.cc:5022
octave_value_list evaluate_end_expression(const octave_value_list &args)
Definition pt-eval.cc:5171
void add_autoload(const std::string &fcn, const std::string &nm)
Definition pt-eval.cc:4785
std::list< frame_info > backtrace_info() const
Definition pt-eval.cc:2697
void visit_constant(tree_constant &)
Definition pt-eval.cc:3975
void display_call_stack() const
Definition pt-eval.cc:2828
octave_map empty_backtrace() const
Definition pt-eval.cc:2716
void visit_superclass_ref(tree_superclass_ref &)
Definition pt-eval.cc:4544
void visit_simple_assignment(tree_simple_assignment &)
Definition pt-eval.cc:4030
octave_value & global_varref(const std::string &name)
Definition pt-eval.cc:1998
octave_map backtrace() const
Definition pt-eval.cc:2710
void final_index_error(index_exception &ie, const tree_expression *expr)
Definition pt-eval.cc:4831
void visit_args_block_validation_list(tree_args_block_validation_list &)
Definition pt-eval.cc:1295
Matrix ignored_fcn_outputs() const
Definition pt-eval.cc:1482
void debug_where(std::ostream &os) const
Definition pt-eval.cc:2570
int current_line() const
Definition pt-eval.cc:2546
void clear_global_variables()
Definition pt-eval.cc:2922
void clear_global_variable(const std::string &name)
Definition pt-eval.cc:2904
std::string get_dispatch_class() const
Definition pt-eval.cc:2654
octave_value_list execute_mex_function(octave_mex_function &mex_function, int nargout, const octave_value_list &args)
Definition pt-eval.cc:3587
std::string inputname(int n, bool ids_only=true) const
Definition pt-eval.cc:1474
void set_dispatch_class(const std::string &class_name)
Definition pt-eval.cc:2660
void visit_boolean_expression(tree_boolean_expression &)
Definition pt-eval.cc:1325
bool goto_frame(std::size_t n=0, bool verbose=false)
Definition pt-eval.cc:2630
void visit_switch_case(tree_switch_case &)
Definition pt-eval.cc:4196
void munlock(bool skip_first=false) const
Definition pt-eval.cc:2794
void visit_arg_validation(tree_arg_validation &)
Definition pt-eval.cc:1301
octave_value get_auto_fcn_var(stack_frame::auto_var_type avt) const
Definition pt-eval.cc:2247
void remove_autoload(const std::string &fcn, const std::string &nm)
Definition pt-eval.cc:4792
void debug_list(std::ostream &os, int num_lines) const
Definition pt-eval.cc:2578
bool at_top_level() const
Definition pt-eval.cc:550
void visit_octave_user_function_header(octave_user_function &)
Definition pt-eval.cc:3842
void visit_arg_size_spec(tree_arg_size_spec &)
Definition pt-eval.cc:1307
void visit_multi_assignment(tree_multi_assignment &)
Definition pt-eval.cc:3953
void visit_continue_command(tree_continue_command &)
Definition pt-eval.cc:1364
octave_value find(const std::string &name)
Definition pt-eval.cc:2834
symbol_info_list top_scope_symbol_info() const
Definition pt-eval.cc:4716
void visit_while_command(tree_while_command &)
Definition pt-eval.cc:4460
void visit_do_until_command(tree_do_until_command &)
Definition pt-eval.cc:4503
octave_map get_autoload_map() const
Definition pt-eval.cc:4722
void visit_index_expression(tree_index_expression &)
Definition pt-eval.cc:3935
void visit_postfix_expression(tree_postfix_expression &)
Definition pt-eval.cc:3993
std::list< std::shared_ptr< stack_frame > > backtrace_frames() const
Definition pt-eval.cc:2684
std::list< std::string > variable_names() const
Definition pt-eval.cc:2989
void define_parameter_list_from_arg_vector(tree_parameter_list *param_list, const octave_value_list &args)
Definition pt-eval.cc:2254
bool is_local_variable(const std::string &name) const
Definition pt-eval.cc:1896
void visit_decl_command(tree_decl_command &)
Definition pt-eval.cc:3142
bool in_debug_repl() const
Definition pt-eval.cc:5150
void visit_arg_validation_fcns(tree_arg_validation_fcns &)
Definition pt-eval.cc:1313
void visit_function_def(tree_function_def &)
Definition pt-eval.cc:3854
symbol_scope get_top_scope() const
Definition pt-eval.cc:2765
void visit_switch_command(tree_switch_command &)
Definition pt-eval.cc:4208
int index_position() const
Definition pt-eval.h:762
void clear_symbol_pattern(const std::string &pattern)
Definition pt-eval.cc:2953
void clear_symbol(const std::string &name)
Definition pt-eval.cc:2941
bool in_user_code() const
Definition pt-eval.cc:3136
void visit_arguments_block(tree_arguments_block &)
Definition pt-eval.cc:1283
void dbquit(bool all=false)
Definition pt-eval.cc:5164
void keyboard(const std::string &prompt="debug> ")
Definition pt-eval.cc:1463
void restore_frame(std::size_t n)
Definition pt-eval.cc:2648
void clear_objects()
Definition pt-eval.cc:2859
void visit_if_command(tree_if_command &)
Definition pt-eval.cc:3888
bool is_class_method_executing(std::string &dispatch_class) const
Definition pt-eval.cc:2666
void visit_spmd_command(tree_spmd_command &)
Definition pt-eval.cc:3434
octave_value_list convert_to_const_vector(tree_argument_list *arg_list)
Definition pt-eval.cc:2363
void debug_type(std::ostream &os, int start_line, int end_line) const
Definition pt-eval.cc:2589
unwind_protect * curr_fcn_unwind_protect_frame()
Definition pt-eval.cc:2606
std::shared_ptr< stack_frame > pop_return_stack_frame()
Definition pt-eval.cc:2540
void visit_try_catch_command(tree_try_catch_command &)
Definition pt-eval.cc:4250
void visit_colon_expression(tree_colon_expression &)
Definition pt-eval.cc:1358
int server_loop()
Definition pt-eval.cc:892
int debug_user_code_line() const
Definition pt-eval.cc:2558
int returning() const
Definition pt-eval.h:796
void push_dummy_scope(const std::string &name)
Definition pt-eval.cc:2751
int echo() const
Definition pt-eval.h:835
void visit_simple_for_command(tree_simple_for_command &)
Definition pt-eval.cc:3228
std::shared_ptr< push_parser > get_parser()
Definition pt-eval.h:159
octave_value_list make_value_list(tree_argument_list *args, const string_vector &arg_nm)
Definition pt-eval.cc:4869
std::string backtrace_message() const
Definition pt-eval.cc:2722
void clear_variable(const std::string &name)
Definition pt-eval.cc:2868
void visit_matrix(tree_matrix &)
Definition pt-eval.cc:3941
bool is_variable(const std::string &name) const
Definition pt-eval.cc:1887
bool is_class_constructor_executing(std::string &dispatch_class) const
Definition pt-eval.cc:2672
void visit_octave_user_script(octave_user_script &)
Definition pt-eval.cc:3652
std::string lookup_autoload(const std::string &nm) const
Definition pt-eval.cc:4745
void visit_if_clause(tree_if_clause &)
Definition pt-eval.cc:3882
std::list< std::string > reverse_lookup_autoload(const std::string &nm) const
Definition pt-eval.cc:4773
std::size_t current_call_stack_frame_number() const
Definition pt-eval.h:646
void visit_args_block_attribute_list(tree_args_block_attribute_list &)
Definition pt-eval.cc:1289
std::size_t debug_frame() const
Definition pt-eval.h:637
octave_function * caller_function() const
Definition pt-eval.cc:2624
std::list< std::string > global_variable_names() const
Definition pt-eval.cc:2977
octave_value do_who(int argc, const string_vector &argv, bool return_list, bool verbose=false)
Definition pt-eval.cc:4862
void set_parser(const std::shared_ptr< push_parser > &parser)
Definition pt-eval.h:164
symbol_info_list get_symbol_info()
Definition pt-eval.cc:4710
symbol_info_list glob_symbol_info(const std::string &pattern) const
Definition pt-eval.cc:4698
bool silent_functions() const
Definition pt-eval.h:614
void clear_global_variable_pattern(const std::string &pattern)
Definition pt-eval.cc:2910
void visit_argument_list(tree_argument_list &)
Definition pt-eval.cc:1277
void pop_scope()
Definition pt-eval.cc:2759
octave_value_list convert_return_list_to_const_vector(tree_parameter_list *ret_list, int nargout, const Cell &varargout)
Definition pt-eval.cc:2393
void assign(const std::string &name, const octave_value &val=octave_value())
Definition pt-eval.cc:2024
void assignin(const std::string &context, const std::string &name, const octave_value &val=octave_value())
Definition pt-eval.cc:2033
void visit_statement(tree_statement &)
Definition pt-eval.cc:4036
char string_fill_char() const
Definition pt-eval.h:660
octave_value top_level_varval(const std::string &name) const
Definition pt-eval.cc:2011
void dbupdown(int n, bool verbose=false)
Definition pt-eval.cc:1469
std::shared_ptr< stack_frame > current_user_frame() const
Definition pt-eval.h:456
octave_value evaluate_anon_fcn_handle(tree_anon_fcn_handle &afh)
Definition pt-eval.cc:3445
void undefine_parameter_list(tree_parameter_list *param_list)
Definition pt-eval.cc:2283
octave_value max_stack_depth(const octave_value_list &args, int nargout)
Definition pt-eval.cc:2822
void visit_identifier(tree_identifier &)
Definition pt-eval.cc:3876
void clear_symbol_regexp(const std::string &pattern)
Definition pt-eval.cc:2965
void get_line_and_eval()
Definition pt-eval.cc:657
std::list< std::string > autoloaded_functions() const
Definition pt-eval.cc:4762
void visit_octave_user_function_trailer(octave_user_function &)
Definition pt-eval.cc:3848
int debug_user_code_column() const
Definition pt-eval.cc:2564
void push_echo_state(int type, const std::string &file_name, int pos=1)
Definition pt-eval.cc:4935
void visit_fcn_handle(tree_fcn_handle &)
Definition pt-eval.cc:3981
octave_value_list execute_user_script(octave_user_script &user_script, int nargout, const octave_value_list &args)
Definition pt-eval.cc:3609
void goto_base_frame()
Definition pt-eval.cc:2642
void eval(std::shared_ptr< tree_statement_list > &stmt_list, bool interactive)
Definition pt-eval.cc:1001
std::string whos_line_format() const
Definition pt-eval.h:625
octave_value_list evalin(const std::string &context, const std::string &try_code, int nargout)
Definition pt-eval.cc:1188
bool is_defined(const tree_expression *expr) const
Definition pt-eval.cc:1922
octave_value global_varval(const std::string &name) const
Definition pt-eval.cc:1992
int num_indices() const
Definition pt-eval.h:764
void top_level_assign(const std::string &name, const octave_value &val=octave_value())
Definition pt-eval.cc:2017
void install_variable(const std::string &name, const octave_value &value, bool global)
Definition pt-eval.cc:1981
void visit_binary_expression(tree_binary_expression &)
Definition pt-eval.cc:1319
symbol_info_list regexp_symbol_info(const std::string &pattern) const
Definition pt-eval.cc:4704
void set_auto_fcn_var(stack_frame::auto_var_type avt, const octave_value &val=octave_value())
Definition pt-eval.cc:2228
octave_user_code * debug_user_code() const
Definition pt-eval.cc:2612
bool eval_decl_elt(tree_decl_elt *elt)
Definition pt-eval.cc:2447
bool quiet_breakpoint_flag() const
Definition pt-eval.h:651
int breaking() const
Definition pt-eval.h:778
void clear_global_variable_regexp(const std::string &pattern)
Definition pt-eval.cc:2916
void visit_decl_elt(tree_decl_elt &)
Definition pt-eval.cc:3166
void parse_and_execute(const std::string &input, bool &incomplete_parse)
Definition pt-eval.cc:592
void visit_parameter_list(tree_parameter_list &)
Definition pt-eval.cc:3987
std::list< std::string > top_level_variable_names() const
Definition pt-eval.cc:2983
std::list< octave_lvalue > make_lvalue_list(tree_argument_list *)
Definition pt-eval.cc:4924
int continuing() const
Definition pt-eval.h:787
int current_column() const
Definition pt-eval.cc:2552
void enter_debugger(const std::string &prompt="debug> ")
Definition pt-eval.cc:1405
void visit_complex_for_command(tree_complex_for_command &)
Definition pt-eval.cc:3358
octave_value whos_line_format(const octave_value_list &args, int nargout)
Definition pt-eval.cc:4806
octave_user_code * get_user_code(const std::string &fname="")
Definition pt-eval.cc:2999
void global_assign(const std::string &name, const octave_value &val=octave_value())
Definition pt-eval.cc:2004
std::string PS4() const
Definition pt-eval.h:712
octave_value make_fcn_handle(const std::string &nm)
Definition pt-eval.cc:1630
void mlock(bool skip_first=false) const
Definition pt-eval.cc:2777
void visit_metaclass_query(tree_metaclass_query &)
Definition pt-eval.cc:4550
void visit_compound_binary_expression(tree_compound_binary_expression &)
Definition pt-eval.cc:1331
void do_unwind_protect_cleanup_code(tree_statement_list *list)
Definition pt-eval.cc:4322
octave_value varval(const symbol_record &sym) const
Definition pt-eval.cc:1963
void visit_switch_case_list(tree_switch_case_list &)
Definition pt-eval.cc:4202
int dbstep_flag() const
Definition pt-eval.h:805
void push_stack_frame(const symbol_scope &scope)
Definition pt-eval.cc:2501
std::string mfilename(const std::string &opt="") const
Definition pt-eval.cc:556
void visit_prefix_expression(tree_prefix_expression &)
Definition pt-eval.cc:3999
void clear_variable_regexp(const std::string &pattern)
Definition pt-eval.cc:2886
void visit_no_op_command(tree_no_op_command &)
Definition pt-eval.cc:3959
octave_function * current_function(bool skip_first=false) const
Definition pt-eval.cc:2618
void goto_caller_frame()
Definition pt-eval.cc:2636
bool statement_printing_enabled()
Definition pt-eval.cc:1383
void set_nargin(int nargin)
Definition pt-eval.cc:2235
void clear_variable_pattern(const std::string &pattern)
Definition pt-eval.cc:2877
std::string current_function_name(bool skip_first=false) const
Definition pt-eval.cc:3125
void clear_variables()
Definition pt-eval.cc:2895
void set_nargout(int nargout)
Definition pt-eval.cc:2241
void visit_if_command_list(tree_if_command_list &)
Definition pt-eval.cc:3909
virtual octave_value evaluate(tree_evaluator &tw, int nargout=1)=0
virtual bool is_identifier() const
Definition pt-exp.h:68
bool print_result() const
Definition pt-exp.h:107
tree_expression * set_print_flag(bool print)
Definition pt-exp.h:136
virtual std::string name() const
Definition pt-exp.h:114
virtual tree_expression * dup(symbol_scope &scope) const =0
virtual bool is_assignment_expression() const
Definition pt-exp.h:72
virtual octave_lvalue lvalue(tree_evaluator &)
Definition pt-exp.cc:43
virtual octave_value_list evaluate_n(tree_evaluator &tw, int nargout=1)=0
octave_value function()
Definition pt-cmd.h:159
virtual bool is_black_hole() const
Definition pt-id.h:79
symbol_record symbol() const
Definition pt-id.h:114
octave_lvalue lvalue(tree_evaluator &tw)
Definition pt-id.cc:68
octave_value evaluate(tree_evaluator &tw, int nargout=1)
Definition pt-id.h:100
void accept(tree_walker &tw)
Definition pt-select.h:156
tree_if_command_list * cmd_list()
Definition pt-select.h:186
bool is_end_of_fcn_or_script() const
Definition pt-cmd.h:99
bool takes_varargs() const
Definition pt-misc.h:96
tree_parameter_list * dup(symbol_scope &scope) const
Definition pt-misc.cc:69
bool varargs_only()
Definition pt-misc.h:98
tree_expression * left_hand_side()
Definition pt-loop.h:165
tree_expression * control_expr()
Definition pt-loop.h:167
tree_statement_list * body()
Definition pt-loop.h:173
tree_statement_list * body()
Definition pt-spmd.h:61
void accept(tree_walker &tw)
Definition pt-stmt.h:230
tree_command * command()
Definition pt-stmt.h:103
bool is_active_breakpoint(tree_evaluator &tw) const
Definition pt-stmt.cc:102
tree_expression * expression()
Definition pt-stmt.h:105
int column() const
Definition pt-stmt.cc:159
bool is_expression() const
Definition pt-stmt.h:78
void accept(tree_walker &tw)
Definition pt-stmt.h:124
int line() const
Definition pt-stmt.cc:151
bool is_end_of_fcn_or_script() const
Definition pt-stmt.cc:175
tree_expression * case_label()
Definition pt-select.h:233
tree_switch_case_list * case_list()
Definition pt-select.h:337
tree_expression * switch_value()
Definition pt-select.h:335
tree_identifier * identifier()
Definition pt-except.h:66
tree_statement_list * cleanup()
Definition pt-except.h:68
tree_statement_list * body()
Definition pt-except.h:62
tree_statement_list * cleanup()
Definition pt-except.h:121
tree_statement_list * body()
Definition pt-except.h:117
tree_statement_list * body()
Definition pt-loop.h:67
tree_expression * condition()
Definition pt-loop.h:65
virtual int line() const
Definition pt.cc:45
bool is_active_breakpoint(tree_evaluator &tw) const
Definition pt.h:87
virtual int column() const
Definition pt.cc:51
virtual void accept(tree_walker &tw)=0
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition defun.h:111
void interpreter_try(unwind_protect &frame)
Definition error.cc:2311
void error_with_id(const char *id, const char *fmt,...)
Definition error.cc:1053
void warning(const char *fmt,...)
Definition error.cc:1083
void warning_with_id(const char *id, const char *fmt,...)
Definition error.cc:1098
void error(const char *fmt,...)
Definition error.cc:1008
void err_indexed_cs_list()
Definition errwarn.cc:65
octave::sys::time Vlast_prompt_time
Definition input.cc:82
bool octave_completion_matches_called
Definition input.cc:85
bool iskeyword(const std::string &s)
Definition lex.cc:1351
octave_value_list call_mex(octave_mex_function &mex_fcn, const octave_value_list &args, int nargout_arg)
Definition mxarray.cc:3459
octave_value parse_fcn_file(interpreter &interp, const std::string &full_file, const std::string &file, const std::string &dir_name, const std::string &dispatch_type, const std::string &package_name, bool require_file, bool force_script, bool autoload, bool relative_lookup)
int release_unreferenced_dynamic_libraries()
Definition oct-shlib.cc:72
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
#define octave_stdout
Definition pager.h:301
#define panic_if(cond)
Definition panic.h:57
std::atomic< int > octave_interrupt_state
Definition quit.cc:39
F77_RET_T const F77_DBLE const F77_DBLE * f
bool valid_identifier(const char *s)
Definition utils.cc:79
void sleep(double seconds, bool do_graphics_events)
Definition utils.cc:1577
std::string fcn_file_in_path(const std::string &name)
Definition utils.cc:749
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition variables.cc:583
F77_RET_T len
Definition xerbla.cc:61