GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
stack-frame.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-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 (octave_stack_frame_h)
27 #define octave_stack_frame_h 1
28 
29 #include "octave-config.h"
30 
31 #include <deque>
32 #include <iosfwd>
33 #include <list>
34 #include <map>
35 #include <memory>
36 #include <string>
37 
38 class octave_value;
39 class octave_value_list;
40 
41 #include "error.h"
42 #include "ov-fcn.h"
43 #include "ov-usr-fcn.h"
44 #include "syminfo.h"
45 #include "symscope.h"
46 
47 // Variable values are stored in the stack_frame objects that make up
48 // the call_stack. There are four separate stack_frame objects
49 // corresponding to the following language elements:
50 //
51 // * user-defined functions
52 //
53 // These are .m files. They have local variables.
54 //
55 // * scripts
56 //
57 // These are .m files, but not functions. They access variables,
58 // but do not store any values directly. All values are stored in
59 // the stack frame corresponding to the scope in which they are
60 // executed.
61 //
62 // * scopes that do not correspond to functions
63 //
64 // This is primarily used by the top-level scope but the
65 // interpreter may also create temporary scopes in which to
66 // evaluate functions or scripts.
67 //
68 // * compiled functions
69 //
70 // These are built-in functions and dynamically-loaded compiled
71 // functions (.mex and .oct files) and do not contain variable
72 // values of their own. They are skipped when Octave displays a
73 // stack trace.
74 //
75 // All stack frames also contain the following data:
76 //
77 // * a reference to the evaluator that contains the frame
78 //
79 // Global variables are now stored in the evaluator and this link
80 // gives us immediate access to them.
81 //
82 // * line and column in the source file where the stack frame was created
83 //
84 // These values are used to print stack traces.
85 //
86 // * A pointer to the nearest parent frame that contains variable
87 // info (the "static" link)
88 //
89 // A frame that contains variable info may be a user-defined
90 // function, script, or scope frame. This pointer should never
91 // point to a compiled function stack frame.
92 //
93 // * A pointer to the nearest lexical parent frame (the "access" link)
94 //
95 // Used to access non-local variables for nested and anonymous
96 // functions or as a link to the parent frame in which a script is
97 // executed. This pointer should only point to a parent function
98 // stack frame.
99 
100 namespace octave
101 {
102  class tree_evaluator;
103  class symbol_info_list;
104  class unwind_protect;
105 
106  class stack_frame_walker;
107 
109  {
110  public:
111 
112  typedef std::map<std::string, octave_value> local_vars_map;
113 
114  // Markers indicating the type of a variable. Values for local
115  // variables are stored in the stack frame. Values for
116  // global variables are stored in the tree_evaluator object that
117  // contains the stack frame. Values for persistent variables are
118  // stored in the function scope corresponding to the stack frame.
119 
121  {
124  PERSISTENT
125  };
126 
127  // Index into the list of automatic variables for user-defined
128  // function stack frames.
129 
131  {
138  };
139 
140  stack_frame (void) = delete;
141 
143  const std::shared_ptr<stack_frame>& parent_link,
144  const std::shared_ptr<stack_frame>& static_link,
145  const std::shared_ptr<stack_frame>& access_link)
146  : m_evaluator (tw), m_line (-1), m_column (-1), m_index (index),
149  { }
150 
151  // Compiled function.
152  static stack_frame *
153  create (tree_evaluator& tw, octave_function *fcn, size_t index,
154  const std::shared_ptr<stack_frame>& parent_link,
155  const std::shared_ptr<stack_frame>& static_link);
156 
157  // Script.
158  static stack_frame *
159  create (tree_evaluator& tw, octave_user_script *script, size_t index,
160  const std::shared_ptr<stack_frame>& parent_link,
161  const std::shared_ptr<stack_frame>& static_link);
162 
163  // User-defined function.
164  static stack_frame *
165  create (tree_evaluator& tw, octave_user_function *fcn, size_t index,
166  const std::shared_ptr<stack_frame>& parent_link,
167  const std::shared_ptr<stack_frame>& static_link,
168  const std::shared_ptr<stack_frame>& access_link = std::shared_ptr<stack_frame> ());
169 
170  // Anonymous user-defined function with init vars.
171  static stack_frame *
172  create (tree_evaluator& tw, octave_user_function *fcn, size_t index,
173  const std::shared_ptr<stack_frame>& parent_link,
174  const std::shared_ptr<stack_frame>& static_link,
175  const local_vars_map& local_vars);
176 
177  // Scope.
178  static stack_frame *
179  create (tree_evaluator& tw, const symbol_scope& scope, size_t index,
180  const std::shared_ptr<stack_frame>& parent_link,
181  const std::shared_ptr<stack_frame>& static_link);
182 
183  stack_frame (const stack_frame& elt) = default;
184 
185  stack_frame& operator = (const stack_frame& elt) = delete;
186 
187  virtual ~stack_frame (void) = default;
188 
189  // FIXME: It would be nice to eliminate these but there are a few
190  // places where we still need to know the specific type of the
191  // stack frame that we are handling.
192 
193  virtual bool is_compiled_fcn_frame (void) const { return false; }
194  virtual bool is_user_script_frame (void) const { return false; }
195  virtual bool is_user_fcn_frame (void) const { return false; }
196  virtual bool is_scope_frame (void) const { return false; }
197 
198  virtual void clear_values (void);
199 
200  size_t index (void) const { return m_index; }
201 
202  void line (int l) { m_line = l; }
203  int line (void) const { return m_line; }
204 
205  void column (int c) { m_column = c; }
206  int column (void) const { return m_column; }
207 
208  std::string fcn_file_name (void) const
209  {
210  octave_function *fcn = function ();
211 
212  return fcn ? fcn->fcn_file_name () : "";
213  }
214 
215  std::string fcn_name (bool print_subfn = true) const
216  {
217  std::string retval;
218 
219  octave_function *fcn = function ();
220 
221  if (fcn)
222  {
223  std::string parent_fcn_name = fcn->parent_fcn_name ();
224 
225  if (print_subfn && ! parent_fcn_name.empty ())
226  retval = parent_fcn_name + '>';
227 
228  if (fcn->is_anonymous_function ())
229  retval += "@<anonymous>";
230  else
231  retval += fcn->name ();
232  }
233  else
234  retval = "<unknown>";
235 
236  return retval;
237  }
238 
239  virtual symbol_scope get_scope (void) const = 0;
240 
241  virtual octave_function * function (void) const { return nullptr; }
242 
243  virtual unwind_protect * unwind_protect_frame (void) { return nullptr; }
244 
246  make_symbol_info_list (const std::list<symbol_record>& symrec_list) const;
247 
248  octave_value who (const string_vector& patterns, bool have_regexp,
249  bool return_list, bool verbose,
250  const std::string& whos_line_fmt,
251  const std::string& msg);
252 
254 
255  octave_value workspace (void);
256 
257  std::list<std::string> variable_names (void) const;
258 
259  // Look for named symbol visible from current scope. Don't
260  // attempt to insert if missing.
261  virtual symbol_record lookup_symbol (const std::string&) const = 0;
262 
263  // Look for named symbol visible from current scope. Attempt to
264  // insert if missing.
265  virtual symbol_record insert_symbol (const std::string&) = 0;
266 
267  symbol_info_list glob_symbol_info (const std::string& pattern);
268 
269  symbol_info_list regexp_symbol_info (const std::string& pattern);
270 
272  {
273  return all_variables ();
274  }
275 
276  void make_persistent (const symbol_record& sym)
277  {
278  if (sym.is_formal ())
279  {
280  std::string nm = sym.name ();
281  error ("can't make function parameter %s persistent", nm.c_str ());
282  }
283 
284  if (is_global (sym))
285  {
286  std::string nm = sym.name ();
287  error ("can't make global variable '%s' persistent", nm.c_str ());
288  }
289 
290  install_variable (sym, octave_value (), false);
291 
292  mark_persistent (sym);
293  }
294 
295  void make_global (const symbol_record& sym)
296  {
297  if (is_persistent (sym))
298  {
299  std::string nm = sym.name ();
300  error ("can't make persistent variable '%s' global", nm.c_str ());
301  }
302 
303  install_variable (sym, octave_value (), true);
304 
305  mark_global (sym);
306  }
307 
308  std::shared_ptr<stack_frame>
309  parent_link (void) const {return m_parent_link; }
310 
311  std::shared_ptr<stack_frame>
312  static_link (void) const {return m_static_link; }
313 
314  std::shared_ptr<stack_frame>
315  access_link (void) const {return m_access_link; }
316 
317  virtual size_t size (void) const;
318 
319  virtual void resize (size_t);
320 
321  void mark_global (const symbol_record& sym)
322  {
323  mark_scope (sym, GLOBAL);
324  }
325 
326  void unmark_global (const symbol_record& sym)
327  {
328  mark_scope (sym, LOCAL);
329  }
330 
331  void mark_persistent (const symbol_record& sym)
332  {
333  mark_scope (sym, PERSISTENT);
334  }
335 
337  {
338  mark_scope (sym, LOCAL);
339  }
340 
341  bool is_defined (const symbol_record& sym) const
342  {
343  octave_value val = varval (sym);
344 
345  return val.is_defined ();
346  }
347 
348  bool is_variable (const symbol_record& sym) const
349  {
350  octave_value val = varval (sym);
351 
352  return val.is_defined ();
353  }
354 
355  bool is_variable (const std::string& name) const
356  {
358 
359  return sym ? is_variable (sym) : false;
360  }
361 
362  bool is_local_variable (const std::string& name) const
363  {
365 
366  return sym ? (is_variable (sym) && ! is_global (sym)) : false;
367  }
368 
369  bool is_object (const symbol_record& sym) const
370  {
371  octave_value val = varval (sym);
372 
373  return val.isobject ();
374  }
375 
376  bool is_object (const std::string& name) const
377  {
379 
380  return sym ? is_object (sym) : false;
381  }
382 
383  virtual scope_flags scope_flag (const symbol_record&) const = 0;
384 
385  virtual scope_flags get_scope_flag (size_t) const;
386 
387  virtual void set_scope_flag (size_t, scope_flags);
388 
389  bool is_global (const symbol_record& sym) const
390  {
391  return scope_flag (sym) == GLOBAL;
392  }
393 
394  bool is_global (const std::string& name) const
395  {
397 
398  return sym ? is_global (sym) : false;
399  }
400 
401  bool is_persistent (const symbol_record& sym) const
402  {
403  return scope_flag (sym) == PERSISTENT;
404  }
405 
406  bool is_persistent (const std::string& name) const
407  {
409 
410  return sym ? is_persistent (sym) : false;
411  }
412 
413  void install_variable (const symbol_record& sym,
414  const octave_value& value, bool global);
415 
416  void install_variable (const std::string& name,
417  const octave_value& value, bool global)
418  {
420 
421  install_variable (sym, value, global);
422  }
423 
425 
426  virtual void set_auto_fcn_var (auto_var_type, const octave_value&) = 0;
427 
428  virtual octave_value varval (const symbol_record& sym) const = 0;;
429 
430  virtual octave_value varval (size_t data_offset) const;
431 
432  octave_value varval (const std::string& name) const
433  {
435 
436  return sym ? varval (sym) : octave_value ();
437  }
438 
439  virtual octave_value& varref (const symbol_record& sym) = 0;
440 
441  virtual octave_value& varref (size_t data_offset);
442 
443  void assign (const symbol_record& sym, const octave_value& val)
444  {
445  octave_value& lhs = varref (sym);
446 
447  if (lhs.get_count () == 1)
448  lhs.call_object_destructor ();
449 
450  // Regularize a null matrix if stored into a variable.
451  lhs = val.storable_value ();
452  }
453 
454  void assign (const std::string& name, const octave_value& val)
455  {
457 
458  assign (sym, val);
459  }
460 
462  const std::string& type,
463  const std::list<octave_value_list>& idx,
464  const octave_value& rhs)
465  {
466  if (idx.empty ())
467  {
468  if (op == octave_value::op_asn_eq)
469  assign (sym, rhs);
470  else
471  varref (sym).assign (op, rhs);
472  }
473  else
474  varref (sym).assign (op, type, idx, rhs);
475  }
476 
478  const symbol_record& sym,
479  const std::string& type,
480  const std::list<octave_value_list>& idx)
481  {
482  if (idx.empty ())
483  varref (sym).do_non_const_unary_op (op);
484  else
485  varref (sym).do_non_const_unary_op (op, type, idx);
486  }
487 
488  octave_value value (const symbol_record& sym, const std::string& type,
489  const std::list<octave_value_list>& idx) const
490  {
491  octave_value retval = varval (sym);
492 
493  if (! idx.empty ())
494  {
495  if (retval.is_constant ())
496  retval = retval.subsref (type, idx);
497  else
498  {
499  octave_value_list t = retval.subsref (type, idx, 1);
500 
501  retval = t.length () > 0 ? t(0) : octave_value ();
502  }
503  }
504 
505  return retval;
506  }
507 
508  octave_value find_subfunction (const std::string& name) const
509  {
510  symbol_scope scope = get_scope ();
511 
512  return scope.find_subfunction (name);
513  }
514 
515  void clear (const symbol_record& sym)
516  {
517  if (is_global (sym))
518  unmark_global (sym);
519 
520  assign (sym, octave_value ());
521 
522  if (is_persistent (sym))
523  unmark_persistent (sym);
524  }
525 
526  void clear_objects (void);
527 
528  void clear_variable (const std::string& name);
529 
530  void clear_variable_pattern (const std::string& pattern);
531  void clear_variable_pattern (const string_vector& patterns);
532 
533  void clear_variable_regexp (const std::string& pattern);
534  void clear_variable_regexp (const string_vector& patterns);
535 
536  void clear_variables (void);
537 
538  std::string get_dispatch_class (void) const { return m_dispatch_class; }
539 
540  void set_dispatch_class (const std::string& class_name)
541  {
542  m_dispatch_class = class_name;
543  }
544 
545  void display_stopped_in_message (std::ostream& os) const;
546 
547  virtual void mark_scope (const symbol_record&, scope_flags) = 0;
548 
549  virtual void display (bool follow = true) const;
550 
551  virtual void accept (stack_frame_walker& sfw) = 0;
552 
553  protected:
554 
555  // Reference to the call stack that contains this frame. Global
556  // variables are stored in the call stack. This link gives us
557  // immediate access to them.
559 
560  // The line and column of the source file where this stack frame
561  // was created. Used to print stack traces.
562  int m_line;
563  int m_column;
564 
565  // Index in call stack.
566  size_t m_index;
567 
568  // Pointer to the nearest parent frame. May include compiled
569  // functions.
570  std::shared_ptr<stack_frame> m_parent_link;
571 
572  // Pointer to the nearest parent frame that contains variable
573  // information (script, function, or scope). This link skips over
574  // compiled function parent frames.
575  std::shared_ptr<stack_frame> m_static_link;
576 
577  // Pointer to the nearest lexical parent frame. Used to access
578  // non-local variables for nested and anonymous functions or as a
579  // link to the parent frame in which a script is executed.
580  std::shared_ptr<stack_frame> m_access_link;
581 
582  // Allow function handles to temporarily store their dispatch class
583  // in the call stack.
584  std::string m_dispatch_class;
585  };
586 }
587 
588 #endif
int column(void) const
Definition: stack-frame.h:206
bool is_persistent(const symbol_record &sym) const
Definition: stack-frame.h:401
void clear_variables(void)
bool is_local_variable(const std::string &name) const
Definition: stack-frame.h:362
octave_value value(const symbol_record &sym, const std::string &type, const std::list< octave_value_list > &idx) const
Definition: stack-frame.h:488
void clear_variable_regexp(const std::string &pattern)
octave_value who(const string_vector &patterns, bool have_regexp, bool return_list, bool verbose, const std::string &whos_line_fmt, const std::string &msg)
virtual symbol_scope get_scope(void) const =0
void assign(const symbol_record &sym, const octave_value &val)
Definition: stack-frame.h:443
virtual octave_value get_auto_fcn_var(auto_var_type) const =0
void do_non_const_unary_op(octave_value::unary_op op, const symbol_record &sym, const std::string &type, const std::list< octave_value_list > &idx)
Definition: stack-frame.h:477
void unmark_global(const symbol_record &sym)
Definition: stack-frame.h:326
std::shared_ptr< stack_frame > m_static_link
Definition: stack-frame.h:575
void make_global(const symbol_record &sym)
Definition: stack-frame.h:295
bool is_global(const symbol_record &sym) const
Definition: stack-frame.h:389
bool is_global(const std::string &name) const
Definition: stack-frame.h:394
symbol_info_list all_variables(void)
bool is_object(const std::string &name) const
Definition: stack-frame.h:376
stack_frame & operator=(const stack_frame &elt)=delete
symbol_info_list regexp_symbol_info(const std::string &pattern)
virtual void mark_scope(const symbol_record &, scope_flags)=0
int line(void) const
Definition: stack-frame.h:203
void clear_objects(void)
std::string m_dispatch_class
Definition: stack-frame.h:584
tree_evaluator & m_evaluator
Definition: stack-frame.h:558
virtual bool is_scope_frame(void) const
Definition: stack-frame.h:196
virtual scope_flags get_scope_flag(size_t) const
void clear_variable_pattern(const std::string &pattern)
virtual void set_scope_flag(size_t, scope_flags)
virtual void display(bool follow=true) const
symbol_info_list make_symbol_info_list(const std::list< symbol_record > &symrec_list) const
std::list< std::string > variable_names(void) const
std::shared_ptr< stack_frame > m_parent_link
Definition: stack-frame.h:570
virtual void set_auto_fcn_var(auto_var_type, const octave_value &)=0
virtual bool is_user_script_frame(void) const
Definition: stack-frame.h:194
std::string get_dispatch_class(void) const
Definition: stack-frame.h:538
std::shared_ptr< stack_frame > access_link(void) const
Definition: stack-frame.h:315
void clear_variable(const std::string &name)
size_t index(void) const
Definition: stack-frame.h:200
bool is_defined(const symbol_record &sym) const
Definition: stack-frame.h:341
void column(int c)
Definition: stack-frame.h:205
void install_variable(const std::string &name, const octave_value &value, bool global)
Definition: stack-frame.h:416
octave_value workspace(void)
virtual octave_value & varref(const symbol_record &sym)=0
std::shared_ptr< stack_frame > m_access_link
Definition: stack-frame.h:580
std::string fcn_name(bool print_subfn=true) const
Definition: stack-frame.h:215
virtual void clear_values(void)
void mark_global(const symbol_record &sym)
Definition: stack-frame.h:321
void assign(octave_value::assign_op op, const symbol_record &sym, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: stack-frame.h:461
std::shared_ptr< stack_frame > parent_link(void) const
Definition: stack-frame.h:309
bool is_variable(const symbol_record &sym) const
Definition: stack-frame.h:348
std::shared_ptr< stack_frame > static_link(void) const
Definition: stack-frame.h:312
virtual size_t size(void) const
virtual bool is_compiled_fcn_frame(void) const
Definition: stack-frame.h:193
void clear(const symbol_record &sym)
Definition: stack-frame.h:515
stack_frame(tree_evaluator &tw, size_t index, const std::shared_ptr< stack_frame > &parent_link, const std::shared_ptr< stack_frame > &static_link, const std::shared_ptr< stack_frame > &access_link)
Definition: stack-frame.h:142
void unmark_persistent(const symbol_record &sym)
Definition: stack-frame.h:336
std::string fcn_file_name(void) const
Definition: stack-frame.h:208
virtual ~stack_frame(void)=default
static stack_frame * create(tree_evaluator &tw, octave_function *fcn, size_t index, const std::shared_ptr< stack_frame > &parent_link, const std::shared_ptr< stack_frame > &static_link)
bool is_object(const symbol_record &sym) const
Definition: stack-frame.h:369
symbol_info_list glob_symbol_info(const std::string &pattern)
bool is_persistent(const std::string &name) const
Definition: stack-frame.h:406
void install_variable(const symbol_record &sym, const octave_value &value, bool global)
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
virtual scope_flags scope_flag(const symbol_record &) const =0
octave_value varval(const std::string &name) const
Definition: stack-frame.h:432
virtual symbol_record insert_symbol(const std::string &)=0
void make_persistent(const symbol_record &sym)
Definition: stack-frame.h:276
symbol_info_list get_symbol_info(void)
Definition: stack-frame.h:271
void mark_persistent(const symbol_record &sym)
Definition: stack-frame.h:331
void set_dispatch_class(const std::string &class_name)
Definition: stack-frame.h:540
virtual bool is_user_fcn_frame(void) const
Definition: stack-frame.h:195
virtual octave_value varval(const symbol_record &sym) const =0
virtual void accept(stack_frame_walker &sfw)=0
bool is_variable(const std::string &name) const
Definition: stack-frame.h:355
virtual symbol_record lookup_symbol(const std::string &) const =0
stack_frame(const stack_frame &elt)=default
void line(int l)
Definition: stack-frame.h:202
octave_value find_subfunction(const std::string &name) const
Definition: stack-frame.h:508
void assign(const std::string &name, const octave_value &val)
Definition: stack-frame.h:454
stack_frame(void)=delete
void display_stopped_in_message(std::ostream &os) const
virtual unwind_protect * unwind_protect_frame(void)
Definition: stack-frame.h:243
virtual void resize(size_t)
bool is_formal(void) const
Definition: symrec.h:190
std::string name(void) const
Definition: symrec.h:185
octave_value find_subfunction(const std::string &name) const
Definition: symscope.h:519
virtual bool is_anonymous_function(void) const
Definition: ov-base.h:463
virtual std::string fcn_file_name(void) const
Definition: ov-fcn.h:78
virtual std::string parent_fcn_name(void) const
Definition: ov-fcn.h:85
std::string name(void) const
Definition: ov-fcn.h:214
octave_idx_type length(void) const
Definition: ovl.h:113
octave_idx_type get_count(void) const
Definition: ov.h:399
unary_op
Definition: ov.h:83
void call_object_destructor(void)
Definition: ov.h:1360
bool is_defined(void) const
Definition: ov.h:551
assign_op
Definition: ov.h:138
@ op_asn_eq
Definition: ov.h:139
octave_value & do_non_const_unary_op(unary_op op)
Definition: ov.cc:2701
octave_value & assign(assign_op op, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
octave_value storable_value(void) const
bool isobject(void) const
Definition: ov.h:620
void error(const char *fmt,...)
Definition: error.cc:968
QString name
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811