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