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