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