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