GNU Octave 7.1.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-2022 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
38class octave_value;
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
100namespace 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 {
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_is_closure_context (false),
147 m_line (-1), m_column (-1), m_index (index),
150 { }
151
152 // Compiled function.
153 static stack_frame *
154 create (tree_evaluator& tw, octave_function *fcn, std::size_t index,
155 const std::shared_ptr<stack_frame>& parent_link,
156 const std::shared_ptr<stack_frame>& static_link);
157
158 // Script.
159 static stack_frame *
160 create (tree_evaluator& tw, octave_user_script *script, std::size_t index,
161 const std::shared_ptr<stack_frame>& parent_link,
162 const std::shared_ptr<stack_frame>& static_link);
163
164 // User-defined function.
165 static stack_frame *
166 create (tree_evaluator& tw, octave_user_function *fcn, std::size_t index,
167 const std::shared_ptr<stack_frame>& parent_link,
168 const std::shared_ptr<stack_frame>& static_link,
169 const std::shared_ptr<stack_frame>& access_link = std::shared_ptr<stack_frame> ());
170
171 // Anonymous user-defined function with init vars.
172 static stack_frame *
173 create (tree_evaluator& tw, octave_user_function *fcn, std::size_t index,
174 const std::shared_ptr<stack_frame>& parent_link,
175 const std::shared_ptr<stack_frame>& static_link,
176 const local_vars_map& local_vars,
177 const std::shared_ptr<stack_frame>& access_link = std::shared_ptr<stack_frame> ());
178
179 // Scope.
180 static stack_frame *
181 create (tree_evaluator& tw, const symbol_scope& scope, std::size_t index,
182 const std::shared_ptr<stack_frame>& parent_link,
183 const std::shared_ptr<stack_frame>& static_link);
184
185 stack_frame (const stack_frame& elt) = default;
186
187 stack_frame& operator = (const stack_frame& elt) = delete;
188
189 virtual ~stack_frame (void) = default;
190
191 // FIXME: It would be nice to eliminate these but there are a few
192 // places where we still need to know the specific type of the
193 // stack frame that we are handling.
194
195 virtual bool is_compiled_fcn_frame (void) const { return false; }
196 virtual bool is_user_script_frame (void) const { return false; }
197 virtual bool is_user_fcn_frame (void) const { return false; }
198 virtual bool is_scope_frame (void) const { return false; }
199
200 virtual void clear_values (void);
201
202 std::size_t index (void) const { return m_index; }
203
204 void line (int l) { m_line = l; }
205 int line (void) const { return m_line; }
206
207 void column (int c) { m_column = c; }
208 int column (void) const { return m_column; }
209
210 std::string fcn_file_name (void) const
211 {
212 octave_function *fcn = function ();
213
214 return fcn ? fcn->fcn_file_name () : "";
215 }
216
217 std::string fcn_name (bool print_subfn = true) const
218 {
219 std::string retval;
220
221 octave_function *fcn = function ();
222
223 if (fcn)
224 {
225 std::string parent_fcn_name = fcn->parent_fcn_name ();
226
227 if (print_subfn && ! parent_fcn_name.empty ())
228 retval = parent_fcn_name + '>';
229
230 if (fcn->is_anonymous_function ())
231 retval += "@<anonymous>";
232 else
233 retval += fcn->name ();
234 }
235 else
236 retval = "<unknown>";
237
238 return retval;
239 }
240
241 virtual symbol_scope get_scope (void) const = 0;
242
243 virtual octave_function * function (void) const { return nullptr; }
244
245 virtual unwind_protect * unwind_protect_frame (void) { return nullptr; }
246
248 make_symbol_info_list (const std::list<symbol_record>& symrec_list) const;
249
250 octave_value who (const string_vector& patterns, bool have_regexp,
251 bool return_list, bool verbose,
252 const std::string& whos_line_fmt,
253 const std::string& msg);
254
256
257 octave_value workspace (void);
258
259 std::list<std::string> variable_names (void) const;
260
261 // Look for named symbol visible from current scope. Don't
262 // attempt to insert if missing.
263 virtual symbol_record lookup_symbol (const std::string&) const = 0;
264
265 // Look for named symbol visible from current scope. Attempt to
266 // insert if missing.
267 virtual symbol_record insert_symbol (const std::string&) = 0;
268
269 symbol_info_list glob_symbol_info (const std::string& pattern);
270
271 symbol_info_list regexp_symbol_info (const std::string& pattern);
272
274 {
275 return all_variables ();
276 }
277
279 {
280 if (sym.is_formal ())
281 {
282 std::string nm = sym.name ();
283 error ("can't make function parameter %s persistent", nm.c_str ());
284 }
285
286 if (is_global (sym))
287 {
288 std::string nm = sym.name ();
289 error ("can't make global variable '%s' persistent", nm.c_str ());
290 }
291
292 install_variable (sym, octave_value (), false);
293
294 mark_persistent (sym);
295 }
296
297 void make_global (const symbol_record& sym)
298 {
299 if (is_persistent (sym))
300 {
301 std::string nm = sym.name ();
302 error ("can't make persistent variable '%s' global", nm.c_str ());
303 }
304
305 install_variable (sym, octave_value (), true);
306
307 mark_global (sym);
308 }
309
310 std::shared_ptr<stack_frame>
311 parent_link (void) const {return m_parent_link; }
312
313 std::shared_ptr<stack_frame>
314 static_link (void) const {return m_static_link; }
315
316 std::shared_ptr<stack_frame>
317 access_link (void) const {return m_access_link; }
318
319 virtual std::size_t size (void) const;
320
321 virtual void resize (std::size_t);
322
323 void mark_global (const symbol_record& sym)
324 {
325 mark_scope (sym, GLOBAL);
326 }
327
328 void unmark_global (const symbol_record& sym)
329 {
330 mark_scope (sym, LOCAL);
331 }
332
334 {
335 mark_scope (sym, PERSISTENT);
336 }
337
339 {
340 mark_scope (sym, LOCAL);
341 }
342
343 bool is_defined (const symbol_record& sym) const
345 octave_value val = varval (sym);
346
347 return val.is_defined ();
348 }
349
350 bool is_variable (const symbol_record& sym) const
351 {
352 octave_value val = varval (sym);
353
354 return val.is_defined ();
355 }
356
357 bool is_variable (const std::string& name) const
358 {
360
361 return sym ? is_variable (sym) : false;
362 }
363
364 bool is_local_variable (const std::string& name) const
365 {
367
368 return sym ? (is_variable (sym) && ! is_global (sym)) : false;
369 }
370
371 bool is_object (const symbol_record& sym) const
372 {
373 octave_value val = varval (sym);
374
375 return val.isobject ();
376 }
377
378 bool is_object (const std::string& name) const
379 {
381
382 return sym ? is_object (sym) : false;
383 }
384
385 virtual scope_flags scope_flag (const symbol_record&) const = 0;
386
387 virtual scope_flags get_scope_flag (std::size_t) const;
388
389 virtual void set_scope_flag (std::size_t, scope_flags);
390
391 bool is_global (const symbol_record& sym) const
392 {
393 return scope_flag (sym) == GLOBAL;
394 }
395
396 bool is_global (const std::string& name) const
397 {
399
400 return sym ? is_global (sym) : false;
401 }
402
403 bool is_persistent (const symbol_record& sym) const
404 {
405 return scope_flag (sym) == PERSISTENT;
406 }
407
408 bool is_persistent (const std::string& name) const
409 {
411
412 return sym ? is_persistent (sym) : false;
413 }
414
415 void install_variable (const symbol_record& sym,
416 const octave_value& value, bool global);
417
418 void install_variable (const std::string& name,
419 const octave_value& value, bool global)
420 {
422
423 install_variable (sym, value, global);
424 }
425
427
428 virtual void set_auto_fcn_var (auto_var_type, const octave_value&) = 0;
429
430 virtual octave_value varval (const symbol_record& sym) const = 0;;
431
432 virtual octave_value varval (std::size_t data_offset) const;
433
434 octave_value varval (const std::string& name) const
435 {
437
438 return sym ? varval (sym) : octave_value ();
439 }
440
441 virtual octave_value& varref (const symbol_record& sym) = 0;
442
443 virtual octave_value& varref (std::size_t data_offset);
444
445 void assign (const symbol_record& sym, const octave_value& val)
446 {
447 octave_value& lhs = varref (sym);
448
449 if (lhs.get_count () == 1)
451
452 // Regularize a null matrix if stored into a variable.
453 lhs = val.storable_value ();
454 }
455
456 void assign (const std::string& name, const octave_value& val)
457 {
459
460 assign (sym, val);
461 }
462
464 const std::string& type,
465 const std::list<octave_value_list>& idx,
466 const octave_value& rhs)
467 {
468 if (idx.empty ())
469 {
470 if (op == octave_value::op_asn_eq)
471 assign (sym, rhs);
472 else
473 varref (sym).assign (op, rhs);
474 }
475 else
476 varref (sym).assign (op, type, idx, rhs);
477 }
478
480 const symbol_record& sym,
481 const std::string& type,
482 const std::list<octave_value_list>& idx)
483 {
484 if (idx.empty ())
485 varref (sym).non_const_unary_op (op);
486 else
487 varref (sym).non_const_unary_op (op, type, idx);
488 }
489
490 octave_value value (const symbol_record& sym, const std::string& type,
491 const std::list<octave_value_list>& idx) const
492 {
493 octave_value retval = varval (sym);
494
495 if (! idx.empty ())
496 {
497 if (retval.is_constant ())
498 retval = retval.subsref (type, idx);
499 else
500 {
501 octave_value_list t = retval.subsref (type, idx, 1);
502
503 retval = t.length () > 0 ? t(0) : octave_value ();
504 }
505 }
506
507 return retval;
508 }
509
510 octave_value find_subfunction (const std::string& name) const
511 {
512 symbol_scope scope = get_scope ();
513
514 return scope.find_subfunction (name);
515 }
516
517 void clear (const symbol_record& sym)
518 {
519 if (is_global (sym))
520 unmark_global (sym);
521
522 assign (sym, octave_value ());
523
524 if (is_persistent (sym))
525 unmark_persistent (sym);
526 }
527
528 void clear_objects (void);
529
530 void clear_variable (const std::string& name);
531
532 void clear_variable_pattern (const std::string& pattern);
533 void clear_variable_pattern (const string_vector& patterns);
534
535 void clear_variable_regexp (const std::string& pattern);
536 void clear_variable_regexp (const string_vector& patterns);
537
538 void clear_variables (void);
539
540 std::string get_dispatch_class (void) const { return m_dispatch_class; }
541
542 void set_dispatch_class (const std::string& class_name)
543 {
544 m_dispatch_class = class_name;
545 }
546
547 void display_stopped_in_message (std::ostream& os) const;
548
549 virtual void mark_scope (const symbol_record&, scope_flags) = 0;
550
551 virtual void display (bool follow = true) const;
552
553 virtual void accept (stack_frame_walker& sfw) = 0;
554
555 virtual void break_closure_cycles (const std::shared_ptr<stack_frame>&) { }
556
558 bool is_closure_context (void) const { return m_is_closure_context; }
559
560 protected:
561
562 // Reference to the call stack that contains this frame. Global
563 // variables are stored in the call stack. This link gives us
564 // immediate access to them.
566
567 // TRUE if this stack frame is saved with a handle to a nested
568 // function (closure).
570
571 // The line and column of the source file where this stack frame
572 // was created. Used to print stack traces.
575
576 // Index in call stack.
577 std::size_t m_index;
578
579 // Pointer to the nearest parent frame. May include compiled
580 // functions.
581 std::shared_ptr<stack_frame> m_parent_link;
582
583 // Pointer to the nearest parent frame that contains variable
584 // information (script, function, or scope). This link skips over
585 // compiled function parent frames.
586 std::shared_ptr<stack_frame> m_static_link;
587
588 // Pointer to the nearest lexical parent frame. Used to access
589 // non-local variables for nested and anonymous functions or as a
590 // link to the parent frame in which a script is executed.
591 std::shared_ptr<stack_frame> m_access_link;
592
593 // Allow function handles to temporarily store their dispatch class
594 // in the call stack.
595 std::string m_dispatch_class;
596 };
597}
598
599#endif
int column(void) const
Definition: stack-frame.h:208
bool is_persistent(const symbol_record &sym) const
Definition: stack-frame.h:403
void mark_closure_context(void)
Definition: stack-frame.h:557
void clear_variables(void)
bool is_local_variable(const std::string &name) const
Definition: stack-frame.h:364
std::size_t index(void) const
Definition: stack-frame.h:202
octave_value value(const symbol_record &sym, const std::string &type, const std::list< octave_value_list > &idx) const
Definition: stack-frame.h:490
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)
bool is_closure_context(void) const
Definition: stack-frame.h:558
virtual symbol_scope get_scope(void) const =0
virtual scope_flags get_scope_flag(std::size_t) const
void assign(const symbol_record &sym, const octave_value &val)
Definition: stack-frame.h:445
stack_frame & operator=(const stack_frame &elt)=delete
virtual octave_value get_auto_fcn_var(auto_var_type) const =0
void unmark_global(const symbol_record &sym)
Definition: stack-frame.h:328
std::shared_ptr< stack_frame > m_static_link
Definition: stack-frame.h:586
std::shared_ptr< stack_frame > access_link(void) const
Definition: stack-frame.h:317
virtual void resize(std::size_t)
virtual octave_function * function(void) const
Definition: stack-frame.h:243
void make_global(const symbol_record &sym)
Definition: stack-frame.h:297
bool is_global(const symbol_record &sym) const
Definition: stack-frame.h:391
bool is_global(const std::string &name) const
Definition: stack-frame.h:396
symbol_info_list all_variables(void)
bool is_object(const std::string &name) const
Definition: stack-frame.h:378
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:205
void clear_objects(void)
std::string m_dispatch_class
Definition: stack-frame.h:595
tree_evaluator & m_evaluator
Definition: stack-frame.h:565
virtual void set_scope_flag(std::size_t, scope_flags)
virtual bool is_scope_frame(void) const
Definition: stack-frame.h:198
void clear_variable_pattern(const std::string &pattern)
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:581
virtual void set_auto_fcn_var(auto_var_type, const octave_value &)=0
std::shared_ptr< stack_frame > static_link(void) const
Definition: stack-frame.h:314
virtual bool is_user_script_frame(void) const
Definition: stack-frame.h:196
std::string get_dispatch_class(void) const
Definition: stack-frame.h:540
std::shared_ptr< stack_frame > parent_link(void) const
Definition: stack-frame.h:311
void clear_variable(const std::string &name)
bool is_defined(const symbol_record &sym) const
Definition: stack-frame.h:343
void column(int c)
Definition: stack-frame.h:207
void install_variable(const std::string &name, const octave_value &value, bool global)
Definition: stack-frame.h:418
octave_value workspace(void)
virtual unwind_protect * unwind_protect_frame(void)
Definition: stack-frame.h:245
std::shared_ptr< stack_frame > m_access_link
Definition: stack-frame.h:591
std::string fcn_name(bool print_subfn=true) const
Definition: stack-frame.h:217
virtual void break_closure_cycles(const std::shared_ptr< stack_frame > &)
Definition: stack-frame.h:555
virtual void clear_values(void)
virtual octave_value & varref(const symbol_record &sym)=0
virtual std::size_t size(void) const
void mark_global(const symbol_record &sym)
Definition: stack-frame.h:323
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:463
bool is_variable(const symbol_record &sym) const
Definition: stack-frame.h:350
static stack_frame * create(tree_evaluator &tw, octave_function *fcn, std::size_t index, const std::shared_ptr< stack_frame > &parent_link, const std::shared_ptr< stack_frame > &static_link)
virtual bool is_compiled_fcn_frame(void) const
Definition: stack-frame.h:195
void clear(const symbol_record &sym)
Definition: stack-frame.h:517
void unmark_persistent(const symbol_record &sym)
Definition: stack-frame.h:338
std::string fcn_file_name(void) const
Definition: stack-frame.h:210
virtual ~stack_frame(void)=default
stack_frame(tree_evaluator &tw, std::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
bool is_object(const symbol_record &sym) const
Definition: stack-frame.h:371
symbol_info_list glob_symbol_info(const std::string &pattern)
bool is_persistent(const std::string &name) const
Definition: stack-frame.h:408
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:434
std::size_t m_index
Definition: stack-frame.h:577
virtual symbol_record insert_symbol(const std::string &)=0
void make_persistent(const symbol_record &sym)
Definition: stack-frame.h:278
symbol_info_list get_symbol_info(void)
Definition: stack-frame.h:273
void mark_persistent(const symbol_record &sym)
Definition: stack-frame.h:333
void set_dispatch_class(const std::string &class_name)
Definition: stack-frame.h:542
virtual bool is_user_fcn_frame(void) const
Definition: stack-frame.h:197
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:357
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:204
octave_value find_subfunction(const std::string &name) const
Definition: stack-frame.h:510
void assign(const std::string &name, const octave_value &val)
Definition: stack-frame.h:456
stack_frame(void)=delete
void display_stopped_in_message(std::ostream &os) const
void 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:479
bool is_formal(void) const
Definition: symrec.h:212
std::string name(void) const
Definition: symrec.h:207
octave_value find_subfunction(const std::string &name) const
Definition: symscope.h:511
virtual bool is_anonymous_function(void) const
Definition: ov-base.h:499
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:207
octave_idx_type length(void) const
Definition: ovl.h:113
octave_idx_type get_count(void) const
Definition: ov.h:475
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:525
unary_op
Definition: ov.h:77
bool is_constant(void) const
Definition: ov.h:810
void call_object_destructor(void)
Definition: ov.h:1558
OCTINTERP_API octave_value storable_value(void) const
bool is_defined(void) const
Definition: ov.h:637
assign_op
Definition: ov.h:132
@ op_asn_eq
Definition: ov.h:133
OCTINTERP_API octave_value & assign(assign_op op, const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
OCTINTERP_API octave_value & non_const_unary_op(unary_op op)
bool isobject(void) const
Definition: ov.h:709
void error(const char *fmt,...)
Definition: error.cc:980
QString name
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))