GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
stack-frame.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1995-2024 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 <iostream>
31 
32 #include "lo-regexp.h"
33 #include "str-vec.h"
34 
35 #include "defun.h"
36 #include "error.h"
37 #include "interpreter.h"
38 #include "interpreter-private.h"
39 #include "oct-map.h"
40 #include "ov.h"
41 #include "ov-fcn.h"
42 #include "ov-fcn-handle.h"
43 #include "ov-usr-fcn.h"
44 #include "pager.h"
45 #include "parse.h"
46 #include "pt-eval.h"
47 #include "stack-frame.h"
48 #include "syminfo.h"
49 #include "symrec.h"
50 #include "symscope.h"
51 #include "variables.h"
52 
54 
55 // FIXME: There should probably be a display method for the script,
56 // fcn, and scope objects and the script and function objects should
57 // be responsible for displaying the scopes they contain.
58 
59 static void display_scope (std::ostream& os, const symbol_scope& scope)
60 {
61  if (scope)
62  {
63  os << "scope: " << scope.name () << std::endl;
64 
65  if (scope.num_symbols () > 0)
66  {
67  os << "name (frame offset, data offset, storage class):"
68  << std::endl;
69 
70  std::list<symbol_record> symbols = scope.symbol_list ();
71 
72  for (auto& sym : symbols)
73  {
74  os << " " << sym.name () << " (" << sym.frame_offset ()
75  << ", " << sym.data_offset () << ", " << sym.storage_class ()
76  << ")" << std::endl;
77  }
78  }
79  }
80 }
81 
82 class compiled_fcn_stack_frame;
83 class script_stack_frame;
84 class user_fcn_stack_frame;
85 class scope_stack_frame;
86 
87 class stack_frame_walker
88 {
89 protected:
90 
91  stack_frame_walker () { }
92 
93  virtual ~stack_frame_walker () = default;
94 
95 public:
96 
97  OCTAVE_DISABLE_COPY_MOVE (stack_frame_walker)
98 
99  virtual void
100  visit_compiled_fcn_stack_frame (compiled_fcn_stack_frame&) = 0;
101 
102  virtual void
103  visit_script_stack_frame (script_stack_frame&) = 0;
104 
105  virtual void
106  visit_user_fcn_stack_frame (user_fcn_stack_frame&) = 0;
107 
108  virtual void
109  visit_scope_stack_frame (scope_stack_frame&) = 0;
110 };
111 
112 class compiled_fcn_stack_frame : public stack_frame
113 {
114 public:
115 
116  compiled_fcn_stack_frame () = delete;
117 
118  compiled_fcn_stack_frame (tree_evaluator& tw, octave_function *fcn,
119  std::size_t index,
120  const std::shared_ptr<stack_frame>& parent_link,
121  const std::shared_ptr<stack_frame>& static_link)
122  : stack_frame (tw, index, parent_link, static_link,
123  static_link->access_link ()),
124  m_fcn (fcn)
125  { }
126 
127  compiled_fcn_stack_frame (const compiled_fcn_stack_frame& elt) = default;
128 
129  compiled_fcn_stack_frame&
130  operator = (const compiled_fcn_stack_frame& elt) = delete;
131 
132  ~compiled_fcn_stack_frame () = default;
133 
134  bool is_compiled_fcn_frame () const { return true; }
135 
136  symbol_scope get_scope () const
137  {
138  return m_static_link->get_scope ();
139  }
140 
141  octave_function * function () const { return m_fcn; }
142 
143  symbol_record lookup_symbol (const std::string& name) const
144  {
145  return m_static_link->lookup_symbol (name);
146  }
147 
148  symbol_record insert_symbol (const std::string& name)
149  {
150  return m_static_link->insert_symbol (name);
151  }
152 
153  stack_frame::scope_flags scope_flag (const symbol_record& sym) const
154  {
155  // Look in closest stack frame that contains values (either the
156  // top scope, or a user-defined function or script).
157 
158  return m_static_link->scope_flag (sym);
159  }
160 
161  void set_auto_fcn_var (auto_var_type avt, const octave_value& val)
162  {
163  m_static_link->set_auto_fcn_var (avt, val);
164  }
165 
166  octave_value get_auto_fcn_var (auto_var_type avt) const
167  {
168  return m_static_link->get_auto_fcn_var (avt);
169  }
170 
171  // We only need to override one of each of these functions. The
172  // using declaration will avoid warnings about partially-overloaded
173  // virtual functions.
174  using stack_frame::varval;
175  using stack_frame::varref;
176 
177  octave_value varval (const symbol_record& sym) const
178  {
179  // Look in closest stack frame that contains values (either the
180  // top scope, or a user-defined function or script).
181 
182  return m_static_link->varval (sym);
183  }
184 
185  octave_value& varref (const symbol_record& sym)
186  {
187  // Look in closest stack frame that contains values (either the
188  // top scope, or a user-defined function or script).
189 
190  return m_static_link->varref (sym);
191  }
192 
193  void mark_scope (const symbol_record& sym, scope_flags flag)
194  {
195  // Look in closest stack frame that contains values (either the
196  // top scope, or a user-defined function or script).
197 
198  m_static_link->mark_scope (sym, flag);
199  }
200 
201  void display (bool follow = true) const;
202 
203  void accept (stack_frame_walker& sfw);
204 
205 private:
206 
207  // Compiled function object associated with this stack frame.
208  // Should always be a built-in, .oct or .mex file function and
209  // should always be valid.
210  octave_function *m_fcn;
211 };
212 
213 // Scripts have a symbol_scope object to store the set of variables
214 // in the script, but values for those variables are stored in the
215 // stack frame corresponding to the nearest calling function or in
216 // the top-level scope (the evaluation stack frame).
217 //
218 // Accessing values in a scope requires a mapping from the index of
219 // the variable for the script scope to the list of values in the
220 // evaluation frame(s). The frame offset tells us how many access
221 // links we must follow to find the stack frame that holds the
222 // value. The value offset is the index into the vector of values
223 // in that stack frame that we should use to find the value.
224 //
225 // Frame and value offsets are set in this stack frame when it is
226 // created using information from the script and enclosing scopes.
227 //
228 // If a script is invoked in a nested function context, the frame
229 // offsets for individual values may be different. Some may be
230 // accessed from the invoking function and some may come from a
231 // parent function.
232 
233 class script_stack_frame : public stack_frame
234 {
235 public:
236 
237  script_stack_frame () = delete;
238 
239  script_stack_frame (tree_evaluator& tw, octave_user_script *script,
240  std::size_t index,
241  const std::shared_ptr<stack_frame>& parent_link,
242  const std::shared_ptr<stack_frame>& static_link);
243 
244  script_stack_frame (const script_stack_frame& elt) = default;
245 
246  script_stack_frame& operator = (const script_stack_frame& elt) = delete;
247 
248  ~script_stack_frame ()
249  {
250  delete m_unwind_protect_frame;
251  }
252 
253  bool is_user_script_frame () const { return true; }
254 
255  static std::shared_ptr<stack_frame>
256  get_access_link (const std::shared_ptr<stack_frame>& static_link);
257 
258  static std::size_t get_num_symbols (octave_user_script *script);
259 
260  void set_script_offsets ();
261 
262  void set_script_offsets_internal (const std::map<std::string,
263  symbol_record>& symbols);
264 
265  void resize_and_update_script_offsets (const symbol_record& sym);
266 
267  symbol_scope get_scope () const { return m_script->scope (); }
268 
269  octave_function * function () const { return m_script; }
270 
271  unwind_protect * unwind_protect_frame ();
272 
273  symbol_record lookup_symbol (const std::string& name) const;
274 
275  symbol_record insert_symbol (const std::string&);
276 
277  std::size_t size () const { return m_lexical_frame_offsets.size (); }
278 
279  void resize (std::size_t size)
280  {
281  m_lexical_frame_offsets.resize (size, 0);
282  m_value_offsets.resize (size, 0);
283  }
284 
285  void get_val_offsets_with_insert (const symbol_record& sym,
286  std::size_t& frame_offset,
287  std::size_t& data_offset);
288 
289  bool get_val_offsets_internal (const symbol_record& sym,
290  std::size_t& frame_offset,
291  std::size_t& data_offset) const;
292 
293  bool get_val_offsets (const symbol_record& sym, std::size_t& frame_offset,
294  std::size_t& data_offset) const;
295 
296  scope_flags scope_flag (const symbol_record& sym) const;
297 
298  void set_auto_fcn_var (auto_var_type avt, const octave_value& val)
299  {
300  m_access_link->set_auto_fcn_var (avt, val);
301  }
302 
303  octave_value get_auto_fcn_var (auto_var_type avt) const
304  {
305  return m_access_link->get_auto_fcn_var (avt);
306  }
307 
308  // We only need to override one of each of these functions. The
309  // using declaration will avoid warnings about partially-overloaded
310  // virtual functions.
311  using stack_frame::varval;
312  using stack_frame::varref;
313 
314  octave_value varval (const symbol_record& sym) const;
315 
316  octave_value& varref (const symbol_record& sym);
317 
318  void mark_scope (const symbol_record& sym, scope_flags flag);
319 
320  void display (bool follow = true) const;
321 
322  void accept (stack_frame_walker& sfw);
323 
324 private:
325 
326  // Script object associated with this stack frame. Should always
327  // be valid.
328  octave_user_script *m_script;
329 
330  // The nearest unwind protect frame that was active when this
331  // stack frame was created. Should always be valid.
332  unwind_protect *m_unwind_protect_frame;
333 
334  // Mapping between the symbols in the symbol_scope object of the
335  // script to the stack frame in which the script is executed. The
336  // frame offsets may be greater than one if the script is executed
337  // in a nested function context.
338 
339  std::vector<std::size_t> m_lexical_frame_offsets;
340  std::vector<std::size_t> m_value_offsets;
341 };
342 
343 // Base class for values and offsets shared by user_fcn and scope
344 // frames.
345 
346 class base_value_stack_frame : public stack_frame
347 {
348 public:
349 
350  base_value_stack_frame () = delete;
351 
352  base_value_stack_frame (tree_evaluator& tw, std::size_t num_symbols,
353  std::size_t index,
354  const std::shared_ptr<stack_frame>& parent_link,
355  const std::shared_ptr<stack_frame>& static_link,
356  const std::shared_ptr<stack_frame>& access_link)
357  : stack_frame (tw, index, parent_link, static_link, access_link),
358  m_values (num_symbols, octave_value ()),
359  m_flags (num_symbols, LOCAL),
360  m_auto_vars (NUM_AUTO_VARS, octave_value ())
361  { }
362 
363  base_value_stack_frame (const base_value_stack_frame& elt) = default;
364 
365  base_value_stack_frame&
366  operator = (const base_value_stack_frame& elt) = delete;
367 
368  ~base_value_stack_frame ()
369  {
370  // The C++ standard doesn't guarantee in which order the elements of a
371  // std::vector are destroyed. GNU libstdc++ and LLVM libc++ seem to
372  // destroy them in a different order. So, erase elements manually
373  // from first to last to be able to guarantee a destructor call order
374  // independent of the used STL, e.g., for classdef objects.
375 
376  // Member dtor order is last to first. So, m_auto_vars before m_values.
377 
378  for (auto auto_vars_iter = m_auto_vars.begin ();
379  auto_vars_iter != m_auto_vars.end ();)
380  auto_vars_iter = m_auto_vars.erase (auto_vars_iter);
381 
382  for (auto values_iter = m_values.begin ();
383  values_iter != m_values.end ();)
384  values_iter = m_values.erase (values_iter);
385  }
386 
387  std::size_t size () const
388  {
389  return m_values.size ();
390  }
391 
392  void resize (std::size_t size)
393  {
394  m_values.resize (size, octave_value ());
395  m_flags.resize (size, LOCAL);
396  }
397 
398  stack_frame::scope_flags get_scope_flag (std::size_t data_offset) const
399  {
400  return m_flags.at (data_offset);
401  }
402 
403  void set_scope_flag (std::size_t data_offset, scope_flags flag)
404  {
405  m_flags.at (data_offset) = flag;
406  }
407 
408  octave_value get_auto_fcn_var (auto_var_type avt) const
409  {
410  return m_auto_vars.at (avt);
411  }
412 
413  void set_auto_fcn_var (auto_var_type avt, const octave_value& val)
414  {
415  m_auto_vars.at (avt) = val;
416  }
417 
418  // We only need to override one of each of these functions. The
419  // using declaration will avoid warnings about partially-overloaded
420  // virtual functions.
421  using stack_frame::varval;
422  using stack_frame::varref;
423 
424  octave_value varval (std::size_t data_offset) const
425  {
426  return m_values.at (data_offset);
427  }
428 
429  octave_value& varref (std::size_t data_offset)
430  {
431  return m_values.at (data_offset);
432  }
433 
434  void display (bool follow = true) const;
435 
436 protected:
437 
438  // Variable values. This array is indexed by the data_offset
439  // value stored in the symbol_record objects of the scope
440  // associated with this stack frame.
441  std::vector<octave_value> m_values;
442 
443  // The type of each variable (local, global, persistent) of each
444  // value. This array is indexed by the data_offset value stored
445  // in the symbol_record objects of the scope associated with this
446  // stack frame. Local values are found in the M_VALUES array.
447  // Global values are stored in the tree_evaluator object that contains
448  // the stack frame. Persistent values are stored in the function
449  // scope corresponding to the stack frame.
450  std::vector<scope_flags> m_flags;
451 
452  // A fixed list of Automatic variables created for this function.
453  // The elements of this vector correspond to the auto_var_type
454  // enum.
455  std::vector<octave_value> m_auto_vars;
456 };
457 
458 // User-defined functions have a symbol_scope object to store the set
459 // of variables in the function and values are stored in the stack
460 // frame corresponding to the invocation of the function or one of
461 // its parents. The frame offset tells us how many access links we
462 // must follow to find the stack frame that holds the value. The
463 // value offset is the index into the vector of values in that stack
464 // frame that we should use to find the value.
465 //
466 // Frame and value offsets are determined when the corresponding
467 // function is parsed.
468 
469 class user_fcn_stack_frame : public base_value_stack_frame
470 {
471 public:
472 
473  user_fcn_stack_frame () = delete;
474 
475  user_fcn_stack_frame (tree_evaluator& tw, octave_user_function *fcn,
476  std::size_t index,
477  const std::shared_ptr<stack_frame>& parent_link,
478  const std::shared_ptr<stack_frame>& static_link,
479  const std::shared_ptr<stack_frame>& access_link = std::shared_ptr<stack_frame> ())
480  : base_value_stack_frame (tw, get_num_symbols (fcn), index,
481  parent_link, static_link,
482  (access_link
483  ? access_link
484  : get_access_link (fcn, static_link))),
485  m_fcn (fcn), m_unwind_protect_frame (nullptr)
486  { }
487 
488  user_fcn_stack_frame (tree_evaluator& tw, octave_user_function *fcn,
489  std::size_t index,
490  const std::shared_ptr<stack_frame>& parent_link,
491  const std::shared_ptr<stack_frame>& static_link,
492  const local_vars_map& local_vars,
493  const std::shared_ptr<stack_frame>& access_link = std::shared_ptr<stack_frame> ())
494  : base_value_stack_frame (tw, get_num_symbols (fcn), index,
495  parent_link, static_link,
496  (access_link
497  ? access_link
498  : get_access_link (fcn, static_link))),
499  m_fcn (fcn), m_unwind_protect_frame (nullptr)
500  {
501  // Initialize local variable values.
502 
503  for (const auto& nm_ov : local_vars)
504  assign (nm_ov.first, nm_ov.second);
505  }
506 
507  user_fcn_stack_frame (const user_fcn_stack_frame& elt) = default;
508 
509  user_fcn_stack_frame&
510  operator = (const user_fcn_stack_frame& elt) = delete;
511 
512  ~user_fcn_stack_frame ()
513  {
514  delete m_unwind_protect_frame;
515  }
516 
517  bool is_user_fcn_frame () const { return true; }
518 
519  static std::shared_ptr<stack_frame>
520  get_access_link (octave_user_function *fcn,
521  const std::shared_ptr<stack_frame>& static_link);
522 
523  static std::size_t get_num_symbols (octave_user_function *fcn)
524  {
525  symbol_scope fcn_scope = fcn->scope ();
526 
527  return fcn_scope.num_symbols ();
528  }
529 
530  void clear_values ();
531 
532  symbol_scope get_scope () const { return m_fcn->scope (); }
533 
534  octave_function * function () const { return m_fcn; }
535 
536  unwind_protect * unwind_protect_frame ();
537 
538  symbol_record lookup_symbol (const std::string& name) const;
539 
540  symbol_record insert_symbol (const std::string&);
541 
542  scope_flags scope_flag (const symbol_record& sym) const;
543 
544  // We only need to override one of each of these functions. The
545  // using declaration will avoid warnings about partially-overloaded
546  // virtual functions.
549 
550  octave_value varval (const symbol_record& sym) const;
551 
552  octave_value& varref (const symbol_record& sym);
553 
554  void mark_scope (const symbol_record& sym, scope_flags flag);
555 
556  void display (bool follow = true) const;
557 
558  void accept (stack_frame_walker& sfw);
559 
560  void break_closure_cycles (const std::shared_ptr<stack_frame>& frame);
561 
562 private:
563 
564  // User-defined object associated with this stack frame. Should
565  // always be valid.
566  octave_user_function *m_fcn;
567 
568  // The nearest unwind protect frame that was active when this
569  // stack frame was created. Should always be valid.
570  unwind_protect *m_unwind_protect_frame;
571 };
572 
573 // Pure scope stack frames (primarily the top-level workspace) have
574 // a set of variables and values are stored in the stack frame. All
575 // variable accesses are direct as there are no parent stack frames.
576 //
577 // Value offsets are determined when the corresponding variable is
578 // entered into the symbol_scope object corresponding to the frame.
579 
580 class scope_stack_frame : public base_value_stack_frame
581 {
582 public:
583 
584  scope_stack_frame () = delete;
585 
586  scope_stack_frame (tree_evaluator& tw, const symbol_scope& scope,
587  std::size_t index,
588  const std::shared_ptr<stack_frame>& parent_link,
589  const std::shared_ptr<stack_frame>& static_link)
590  : base_value_stack_frame (tw, scope.num_symbols (), index,
591  parent_link, static_link, nullptr),
592  m_scope (scope)
593  { }
594 
595  scope_stack_frame (const scope_stack_frame& elt) = default;
596 
597  scope_stack_frame& operator = (const scope_stack_frame& elt) = delete;
598 
599  ~scope_stack_frame () = default;
600 
601  bool is_scope_frame () const { return true; }
602 
603  symbol_scope get_scope () const { return m_scope; }
604 
605  symbol_record lookup_symbol (const std::string& name) const
606  {
607  return m_scope.lookup_symbol (name);
608  }
609 
610  symbol_record insert_symbol (const std::string&);
611 
612  scope_flags scope_flag (const symbol_record& sym) const;
613 
614  // We only need to override one of each of these functions. The
615  // using declaration will avoid warnings about partially-overloaded
616  // virtual functions.
619 
620  octave_value varval (const symbol_record& sym) const;
621 
622  octave_value& varref (const symbol_record& sym);
623 
624  void mark_scope (const symbol_record& sym, scope_flags flag);
625 
626  void display (bool follow = true) const;
627 
628  void accept (stack_frame_walker& sfw);
629 
630 private:
631 
632  // The scope object associated with this stack frame.
633  symbol_scope m_scope;
634 };
635 
636 class symbol_cleaner : public stack_frame_walker
637 {
638 public:
639 
640  symbol_cleaner (const std::string& pattern, bool have_regexp = false)
641  : stack_frame_walker (), m_patterns (pattern),
642  m_clear_all_names (false), m_clear_objects (false),
643  m_have_regexp (have_regexp), m_cleared_names ()
644  { }
645 
646  symbol_cleaner (const string_vector& patterns, bool have_regexp = false)
647  : stack_frame_walker (), m_patterns (patterns),
648  m_clear_all_names (false), m_clear_objects (false),
649  m_have_regexp (have_regexp), m_cleared_names ()
650  { }
651 
652  symbol_cleaner (bool clear_all_names = true, bool clear_objects = false)
653  : stack_frame_walker (), m_patterns (),
654  m_clear_all_names (clear_all_names), m_clear_objects (clear_objects),
655  m_have_regexp (false), m_cleared_names ()
656  { }
657 
658  OCTAVE_DISABLE_COPY_MOVE (symbol_cleaner)
659 
660  ~symbol_cleaner () = default;
661 
662  void visit_compiled_fcn_stack_frame (compiled_fcn_stack_frame& frame)
663  {
664  // This one follows static link always. Hmm, should the access
665  // link for a compiled_fcn_stack_frame be the same as the static
666  // link?
667 
668  std::shared_ptr<stack_frame> slink = frame.static_link ();
669 
670  if (slink)
671  slink->accept (*this);
672  }
673 
674  void visit_script_stack_frame (script_stack_frame& frame)
675  {
676  std::shared_ptr<stack_frame> alink = frame.access_link ();
677 
678  if (alink)
679  alink->accept (*this);
680  }
681 
682  void visit_user_fcn_stack_frame (user_fcn_stack_frame& frame)
683  {
684  clean_frame (frame);
685 
686  std::shared_ptr<stack_frame> alink = frame.access_link ();
687 
688  if (alink)
689  alink->accept (*this);
690  }
691 
692  void visit_scope_stack_frame (scope_stack_frame& frame)
693  {
694  clean_frame (frame);
695 
696  std::shared_ptr<stack_frame> alink = frame.access_link ();
697 
698  if (alink)
699  alink->accept (*this);
700  }
701 
702 private:
703 
704  void maybe_clear_symbol (stack_frame& frame, const symbol_record& sym)
705  {
706  std::string name = sym.name ();
707 
708  if (m_cleared_names.find (name) == m_cleared_names.end ())
709  {
710  // FIXME: Should we check that the name is defined and skip if
711  // it is not? Is it possible for another symbol with the same
712  // name to appear in a later stack frame?
713 
714  // FIXME: If we are clearing objects and a symbol is found,
715  // should we add it to the list of cleared names (since
716  // we did find a symbol) but skip clearing the object?
717 
718  if (m_clear_objects && ! frame.is_object (sym))
719  return;
720 
721  m_cleared_names.insert (name);
722 
723  frame.clear (sym);
724  }
725  }
726 
727  // FIXME: It would be nice to avoid the duplication in the following
728  // function.
729 
730  void clear_symbols (stack_frame& frame,
731  const std::list<symbol_record>& symbols)
732  {
733  if (m_clear_all_names)
734  {
735  for (const auto& sym : symbols)
736  maybe_clear_symbol (frame, sym);
737  }
738  else if (m_have_regexp)
739  {
740  octave_idx_type npatterns = m_patterns.numel ();
741 
742  for (octave_idx_type j = 0; j < npatterns; j++)
743  {
744  std::string pattern = m_patterns[j];
745 
746  regexp pat (pattern);
747 
748  for (const auto& sym : symbols)
749  {
750  if (pat.is_match (sym.name ()))
751  maybe_clear_symbol (frame, sym);
752  }
753  }
754  }
755  else
756  {
757  octave_idx_type npatterns = m_patterns.numel ();
758 
759  for (octave_idx_type j = 0; j < npatterns; j++)
760  {
761  std::string pattern = m_patterns[j];
762 
763  symbol_match pat (pattern);
764 
765  for (const auto& sym : symbols)
766  {
767  if (pat.match (sym.name ()))
768  maybe_clear_symbol (frame, sym);
769  }
770  }
771  }
772  }
773 
774  void clean_frame (stack_frame& frame)
775  {
776  symbol_scope scope = frame.get_scope ();
777 
778  std::list<symbol_record> symbols = scope.symbol_list ();
779 
780  if (m_clear_all_names || ! m_patterns.empty ())
781  clear_symbols (frame, symbols);
782  }
783 
784  string_vector m_patterns;
785 
786  bool m_clear_all_names;
787  bool m_clear_objects;
788  bool m_have_regexp;
789 
790  std::set<std::string> m_cleared_names;
791 };
792 
793 class symbol_info_accumulator : public stack_frame_walker
794 {
795 public:
796 
797  symbol_info_accumulator (const std::string& pattern,
798  bool have_regexp = false)
799  : stack_frame_walker (), m_patterns (pattern), m_match_all (false),
800  m_first_only (false), m_have_regexp (have_regexp), m_sym_inf_list (),
801  m_found_names ()
802  { }
803 
804  symbol_info_accumulator (const string_vector& patterns,
805  bool have_regexp = false)
806  : stack_frame_walker (), m_patterns (patterns), m_match_all (false),
807  m_first_only (false), m_have_regexp (have_regexp), m_sym_inf_list (),
808  m_found_names ()
809  { }
810 
811  symbol_info_accumulator (bool match_all = true, bool first_only = true)
812  : stack_frame_walker (), m_patterns (), m_match_all (match_all),
813  m_first_only (first_only), m_have_regexp (false),
814  m_sym_inf_list (), m_found_names ()
815  { }
816 
817  OCTAVE_DISABLE_COPY_MOVE (symbol_info_accumulator)
818 
819  ~symbol_info_accumulator () = default;
820 
821  bool is_empty () const
822  {
823  for (const auto& nm_sil : m_sym_inf_list)
824  {
825  const symbol_info_list& lst = nm_sil.second;
826 
827  if (! lst.empty ())
828  return false;
829  }
830 
831  return true;
832  }
833 
834  std::list<std::string> names () const
835  {
836  std::list<std::string> retval;
837 
838  for (const auto& nm_sil : m_sym_inf_list)
839  {
840  const symbol_info_list& lst = nm_sil.second;
841 
842  std::list<std::string> nm_list = lst.names ();
843 
844  for (const auto& nm : nm_list)
845  retval.push_back (nm);
846  }
847 
848  return retval;
849  }
850 
852  {
853  symbol_info_list retval;
854 
855  for (const auto& nm_sil : m_sym_inf_list)
856  {
857  const symbol_info_list& lst = nm_sil.second;
858 
859  for (const auto& syminf : lst)
860  retval.push_back (syminf);
861  }
862 
863  return retval;
864  }
865 
866  octave_map map_value () const
867  {
868  octave_map retval;
869 
870  // FIXME: is there a better way to concatenate structures?
871 
872  std::size_t n_frames = m_sym_inf_list.size ();
873 
874  OCTAVE_LOCAL_BUFFER (octave_map, map_list, n_frames);
875 
876  std::size_t j = 0;
877  for (const auto& nm_sil : m_sym_inf_list)
878  {
879  std::string scope_name = nm_sil.first;
880  const symbol_info_list& lst = nm_sil.second;
881 
882  map_list[j] = lst.map_value (scope_name, n_frames-j);
883 
884  j++;
885  }
886 
887  return octave_map::cat (-1, n_frames, map_list);
888  }
889 
890  void display (std::ostream& os, const std::string& format) const
891  {
892  for (const auto& nm_sil : m_sym_inf_list)
893  {
894  os << "\nvariables in scope: " << nm_sil.first << "\n\n";
895 
896  const symbol_info_list& lst = nm_sil.second;
897 
898  lst.display (os, format);
899  }
900  }
901 
902  void visit_compiled_fcn_stack_frame (compiled_fcn_stack_frame& frame)
903  {
904  // This one follows static link always. Hmm, should the access
905  // link for a compiled_fcn_stack_frame be the same as the static
906  // link?
907 
908  std::shared_ptr<stack_frame> slink = frame.static_link ();
909 
910  if (slink)
911  slink->accept (*this);
912  }
913 
914  void visit_script_stack_frame (script_stack_frame& frame)
915  {
916  std::shared_ptr<stack_frame> alink = frame.access_link ();
917 
918  if (alink)
919  alink->accept (*this);
920  }
921 
922  void visit_user_fcn_stack_frame (user_fcn_stack_frame& frame)
923  {
924  append_list (frame);
925 
926  std::shared_ptr<stack_frame> alink = frame.access_link ();
927 
928  if (alink)
929  alink->accept (*this);
930  }
931 
932  void visit_scope_stack_frame (scope_stack_frame& frame)
933  {
934  append_list (frame);
935 
936  std::shared_ptr<stack_frame> alink = frame.access_link ();
937 
938  if (alink)
939  alink->accept (*this);
940  }
941 
942 private:
943 
944  typedef std::pair<std::string, symbol_info_list> syminf_list_elt;
945 
946  // FIXME: the following is too complex and duplicates too much
947  // code. Maybe it should be split up so we have separate classes
948  // that do each job that is needed?
949 
950  std::list<symbol_record>
951  filter (stack_frame& frame, const std::list<symbol_record>& symbols)
952  {
953  std::list<symbol_record> new_symbols;
954 
955  if (m_match_all)
956  {
957  for (const auto& sym : symbols)
958  {
959  if (frame.is_defined (sym))
960  {
961  std::string name = sym.name ();
962 
963  if (m_first_only
964  && m_found_names.find (name) != m_found_names.end ())
965  continue;
966 
967  m_found_names.insert (name);
968 
969  new_symbols.push_back (sym);
970  }
971  }
972  }
973  else if (m_have_regexp)
974  {
975  octave_idx_type npatterns = m_patterns.numel ();
976 
977  for (octave_idx_type j = 0; j < npatterns; j++)
978  {
979  std::string pattern = m_patterns[j];
980 
981  regexp pat (pattern);
982 
983  for (const auto& sym : symbols)
984  {
985  std::string name = sym.name ();
986 
987  if (pat.is_match (name) && frame.is_defined (sym))
988  {
989  if (m_first_only
990  && m_found_names.find (name) != m_found_names.end ())
991  continue;
992 
993  m_found_names.insert (name);
994 
995  new_symbols.push_back (sym);
996  }
997  }
998  }
999  }
1000  else
1001  {
1002  octave_idx_type npatterns = m_patterns.numel ();
1003 
1004  for (octave_idx_type j = 0; j < npatterns; j++)
1005  {
1006  std::string pattern = m_patterns[j];
1007 
1008  symbol_match pat (pattern);
1009 
1010  for (const auto& sym : symbols)
1011  {
1012  std::string name = sym.name ();
1013 
1014  if (pat.match (name) && frame.is_defined (sym))
1015  {
1016  if (m_first_only
1017  && m_found_names.find (name) == m_found_names.end ())
1018  continue;
1019 
1020  m_found_names.insert (name);
1021 
1022  new_symbols.push_back (sym);
1023  }
1024  }
1025  }
1026  }
1027 
1028  return new_symbols;
1029  }
1030 
1031  void append_list (stack_frame& frame)
1032  {
1033  symbol_scope scope = frame.get_scope ();
1034 
1035  std::list<symbol_record> symbols = scope.symbol_list ();
1036 
1037  if (m_match_all || ! m_patterns.empty ())
1038  symbols = filter (frame, symbols);
1039 
1040  symbol_info_list syminf_list = frame.make_symbol_info_list (symbols);
1041 
1042  m_sym_inf_list.push_back (syminf_list_elt (scope.name (), syminf_list));
1043  }
1044 
1045  string_vector m_patterns;
1046 
1047  bool m_match_all;
1048  bool m_first_only;
1049  bool m_have_regexp;
1050 
1051  std::list<std::pair<std::string, symbol_info_list>> m_sym_inf_list;
1052 
1053  std::set<std::string> m_found_names;
1054 };
1055 
1056 stack_frame *
1058  std::size_t index,
1059  const std::shared_ptr<stack_frame>& parent_link,
1060  const std::shared_ptr<stack_frame>& static_link)
1061 {
1062  return new compiled_fcn_stack_frame (tw, fcn, index,
1064 }
1065 
1066 stack_frame *
1068  octave_user_script *script,
1069  std::size_t index,
1070  const std::shared_ptr<stack_frame>& parent_link,
1071  const std::shared_ptr<stack_frame>& static_link)
1072 {
1073  return new script_stack_frame (tw, script, index, parent_link, static_link);
1074 }
1075 
1076 stack_frame *
1078  octave_user_function *fcn, std::size_t index,
1079  const std::shared_ptr<stack_frame>& parent_link,
1080  const std::shared_ptr<stack_frame>& static_link,
1081  const std::shared_ptr<stack_frame>& access_link)
1082 {
1083  return new user_fcn_stack_frame (tw, fcn, index,
1085 }
1086 
1087 stack_frame *
1089  octave_user_function *fcn, std::size_t index,
1090  const std::shared_ptr<stack_frame>& parent_link,
1091  const std::shared_ptr<stack_frame>& static_link,
1092  const local_vars_map& local_vars,
1093  const std::shared_ptr<stack_frame>& access_link)
1094 {
1095  return new user_fcn_stack_frame (tw, fcn, index,
1096  parent_link, static_link, local_vars,
1097  access_link);
1098 }
1099 
1100 stack_frame *
1102  const symbol_scope& scope, std::size_t index,
1103  const std::shared_ptr<stack_frame>& parent_link,
1104  const std::shared_ptr<stack_frame>& static_link)
1105 {
1106  return new scope_stack_frame (tw, scope, index, parent_link, static_link);
1107 }
1108 
1109 // This function is only implemented and should only be called for
1110 // user_fcn stack frames. Anything else indicates an error in the
1111 // implementation, but we'll simply warn if that happens.
1112 
1113 void
1115 {
1116  warning ("invalid call to stack_frame::clear_values; please report");
1117 }
1118 
1120 stack_frame::make_symbol_info_list (const std::list<symbol_record>& symrec_list) const
1121 {
1122  symbol_info_list symbol_stats;
1123 
1124  for (const auto& sym : symrec_list)
1125  {
1126  octave_value value = varval (sym);
1127 
1128  if (! value.is_defined ()
1129  || (is_user_fcn_frame () && sym.frame_offset () > 0))
1130  continue;
1131 
1132  symbol_info syminf (sym.name (), value, sym.is_formal (),
1133  is_global (sym), is_persistent (sym));
1134 
1135  symbol_stats.append (syminf);
1136  }
1137 
1138  return symbol_stats;
1139 }
1140 
1143  bool have_regexp, bool return_list,
1144  bool verbose, const std::string& whos_line_fmt,
1145  const std::string& msg)
1146 {
1147  symbol_info_accumulator sym_inf_accum (patterns, have_regexp);
1148 
1149  accept (sym_inf_accum);
1150 
1151  if (return_list)
1152  {
1153  if (verbose)
1154  return sym_inf_accum.map_value ();
1155  else
1156  return Cell (string_vector (sym_inf_accum.names ()));
1157  }
1158  else if (! sym_inf_accum.is_empty ())
1159  {
1160 
1161  if (msg.empty ())
1162  octave_stdout << "Variables visible from the current scope:\n";
1163  else
1164  octave_stdout << msg;
1165 
1166  if (verbose)
1167  sym_inf_accum.display (octave_stdout, whos_line_fmt);
1168  else
1169  {
1170  octave_stdout << "\n";
1171  string_vector names (sym_inf_accum.names ());
1173  }
1174 
1175  octave_stdout << "\n";
1176  }
1177 
1178  return octave_value ();
1179 }
1180 
1181 // Return first occurrence of variables in current stack frame and any
1182 // parent frames reachable through access links.
1183 
1186 {
1187  symbol_info_accumulator sia (true, true);
1188 
1189  accept (sia);
1190 
1191  return sia.symbol_info ();
1192 }
1193 
1196 {
1197  std::list<octave_scalar_map> ws_list;
1198 
1199  stack_frame *frame = this;
1200 
1201  while (frame)
1202  {
1203  symbol_info_list symbols = frame->all_variables ();
1204 
1205  octave_scalar_map ws;
1206 
1207  for (const auto& sym_name : symbols.names ())
1208  {
1209  octave_value val = symbols.varval (sym_name);
1210 
1211  if (val.is_defined ())
1212  ws.assign (sym_name, val);
1213  }
1214 
1215  ws_list.push_back (ws);
1216 
1217  std::shared_ptr<stack_frame> nxt = frame->access_link ();
1218  frame = nxt.get ();
1219  }
1220 
1221  Cell ws_frames (ws_list.size (), 1);
1222 
1223  octave_idx_type i = 0;
1224  for (const auto& elt : ws_list)
1225  ws_frames(i++) = elt;
1226 
1227  return ws_frames;
1228 }
1229 
1230 // FIXME: Should this function also find any variables in parent
1231 // scopes accessible through access_links?
1232 
1233 std::list<std::string>
1235 {
1236  std::list<std::string> retval;
1237 
1238  symbol_scope scope = get_scope ();
1239 
1240  const std::map<std::string, symbol_record>& symbols = scope.symbols ();
1241 
1242  for (const auto& nm_sr : symbols)
1243  {
1244  if (is_variable (nm_sr.second))
1245  retval.push_back (nm_sr.first);
1246  }
1247 
1248  retval.sort ();
1249 
1250  return retval;
1251 }
1252 
1254 stack_frame::glob_symbol_info (const std::string& pattern)
1255 {
1256  symbol_info_accumulator sia (pattern, false);
1257 
1258  accept (sia);
1259 
1260  return sia.symbol_info ();
1261 }
1262 
1264 stack_frame::regexp_symbol_info (const std::string& pattern)
1265 {
1266  symbol_info_accumulator sia (pattern, true);
1267 
1268  accept (sia);
1269 
1270  return sia.symbol_info ();
1271 }
1272 
1273 std::size_t
1275 {
1276  // This function should only be called for user_fcn_stack_frame or
1277  // scope_stack_frame objects. Anything else indicates an error in
1278  // the implementation.
1279 
1280  panic_impossible ();
1281 }
1282 
1283 void
1284 stack_frame::resize (std::size_t)
1285 {
1286  // This function should only be called for user_fcn_stack_frame or
1287  // scope_stack_frame objects. Anything else indicates an error in
1288  // the implementation.
1289 
1290  panic_impossible ();
1291 }
1292 
1294 stack_frame::get_scope_flag (std::size_t) const
1295 {
1296  // This function should only be called for user_fcn_stack_frame or
1297  // scope_stack_frame objects. Anything else indicates an error in
1298  // the implementation.
1299 
1300  panic_impossible ();
1301 }
1302 
1303 void
1305 {
1306  // This function should only be called for user_fcn_stack_frame or
1307  // scope_stack_frame objects. Anything else indicates an error in
1308  // the implementation.
1309 
1310  panic_impossible ();
1311 }
1312 
1313 void
1315  const octave_value& value, bool global)
1316 {
1317  if (global && ! is_global (sym))
1318  {
1319  octave_value val = varval (sym);
1320 
1321  if (val.is_defined ())
1322  {
1323  std::string nm = sym.name ();
1324 
1325  warning_with_id ("Octave:global-local-conflict",
1326  "global: '%s' is defined in the current scope.\n",
1327  nm.c_str ());
1328  warning_with_id ("Octave:global-local-conflict",
1329  "global: in a future version, global variables must be declared before use.\n");
1330 
1331  // If the symbol is defined in the local but not the
1332  // global scope, then use the local value as the
1333  // initial value. This value will also override any
1334  // initializer in the global statement.
1335  octave_value global_val = m_evaluator.global_varval (nm);
1336 
1337  if (global_val.is_defined ())
1338  {
1339  warning_with_id ("Octave:global-local-conflict",
1340  "global: global value overrides existing local value");
1341 
1342  clear (sym);
1343  }
1344  else
1345  {
1346  warning_with_id ("Octave:global-local-conflict",
1347  "global: existing local value used to initialize global variable");
1348 
1349  m_evaluator.global_varref (nm) = val;
1350  }
1351  }
1352 
1353  mark_global (sym);
1354  }
1355 
1356  if (value.is_defined ())
1357  assign (sym, value);
1358 }
1359 
1361 stack_frame::varval (std::size_t) const
1362 {
1363  // This function should only be called for user_fcn_stack_frame or
1364  // scope_stack_frame objects. Anything else indicates an error in
1365  // the implementation.
1366 
1367  panic_impossible ();
1368 }
1369 
1370 octave_value&
1371 stack_frame::varref (std::size_t)
1372 {
1373  // This function should only be called for user_fcn_stack_frame or
1374  // scope_stack_frame objects. Anything else indicates an error in
1375  // the implementation.
1376 
1377  panic_impossible ();
1378 }
1379 
1380 void
1382 {
1383  symbol_cleaner sc (true, true);
1384 
1385  accept (sc);
1386 }
1387 
1388 void
1389 stack_frame::clear_variable (const std::string& name)
1390 {
1391  symbol_cleaner sc (name);
1392 
1393  accept (sc);
1394 }
1395 
1396 void
1397 stack_frame::clear_variable_pattern (const std::string& pattern)
1398 {
1399  symbol_cleaner sc (pattern);
1400 
1401  accept (sc);
1402 }
1403 
1404 void
1406 {
1407  symbol_cleaner sc (patterns);
1408 
1409  accept (sc);
1410 }
1411 
1412 void
1413 stack_frame::clear_variable_regexp (const std::string& pattern)
1414 {
1415  symbol_cleaner sc (pattern, true);
1416 
1417  accept (sc);
1418 }
1419 
1420 void
1422 {
1423  symbol_cleaner sc (patterns, true);
1424 
1425  accept (sc);
1426 }
1427 
1428 void
1430 {
1431  symbol_cleaner sc;
1432 
1433  accept (sc);
1434 }
1435 
1436 void
1438 {
1439  if (index () == 0)
1440  os << "at top level" << std::endl;
1441  else
1442  {
1443  os << "stopped in " << fcn_name ();
1444 
1445  int l = line ();
1446  if (l > 0)
1447  os << " at line " << line ();
1448 
1449  os << " [" << fcn_file_name () << "] " << std::endl;
1450  }
1451 }
1452 
1453 void
1454 stack_frame::display (bool follow) const
1455 {
1456  std::ostream& os = octave_stdout;
1457 
1458  os << "-- [stack_frame] (" << this << ") --" << std::endl;
1459 
1460  os << "parent link: ";
1461  if (m_parent_link)
1462  os << m_parent_link.get ();
1463  else
1464  os << "NULL";
1465  os << std::endl;
1466 
1467  os << "static link: ";
1468  if (m_static_link)
1469  os << m_static_link.get ();
1470  else
1471  os << "NULL";
1472  os << std::endl;
1473 
1474  os << "access link: ";
1475  if (m_access_link)
1476  os << m_access_link.get ();
1477  else
1478  os << "NULL";
1479  os << std::endl;
1480 
1481  os << "line: " << m_line << std::endl;
1482  os << "column: " << m_column << std::endl;
1483  os << "index: " << m_index << std::endl;
1484 
1485  os << std::endl;
1486 
1487  if (! follow)
1488  return;
1489 
1490  os << "FOLLOWING ACCESS LINKS:" << std::endl;
1491  std::shared_ptr<stack_frame> frm = access_link ();
1492  while (frm)
1493  {
1494  frm->display (false);
1495  os << std::endl;
1496 
1497  frm = frm->access_link ();
1498  }
1499 }
1500 
1501 void
1502 compiled_fcn_stack_frame::display (bool follow) const
1503 {
1504  std::ostream& os = octave_stdout;
1505 
1506  os << "-- [compiled_fcn_stack_frame] (" << this << ") --" << std::endl;
1507  stack_frame::display (follow);
1508 
1509  os << "fcn: " << m_fcn->name ()
1510  << " (" << m_fcn->type_name () << ")" << std::endl;
1511 }
1512 
1513 void
1514 compiled_fcn_stack_frame::accept (stack_frame_walker& sfw)
1515 {
1516  sfw.visit_compiled_fcn_stack_frame (*this);
1517 }
1518 
1519 script_stack_frame::script_stack_frame (tree_evaluator& tw,
1520  octave_user_script *script,
1521  std::size_t index,
1522  const std::shared_ptr<stack_frame>& parent_link,
1523  const std::shared_ptr<stack_frame>& static_link)
1524  : stack_frame (tw, index, parent_link, static_link,
1525  get_access_link (static_link)),
1526  m_script (script), m_unwind_protect_frame (nullptr),
1527  m_lexical_frame_offsets (get_num_symbols (script), 1),
1528  m_value_offsets (get_num_symbols (script), 0)
1529 {
1530  set_script_offsets ();
1531 }
1532 
1533 std::size_t
1534 script_stack_frame::get_num_symbols (octave_user_script *script)
1535 {
1536  symbol_scope script_scope = script->scope ();
1537 
1538  return script_scope.num_symbols ();
1539 }
1540 
1541 void
1542 script_stack_frame::set_script_offsets ()
1543 {
1544  // Set frame and data offsets inside stack frame based on enclosing
1545  // scope(s).
1546 
1547  symbol_scope script_scope = m_script->scope ();
1548 
1549  std::size_t num_script_symbols = script_scope.num_symbols ();
1550 
1551  resize (num_script_symbols);
1552 
1553  const std::map<std::string, symbol_record>& script_symbols
1554  = script_scope.symbols ();
1555 
1556  set_script_offsets_internal (script_symbols);
1557 }
1558 
1559 void script_stack_frame::set_script_offsets_internal
1560 (const std::map<std::string, symbol_record>& script_symbols)
1561 {
1562  // This scope will be used to evaluate the script. Find (or
1563  // possibly insert) symbols from the dummy script scope here.
1564 
1565  symbol_scope eval_scope = m_access_link->get_scope ();
1566 
1567  if (eval_scope.is_nested ())
1568  {
1569  bool found = false;
1570 
1571  for (const auto& nm_sr : script_symbols)
1572  {
1573  std::string name = nm_sr.first;
1574  symbol_record script_sr = nm_sr.second;
1575 
1576  symbol_scope parent_scope = eval_scope;
1577 
1578  std::size_t count = 1;
1579 
1580  while (parent_scope)
1581  {
1582  const std::map<std::string, symbol_record>& parent_scope_symbols
1583  = parent_scope.symbols ();
1584 
1585  auto p = parent_scope_symbols.find (name);
1586 
1587  if (p != parent_scope_symbols.end ())
1588  {
1589  found = true;
1590  symbol_record parent_scope_sr = p->second;
1591 
1592  std::size_t script_sr_data_offset = script_sr.data_offset ();
1593 
1594  m_lexical_frame_offsets.at (script_sr_data_offset)
1595  = parent_scope_sr.frame_offset () + count;
1596 
1597  m_value_offsets.at (script_sr_data_offset)
1598  = parent_scope_sr.data_offset ();
1599 
1600  break;
1601  }
1602  else
1603  {
1604  count++;
1605  parent_scope = parent_scope.parent_scope ();
1606  }
1607  }
1608 
1609  if (! found)
1610  error ("symbol '%s' cannot be added to static scope",
1611  name.c_str ());
1612  }
1613  }
1614  else
1615  {
1616  const std::map<std::string, symbol_record>& eval_scope_symbols
1617  = eval_scope.symbols ();
1618 
1619  for (const auto& nm_sr : script_symbols)
1620  {
1621  std::string name = nm_sr.first;
1622  symbol_record script_sr = nm_sr.second;
1623 
1624  auto p = eval_scope_symbols.find (name);
1625 
1626  symbol_record eval_scope_sr;
1627 
1628  if (p == eval_scope_symbols.end ())
1629  eval_scope_sr = eval_scope.insert (name);
1630  else
1631  eval_scope_sr = p->second;
1632 
1633  std::size_t script_sr_data_offset = script_sr.data_offset ();
1634 
1635  // The +1 is for going from the script frame to the eval
1636  // frame. Only one access_link should need to be followed.
1637 
1638  m_lexical_frame_offsets.at (script_sr_data_offset)
1639  = eval_scope_sr.frame_offset () + 1;
1640 
1641  m_value_offsets.at (script_sr_data_offset)
1642  = eval_scope_sr.data_offset ();
1643  }
1644  }
1645 }
1646 
1647 void
1648 script_stack_frame::resize_and_update_script_offsets (const symbol_record& sym)
1649 {
1650  std::size_t data_offset = sym.data_offset ();
1651 
1652  // This function is called when adding new symbols to a script
1653  // scope. If the symbol wasn't present before, it should be outside
1654  // the range so we need to resize then update offsets.
1655 
1656  panic_unless (data_offset >= size ());
1657 
1658  resize (data_offset+1);
1659 
1660  // FIXME: We should be able to avoid creating the map object and the
1661  // looping in the set_scripts_offsets_internal function. Can we do
1662  // that without (or with minimal) code duplication?
1663 
1664  std::map<std::string, symbol_record> tmp_symbols;
1665  tmp_symbols[sym.name ()] = sym;
1666  set_script_offsets_internal (tmp_symbols);
1667 }
1668 
1669 // If this is a nested scope, set access_link to nearest parent
1670 // stack frame that corresponds to the lexical parent of this scope.
1671 
1672 std::shared_ptr<stack_frame>
1673 script_stack_frame::get_access_link (const std::shared_ptr<stack_frame>& static_link)
1674 {
1675  // If this script is called from another script, set access
1676  // link to ultimate parent stack frame.
1677 
1678  std::shared_ptr<stack_frame> alink = static_link;
1679 
1680  while (alink->is_user_script_frame ())
1681  {
1682  if (alink->access_link ())
1683  alink = alink->access_link ();
1684  else
1685  break;
1686  }
1687 
1688  return alink;
1689 }
1690 
1692 script_stack_frame::unwind_protect_frame ()
1693 {
1694  if (! m_unwind_protect_frame)
1695  m_unwind_protect_frame = new unwind_protect ();
1696 
1697  return m_unwind_protect_frame;
1698 }
1699 
1701 script_stack_frame::lookup_symbol (const std::string& name) const
1702 {
1703  symbol_scope scope = get_scope ();
1704 
1705  symbol_record sym = scope.lookup_symbol (name);
1706 
1707  if (sym)
1708  {
1709  panic_unless (sym.frame_offset () == 0);
1710 
1711  return sym;
1712  }
1713 
1714  sym = m_access_link->lookup_symbol (name);
1715 
1716  // Return symbol record with adjusted frame offset.
1717  symbol_record new_sym = sym.dup ();
1718 
1719  new_sym.set_frame_offset (sym.frame_offset () + 1);
1720 
1721  return new_sym;
1722 }
1723 
1725 script_stack_frame::insert_symbol (const std::string& name)
1726 {
1727  // If the symbols is already in the immediate scope, there is
1728  // nothing more to do.
1729 
1730  symbol_scope scope = get_scope ();
1731 
1732  symbol_record sym = scope.lookup_symbol (name);
1733 
1734  if (sym)
1735  {
1736  // All symbol records in a script scope should have zero offset,
1737  // which means we redirect our lookup using
1738  // lexical_frame_offsets and values_offets.
1739  panic_unless (sym.frame_offset () == 0);
1740 
1741  return sym;
1742  }
1743 
1744  // Insert the symbol in the current scope then resize and update
1745  // offsets. This operation should never fail.
1746 
1747  sym = scope.find_symbol (name);
1748 
1749  panic_unless (sym.is_valid ());
1750 
1751  resize_and_update_script_offsets (sym);
1752 
1753  return sym;
1754 }
1755 
1756 // Similar to set_script_offsets_internal except that we only return
1757 // frame and data offsets for symbols found by name in parent scopes
1758 // instead of updating the offsets stored in the script frame itself.
1759 
1760 bool
1761 script_stack_frame::get_val_offsets_internal (const symbol_record& script_sr,
1762  std::size_t& frame_offset,
1763  std::size_t& data_offset) const
1764 {
1765  bool found = false;
1766 
1767  // This scope will be used to evaluate the script. Find symbols
1768  // here by name.
1769 
1770  symbol_scope eval_scope = m_access_link->get_scope ();
1771 
1772  if (eval_scope.is_nested ())
1773  {
1774  std::string name = script_sr.name ();
1775 
1776  symbol_scope parent_scope = eval_scope;
1777 
1778  std::size_t count = 1;
1779 
1780  while (parent_scope)
1781  {
1782  const std::map<std::string, symbol_record>& parent_scope_symbols
1783  = parent_scope.symbols ();
1784 
1785  auto p = parent_scope_symbols.find (name);
1786 
1787  if (p != parent_scope_symbols.end ())
1788  {
1789  found = true;
1790  symbol_record parent_scope_sr = p->second;
1791 
1792  frame_offset = parent_scope_sr.frame_offset () + count;
1793 
1794  data_offset = parent_scope_sr.data_offset ();
1795 
1796  break;
1797  }
1798  else
1799  {
1800  count++;
1801  parent_scope = parent_scope.parent_scope ();
1802  }
1803  }
1804  }
1805  else
1806  {
1807  const std::map<std::string, symbol_record>& eval_scope_symbols
1808  = eval_scope.symbols ();
1809 
1810  std::string name = script_sr.name ();
1811 
1812  auto p = eval_scope_symbols.find (name);
1813 
1814  symbol_record eval_scope_sr;
1815 
1816  if (p != eval_scope_symbols.end ())
1817  {
1818  found = true;
1819  eval_scope_sr = p->second;
1820 
1821  // The +1 is for going from the script frame to the eval
1822  // frame. Only one access_link should need to be followed.
1823 
1824  frame_offset = eval_scope_sr.frame_offset () + 1;
1825 
1826  data_offset = eval_scope_sr.data_offset ();
1827  }
1828  }
1829 
1830  return found;
1831 }
1832 
1833 bool
1834 script_stack_frame::get_val_offsets (const symbol_record& sym,
1835  std::size_t& frame_offset,
1836  std::size_t& data_offset) const
1837 {
1838  data_offset = sym.data_offset ();
1839  frame_offset = sym.frame_offset ();
1840 
1841  if (frame_offset == 0)
1842  {
1843  // An out of range data_offset value here means that we have a
1844  // symbol that was not originally in the script. But this
1845  // function is called in places where we can't insert a new
1846  // symbol, so we fail and it is up to the caller to decide what
1847  // to do.
1848 
1849  if (data_offset >= size ())
1850  return get_val_offsets_internal (sym, frame_offset, data_offset);
1851 
1852  // Use frame and value offsets stored in this stack frame,
1853  // indexed by data_offset from the symbol_record to find the
1854  // values. These offsets were determined by
1855  // script_stack_frame::set_script_offsets when this script was
1856  // invoked.
1857 
1858  frame_offset = m_lexical_frame_offsets.at (data_offset);
1859 
1860  if (frame_offset == 0)
1861  {
1862  // If the frame offset stored in m_lexical_frame_offsets is
1863  // zero, then the data offset in the evaluation scope has
1864  // not been determined so try to do that now. The symbol
1865  // may have been added by eval and without calling
1866  // resize_and_update_script_offsets.
1867 
1868  return get_val_offsets_internal (sym, frame_offset, data_offset);
1869  }
1870 
1871  data_offset = m_value_offsets.at (data_offset);
1872  }
1873  else
1874  {
1875  // If frame_offset is not zero, then then we must have a symbol
1876  // that was not originally in the script. The values should
1877  // have been determined by the script_stack_frame::lookup function.
1878  }
1879 
1880  return true;
1881 }
1882 
1883 void
1884 script_stack_frame::get_val_offsets_with_insert (const symbol_record& sym,
1885  std::size_t& frame_offset,
1886  std::size_t& data_offset)
1887 {
1888  data_offset = sym.data_offset ();
1889  frame_offset = sym.frame_offset ();
1890 
1891  if (frame_offset == 0)
1892  {
1893  if (data_offset >= size ())
1894  {
1895  // If the data_offset is out of range, then we must have a
1896  // symbol that was not originally in the script. Resize and
1897  // update the offsets.
1898 
1899  resize_and_update_script_offsets (sym);
1900  }
1901 
1902  // Use frame and value offsets stored in this stack frame,
1903  // indexed by data_offset from the symbol_record to find the
1904  // values. These offsets were determined by
1905  // script_stack_frame::set_script_offsets when this script was
1906  // invoked.
1907 
1908  frame_offset = m_lexical_frame_offsets.at (data_offset);
1909 
1910  if (frame_offset == 0)
1911  {
1912  // If the frame offset stored in m_lexical_frame_offsets is
1913  // zero, then the data offset in the evaluation scope has
1914  // not been determined so try to do that now. The symbol
1915  // may have been added by eval and without calling
1916  // resize_and_update_script_offsets.
1917 
1918  // We don't need to resize here. That case is handled above.
1919 
1920  // FIXME: We should be able to avoid creating the map object
1921  // and the looping in the set_scripts_offsets_internal
1922  // function. Can we do that without (or with minimal) code
1923  // duplication?
1924 
1925  std::map<std::string, symbol_record> tmp_symbols;
1926  tmp_symbols[sym.name ()] = sym;
1927  set_script_offsets_internal (tmp_symbols);
1928 
1929  // set_script_offsets_internal may have modified
1930  // m_lexical_frame_offsets and m_value_offsets.
1931 
1932  frame_offset = m_lexical_frame_offsets.at (data_offset);
1933  }
1934 
1935  data_offset = m_value_offsets.at (data_offset);
1936  }
1937  else
1938  {
1939  // If frame_offset is not zero, then then we must have a symbol
1940  // that was not originally in the script. The values were
1941  // determined by the script_stack_frame::lookup function.
1942  }
1943 }
1944 
1946 script_stack_frame::scope_flag (const symbol_record& sym) const
1947 {
1948  std::size_t frame_offset;
1949  std::size_t data_offset;
1950 
1951  bool found = get_val_offsets (sym, frame_offset, data_offset);
1952 
1953  // It can't be global or persistent, so call it local.
1954  if (! found)
1955  return LOCAL;
1956 
1957  // Follow frame_offset access links to stack frame that holds
1958  // the value.
1959 
1960  const stack_frame *frame = this;
1961 
1962  for (std::size_t i = 0; i < frame_offset; i++)
1963  {
1964  std::shared_ptr<stack_frame> nxt = frame->access_link ();
1965  frame = nxt.get ();
1966  }
1967 
1968  if (! frame)
1969  error ("internal error: invalid access link in function call stack");
1970 
1971  if (data_offset >= frame->size ())
1972  return LOCAL;
1973 
1974  return frame->get_scope_flag (data_offset);
1975 }
1976 
1978 script_stack_frame::varval (const symbol_record& sym) const
1979 {
1980  std::size_t frame_offset;
1981  std::size_t data_offset;
1982 
1983  bool found = get_val_offsets (sym, frame_offset, data_offset);
1984 
1985  if (! found)
1986  return octave_value ();
1987 
1988  // Follow frame_offset access links to stack frame that holds
1989  // the value.
1990 
1991  const stack_frame *frame = this;
1992 
1993  for (std::size_t i = 0; i < frame_offset; i++)
1994  {
1995  std::shared_ptr<stack_frame> nxt = frame->access_link ();
1996  frame = nxt.get ();
1997  }
1998 
1999  if (! frame)
2000  error ("internal error: invalid access link in function call stack");
2001 
2002  if (data_offset >= frame->size ())
2003  return octave_value ();
2004 
2005  switch (frame->get_scope_flag (data_offset))
2006  {
2007  case LOCAL:
2008  return frame->varval (data_offset);
2009 
2010  case PERSISTENT:
2011  {
2012  symbol_scope scope = frame->get_scope ();
2013 
2014  return scope.persistent_varval (data_offset);
2015  }
2016 
2017  case GLOBAL:
2018  return m_evaluator.global_varval (sym.name ());
2019  }
2020 
2021  error ("internal error: invalid switch case");
2022 }
2023 
2024 octave_value&
2026 {
2027  std::size_t frame_offset;
2028  std::size_t data_offset;
2029  get_val_offsets_with_insert (sym, frame_offset, data_offset);
2030 
2031  // Follow frame_offset access links to stack frame that holds
2032  // the value.
2033 
2034  stack_frame *frame = this;
2035 
2036  for (std::size_t i = 0; i < frame_offset; i++)
2037  {
2038  std::shared_ptr<stack_frame> nxt = frame->access_link ();
2039  frame = nxt.get ();
2040  }
2041 
2042  if (data_offset >= frame->size ())
2043  frame->resize (data_offset+1);
2044 
2045  switch (frame->get_scope_flag (data_offset))
2046  {
2047  case LOCAL:
2048  return frame->varref (data_offset);
2049 
2050  case PERSISTENT:
2051  {
2052  symbol_scope scope = frame->get_scope ();
2053 
2054  return scope.persistent_varref (data_offset);
2055  }
2056 
2057  case GLOBAL:
2058  return m_evaluator.global_varref (sym.name ());
2059  }
2060 
2061  error ("internal error: invalid switch case");
2062 }
2063 
2064 void
2065 script_stack_frame::mark_scope (const symbol_record& sym,
2066  scope_flags flag)
2067 {
2068  std::size_t data_offset = sym.data_offset ();
2069 
2070  if (data_offset >= size ())
2071  resize_and_update_script_offsets (sym);
2072 
2073  // Redirection to evaluation context for the script.
2074 
2075  std::size_t frame_offset = m_lexical_frame_offsets.at (data_offset);
2076  data_offset = m_value_offsets.at (data_offset);
2077 
2078  if (frame_offset > 1)
2079  error ("variables must be made PERSISTENT or GLOBAL in the first scope in which they are used");
2080 
2081  std::shared_ptr<stack_frame> frame = access_link ();
2082 
2083  if (data_offset >= frame->size ())
2084  frame->resize (data_offset+1);
2085 
2086  frame->set_scope_flag (data_offset, flag);
2087 }
2088 
2089 void
2090 script_stack_frame::display (bool follow) const
2091 {
2092  std::ostream& os = octave_stdout;
2093 
2094  os << "-- [script_stack_frame] (" << this << ") --" << std::endl;
2095  stack_frame::display (follow);
2096 
2097  os << "script: " << m_script->name ()
2098  << " (" << m_script->type_name () << ")" << std::endl;
2099 
2100  os << "lexical_offsets: " << m_lexical_frame_offsets.size ()
2101  << " elements:";
2102 
2103  for (std::size_t i = 0; i < m_lexical_frame_offsets.size (); i++)
2104  os << " " << m_lexical_frame_offsets.at (i);
2105  os << std::endl;
2106 
2107  os << "value_offsets: " << m_value_offsets.size () << " elements:";
2108  for (std::size_t i = 0; i < m_value_offsets.size (); i++)
2109  os << " " << m_value_offsets.at (i);
2110  os << std::endl;
2111 
2112  display_scope (os, get_scope ());
2113 }
2114 
2115 void
2116 script_stack_frame::accept (stack_frame_walker& sfw)
2117 {
2118  sfw.visit_script_stack_frame (*this);
2119 }
2120 
2121 void
2122 base_value_stack_frame::display (bool follow) const
2123 {
2124  std::ostream& os = octave_stdout;
2125 
2126  os << "-- [base_value_stack_frame] (" << this << ") --" << std::endl;
2127  stack_frame::display (follow);
2128 
2129  os << "values: " << m_values.size ()
2130  << " elements (idx, scope flag, type):" << std::endl;
2131 
2132  for (std::size_t i = 0; i < m_values.size (); i++)
2133  {
2134  os << " (" << i << ", " << m_flags.at (i) << ", ";
2135 
2136  octave_value val = varval (i);
2137 
2138  os << (val.is_defined () ? val.type_name () : " UNDEFINED") << ")"
2139  << std::endl;
2140  }
2141 }
2142 
2143 // If this is a nested scope, set access_link to nearest parent
2144 // stack frame that corresponds to the lexical parent of this scope.
2145 
2146 std::shared_ptr<stack_frame>
2147 user_fcn_stack_frame::get_access_link (octave_user_function *fcn,
2148  const std::shared_ptr<stack_frame>& static_link)
2149 {
2150  std::shared_ptr<stack_frame> alink;
2151 
2152  symbol_scope fcn_scope = fcn->scope ();
2153 
2154  if (fcn_scope.is_nested ())
2155  {
2156  if (! static_link)
2157  error ("internal call stack error (invalid static link)");
2158 
2159  symbol_scope caller_scope = static_link->get_scope ();
2160 
2161  int nesting_depth = fcn_scope.nesting_depth ();
2162  int caller_nesting_depth = caller_scope.nesting_depth ();
2163 
2164  if (caller_nesting_depth < nesting_depth)
2165  {
2166  // FIXME: do we need to ensure that the called
2167  // function is a child of the caller? Does it hurt
2168  // to panic_unless this condition, at least for now?
2169 
2170  alink = static_link;
2171  }
2172  else
2173  {
2174  // FIXME: do we need to check that the parent of the
2175  // called function is also a parent of the caller?
2176  // Does it hurt to panic_unless this condition, at least
2177  // for now?
2178 
2179  int links_to_follow = caller_nesting_depth - nesting_depth + 1;
2180 
2181  alink = static_link;
2182 
2183  while (alink && --links_to_follow >= 0)
2184  alink = alink->access_link ();
2185 
2186  if (! alink)
2187  error ("internal function nesting error (invalid access link)");
2188  }
2189  }
2190 
2191  return alink;
2192 }
2193 
2194 void
2195 user_fcn_stack_frame::clear_values ()
2196 {
2197  symbol_scope fcn_scope = m_fcn->scope ();
2198 
2199  const std::list<symbol_record>& symbols = fcn_scope.symbol_list ();
2200 
2201  if (size () == 0)
2202  return;
2203 
2204  for (const auto& sym : symbols)
2205  {
2206  std::size_t frame_offset = sym.frame_offset ();
2207 
2208  if (frame_offset > 0)
2209  continue;
2210 
2211  std::size_t data_offset = sym.data_offset ();
2212 
2213  if (data_offset >= size ())
2214  continue;
2215 
2216  if (get_scope_flag (data_offset) == LOCAL)
2217  {
2218  octave_value& ref = m_values.at (data_offset);
2219 
2220  if (ref.get_count () == 1)
2221  {
2222  ref.call_object_destructor ();
2223  ref = octave_value ();
2224  }
2225  }
2226  }
2227 }
2228 
2230 user_fcn_stack_frame::unwind_protect_frame ()
2231 {
2232  if (! m_unwind_protect_frame)
2233  m_unwind_protect_frame = new unwind_protect ();
2234 
2235  return m_unwind_protect_frame;
2236 }
2237 
2239 user_fcn_stack_frame::lookup_symbol (const std::string& name) const
2240 {
2241  const stack_frame *frame = this;
2242 
2243  while (frame)
2244  {
2245  symbol_scope scope = frame->get_scope ();
2246 
2247  symbol_record sym = scope.lookup_symbol (name);
2248 
2249  if (sym)
2250  return sym;
2251 
2252  std::shared_ptr<stack_frame> nxt = frame->access_link ();
2253  frame = nxt.get ();
2254  }
2255 
2256  return symbol_record ();
2257 }
2258 
2260 user_fcn_stack_frame::insert_symbol (const std::string& name)
2261 {
2262  // If the symbols is already in the immediate scope, there is
2263  // nothing more to do.
2264 
2265  symbol_scope scope = get_scope ();
2266 
2267  symbol_record sym = scope.lookup_symbol (name);
2268 
2269  if (sym)
2270  return sym;
2271 
2272  // FIXME: This needs some thought... We may need to add a symbol to
2273  // a static workspace, but the symbol can never be defined as a
2274  // variable. This currently works by tagging the added symbol as
2275  // "added_static". Aside from the bad name, this doesn't seem like
2276  // the best solution. Maybe scopes should have a separate set of
2277  // symbols that may only be defined as functions?
2278 
2279  // Insert the symbol in the current scope. This is not possible for
2280  // anonymous functions, nested functions, or functions that contain
2281  // nested functions (their scopes will all be marked static).
2282 
2283  // if (scope.is_static ())
2284  // error ("can not add variable '%s' to a static workspace",
2285  // name.c_str ());
2286 
2287  // At this point, non-local references are not possible so we only
2288  // need to look in the current scope and insert there. This
2289  // operation should never fail.
2290 
2291  sym = scope.find_symbol (name);
2292 
2293  panic_unless (sym.is_valid ());
2294 
2295  return sym;
2296 }
2297 
2299 user_fcn_stack_frame::scope_flag (const symbol_record& sym) const
2300 {
2301  std::size_t frame_offset = sym.frame_offset ();
2302  std::size_t data_offset = sym.data_offset ();
2303 
2304  // Follow frame_offset access links to stack frame that holds
2305  // the value.
2306 
2307  const stack_frame *frame = this;
2308 
2309  for (std::size_t i = 0; i < frame_offset; i++)
2310  {
2311  std::shared_ptr<stack_frame> nxt = frame->access_link ();
2312  frame = nxt.get ();
2313  }
2314 
2315  if (! frame)
2316  error ("internal error: invalid access link in function call stack");
2317 
2318  if (data_offset >= frame->size ())
2319  return LOCAL;
2320 
2321  return frame->get_scope_flag (data_offset);
2322 }
2323 
2326 {
2327  std::size_t frame_offset = sym.frame_offset ();
2328  std::size_t data_offset = sym.data_offset ();
2329 
2330  // Follow frame_offset access links to stack frame that holds
2331  // the value.
2332 
2333  const stack_frame *frame = this;
2334 
2335  for (std::size_t i = 0; i < frame_offset; i++)
2336  {
2337  std::shared_ptr<stack_frame> nxt = frame->access_link ();
2338  frame = nxt.get ();
2339  }
2340 
2341  if (! frame)
2342  error ("internal error: invalid access link in function call stack");
2343 
2344  if (data_offset >= frame->size ())
2345  return octave_value ();
2346 
2347  switch (frame->get_scope_flag (data_offset))
2348  {
2349  case LOCAL:
2350  return frame->varval (data_offset);
2351 
2352  case PERSISTENT:
2353  {
2354  symbol_scope scope = frame->get_scope ();
2355 
2356  return scope.persistent_varval (data_offset);
2357  }
2358 
2359  case GLOBAL:
2360  return m_evaluator.global_varval (sym.name ());
2361  }
2362 
2363  error ("internal error: invalid switch case");
2364 }
2365 
2366 octave_value&
2367 user_fcn_stack_frame::varref (const symbol_record& sym)
2368 {
2369  std::size_t frame_offset = sym.frame_offset ();
2370  std::size_t data_offset = sym.data_offset ();
2371 
2372  // Follow frame_offset access links to stack frame that holds
2373  // the value.
2374 
2375  stack_frame *frame = this;
2376 
2377  for (std::size_t i = 0; i < frame_offset; i++)
2378  {
2379  std::shared_ptr<stack_frame> nxt = frame->access_link ();
2380  frame = nxt.get ();
2381  }
2382 
2383  if (data_offset >= frame->size ())
2384  frame->resize (data_offset+1);
2385 
2386  switch (frame->get_scope_flag (data_offset))
2387  {
2388  case LOCAL:
2389  return frame->varref (data_offset);
2390 
2391  case PERSISTENT:
2392  {
2393  symbol_scope scope = frame->get_scope ();
2394 
2395  return scope.persistent_varref (data_offset);
2396  }
2397 
2398  case GLOBAL:
2399  return m_evaluator.global_varref (sym.name ());
2400  }
2401 
2402  error ("internal error: invalid switch case");
2403 }
2404 
2405 void
2406 user_fcn_stack_frame::mark_scope (const symbol_record& sym, scope_flags flag)
2407 {
2408  std::size_t frame_offset = sym.frame_offset ();
2409 
2410  if (frame_offset > 0 && (flag == PERSISTENT || flag == GLOBAL))
2411  error ("variables must be made PERSISTENT or GLOBAL in the first scope in which they are used");
2412 
2413  std::size_t data_offset = sym.data_offset ();
2414 
2415  if (data_offset >= size ())
2416  resize (data_offset+1);
2417 
2418  set_scope_flag (data_offset, flag);
2419 }
2420 
2421 void
2422 user_fcn_stack_frame::display (bool follow) const
2423 {
2424  std::ostream& os = octave_stdout;
2425 
2426  os << "-- [user_fcn_stack_frame] (" << this << ") --" << std::endl;
2427  base_value_stack_frame::display (follow);
2428 
2429  os << "fcn: " << m_fcn->name ()
2430  << " (" << m_fcn->type_name () << ")" << std::endl;
2431 
2432  display_scope (os, get_scope ());
2433 }
2434 
2435 void
2436 user_fcn_stack_frame::accept (stack_frame_walker& sfw)
2437 {
2438  sfw.visit_user_fcn_stack_frame (*this);
2439 }
2440 
2441 void
2442 user_fcn_stack_frame::break_closure_cycles (const std::shared_ptr<stack_frame>& frame)
2443 {
2444  for (auto& val : m_values)
2445  val.break_closure_cycles (frame);
2446 
2447  if (m_access_link)
2448  m_access_link->break_closure_cycles (frame);
2449 }
2450 
2452 scope_stack_frame::insert_symbol (const std::string& name)
2453 {
2454  // There is no access link for scope frames, so there is no other
2455  // frame to search in and the offset must be zero.
2456 
2457  symbol_record sym = m_scope.lookup_symbol (name);
2458 
2459  if (sym)
2460  return sym;
2461 
2462  // If the symbol is not found, insert it. We only need to search in
2463  // the local scope object. This operation should never fail.
2464 
2465  sym = m_scope.find_symbol (name);
2466 
2467  panic_unless (sym.is_valid ());
2468 
2469  return sym;
2470 }
2471 
2473 scope_stack_frame::scope_flag (const symbol_record& sym) const
2474 {
2475  // There is no access link for scope frames, so the frame
2476  // offset must be zero.
2477 
2478  std::size_t data_offset = sym.data_offset ();
2479 
2480  if (data_offset >= size ())
2481  return LOCAL;
2482 
2483  return get_scope_flag (data_offset);
2484 }
2485 
2487 scope_stack_frame::varval (const symbol_record& sym) const
2488 {
2489  // There is no access link for scope frames, so the frame
2490  // offset must be zero.
2491 
2492  std::size_t data_offset = sym.data_offset ();
2493 
2494  if (data_offset >= size ())
2495  return octave_value ();
2496 
2497  switch (get_scope_flag (data_offset))
2498  {
2499  case LOCAL:
2500  return m_values.at (data_offset);
2501 
2502  case PERSISTENT:
2503  return m_scope.persistent_varval (data_offset);
2504 
2505  case GLOBAL:
2506  return m_evaluator.global_varval (sym.name ());
2507  }
2508 
2509  error ("internal error: invalid switch case");
2510 }
2511 
2512 octave_value&
2513 scope_stack_frame::varref (const symbol_record& sym)
2514 {
2515  // There is no access link for scope frames, so the frame
2516  // offset must be zero.
2517 
2518  std::size_t data_offset = sym.data_offset ();
2519 
2520  if (data_offset >= size ())
2521  resize (data_offset+1);
2522 
2523  switch (get_scope_flag (data_offset))
2524  {
2525  case LOCAL:
2526  return m_values.at (data_offset);
2527 
2528  case PERSISTENT:
2529  return m_scope.persistent_varref (data_offset);
2530 
2531  case GLOBAL:
2532  return m_evaluator.global_varref (sym.name ());
2533  }
2534 
2535  error ("internal error: invalid switch case");
2536 }
2537 
2538 void
2539 scope_stack_frame::mark_scope (const symbol_record& sym,
2540  scope_flags flag)
2541 {
2542  // There is no access link for scope frames, so the frame
2543  // offset must be zero.
2544 
2545  std::size_t data_offset = sym.data_offset ();
2546 
2547  if (data_offset >= size ())
2548  resize (data_offset+1);
2549 
2550  set_scope_flag (data_offset, flag);
2551 }
2552 
2553 void
2554 scope_stack_frame::display (bool follow) const
2555 {
2556  std::ostream& os = octave_stdout;
2557 
2558  os << "-- [scope_stack_frame] (" << this << ") --" << std::endl;
2559  base_value_stack_frame::display (follow);
2560 
2561  display_scope (os, m_scope);
2562 }
2563 
2564 void
2565 scope_stack_frame::accept (stack_frame_walker& sfw)
2566 {
2567  sfw.visit_scope_stack_frame (*this);
2568 }
2569 
2570 OCTAVE_END_NAMESPACE(octave)
Definition: Cell.h:43
void push_back(const elt_type &s)
Definition: base-list.h:86
void append(const elt_type &s)
Definition: base-list.h:92
std::size_t size() const
Definition: base-list.h:52
bool empty() const
Definition: base-list.h:50
static octave_map cat(int dim, octave_idx_type n, const octave_scalar_map *map_list)
Definition: oct-map.cc:690
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:230
octave::symbol_scope scope()
Definition: ov-usr-fcn.h:90
void call_object_destructor()
Definition: ov.h:1437
bool is_defined() const
Definition: ov.h:592
void break_closure_cycles(const std::shared_ptr< octave::stack_frame > &)
octave_idx_type get_count() const
Definition: ov.h:421
std::string type_name() const
Definition: ov.h:1345
virtual scope_flags get_scope_flag(std::size_t) const
octave_value workspace()
symbol_info_list glob_symbol_info(const std::string &pattern)
std::string fcn_file_name() const
Definition: stack-frame.h:210
std::shared_ptr< stack_frame > parent_link() const
Definition: stack-frame.h:320
std::list< std::string > variable_names() const
void clear_variables()
virtual octave_value varval(const symbol_record &sym) const =0
void clear(const symbol_record &sym)
Definition: stack-frame.h:530
void clear_objects()
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)
octave_value value(const symbol_record &sym, const std::string &type, const std::list< octave_value_list > &idx) const
Definition: stack-frame.h:503
bool is_global(const symbol_record &sym) const
Definition: stack-frame.h:400
void clear_variable_regexp(const std::string &pattern)
void mark_global(const symbol_record &sym)
Definition: stack-frame.h:332
std::size_t m_index
Definition: stack-frame.h:604
virtual int line() const
Definition: stack-frame.h:205
virtual octave_value & varref(std::size_t data_offset)
void clear_variable_pattern(const std::string &pattern)
std::size_t index() const
Definition: stack-frame.h:202
symbol_info_list regexp_symbol_info(const std::string &pattern)
virtual void display(bool follow=true) const
virtual void set_scope_flag(std::size_t, scope_flags)
bool is_defined(const symbol_record &sym) const
Definition: stack-frame.h:352
virtual void accept(stack_frame_walker &sfw)=0
void display_stopped_in_message(std::ostream &os) const
octave_value varval(const std::string &name) const
Definition: stack-frame.h:446
std::shared_ptr< stack_frame > m_parent_link
Definition: stack-frame.h:608
bool is_persistent(const symbol_record &sym) const
Definition: stack-frame.h:412
std::shared_ptr< stack_frame > m_access_link
Definition: stack-frame.h:618
virtual bool is_user_fcn_frame() const
Definition: stack-frame.h:197
virtual octave_value & varref(const symbol_record &sym)=0
std::string fcn_name(bool print_subfn=true) const
Definition: stack-frame.h:217
void assign(const symbol_record &sym, const octave_value &val)
Definition: stack-frame.h:458
bool is_object(const symbol_record &sym) const
Definition: stack-frame.h:380
std::shared_ptr< stack_frame > static_link() const
Definition: stack-frame.h:323
virtual octave_value varval(std::size_t data_offset) const
void install_variable(const symbol_record &sym, const octave_value &value, bool global)
void clear_variable(const std::string &name)
std::shared_ptr< stack_frame > m_static_link
Definition: stack-frame.h:613
std::map< std::string, octave_value > local_vars_map
Definition: stack-frame.h:112
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)
tree_evaluator & m_evaluator
Definition: stack-frame.h:592
virtual std::size_t size() const
symbol_info_list all_variables()
virtual void clear_values()
virtual symbol_scope get_scope() const =0
virtual void resize(std::size_t)
bool is_variable(const symbol_record &sym) const
Definition: stack-frame.h:359
std::shared_ptr< stack_frame > access_link() const
Definition: stack-frame.h:326
symbol_info_list make_symbol_info_list(const std::list< symbol_record > &symrec_list) const
std::ostream & list_in_columns(std::ostream &, int width=0, const std::string &prefix="") const
Definition: str-vec.cc:201
std::list< std::string > names() const
Definition: syminfo.cc:182
void display(std::ostream &os, const std::string &format) const
Definition: syminfo.cc:334
octave_value varval(const std::string &name) const
Definition: syminfo.cc:170
octave_map map_value(const std::string &caller_function_name, int nesting_level) const
Definition: syminfo.cc:193
bool is_valid() const
Definition: symrec.h:191
symbol_record dup() const
Definition: symrec.h:205
std::string name() const
Definition: symrec.h:207
void set_frame_offset(std::size_t offset)
Definition: symrec.h:195
std::size_t frame_offset() const
Definition: symrec.h:198
std::size_t data_offset() const
Definition: symrec.h:203
bool is_formal() const
Definition: symrec.h:212
std::string name() const
Definition: symscope.h:586
bool is_nested() const
Definition: symscope.h:430
symbol_record find_symbol(const std::string &name)
Definition: symscope.h:489
std::size_t num_symbols() const
Definition: symscope.h:414
std::list< symbol_record > symbol_list() const
Definition: symscope.h:732
std::shared_ptr< symbol_scope_rep > parent_scope() const
Definition: symscope.h:462
octave_value persistent_varval(std::size_t data_offset) const
Definition: symscope.h:484
symbol_record insert(const std::string &name)
Definition: symscope.h:500
octave_value & persistent_varref(std::size_t data_offset)
Definition: symscope.h:477
const std::map< std::string, symbol_record > & symbols() const
Definition: symscope.h:718
symbol_record lookup_symbol(const std::string &name) const
Definition: symscope.h:495
std::size_t nesting_depth() const
Definition: symscope.h:446
octave_value & global_varref(const std::string &name)
Definition: pt-eval.cc:1971
octave_value global_varval(const std::string &name) const
Definition: pt-eval.cc:1965
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
Definition: error.cc:1063
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1078
void() error(const char *fmt,...)
Definition: error.cc:988
#define panic_impossible()
Definition: error.h:503
#define panic_unless(cond)
Definition: error.h:515
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:48
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
@ PERSISTENT
Definition: oct-parse.h:123
@ GLOBAL
Definition: oct-parse.h:122
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define octave_stdout
Definition: pager.h:309
std::size_t format(std::ostream &os, const char *fmt,...)