GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
symscope.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-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 <sstream>
31 
32 #include "file-ops.h"
33 
34 #include "fcn-info.h"
35 #include "interpreter-private.h"
36 #include "interpreter.h"
37 #include "ov-fcn.h"
38 #include "ov-usr-fcn.h"
39 #include "symrec.h"
40 #include "symscope.h"
41 #include "utils.h"
42 
44 
45 symbol_record symbol_scope_rep::insert_local (const std::string& name)
46 {
47  symbol_record sym (name);
48 
49  insert_symbol_record (sym);
50 
51  return sym;
52 }
53 
55 {
56  std::size_t data_offset = num_symbols ();
57  std::string name = sr.name ();
58 
59  sr.set_data_offset (data_offset);
60 
61  m_symbols[name] = sr;
62 }
63 
64 symbol_record symbol_scope_rep::insert (const std::string& name)
65 {
66  table_iterator p = m_symbols.find (name);
67 
68  if (p == m_symbols.end ())
69  {
70  symbol_record ret (name);
71 
72  std::size_t data_offset = num_symbols ();
73 
74  ret.set_data_offset (data_offset);
75 
76  auto t_parent = m_parent.lock ();
77 
78  std::size_t offset = 0;
79 
80  if (is_nested () && t_parent
81  && t_parent->look_nonlocal (name, offset, ret))
82  return m_symbols[name] = ret;
83  else
84  {
85  if (m_is_static)
86  ret.mark_added_static ();
87 
88  return m_symbols[name] = ret;
89  }
90  }
91  else
92  return p->second;
93 }
94 
95 std::list<octave_value> symbol_scope_rep::localfunctions (void) const
96 {
97  std::list<octave_value> retval;
98 
99  // Find the subfunctions of this function (which should be the
100  // primary parent function for this scope).
101 
102  // 1) m_subfunction_names contains only valid subfunctions
103  // 2) m_subfunctions contains both nested functions and subfunctions
104 
105  // loop over them.
106 
107  for (const auto& nm : m_subfunction_names)
108  {
109  auto nm_fcn_iter = m_subfunctions.find (nm);
110 
111  if (nm_fcn_iter != m_subfunctions.end ())
112  {
113  octave_value ov_fcn = nm_fcn_iter->second;
114  octave_user_code *fcn = ov_fcn.user_code_value ();
115 
116  if (! fcn)
117  continue;
118 
119  symbol_scope scope = fcn->scope ();
120 
121  std::list<std::string> plst = scope.parent_fcn_names ();
122 
123  octave_fcn_handle *fh = new octave_fcn_handle (ov_fcn, nm, plst);
124 
125  retval.push_back (octave_value (fh));
126  }
127  }
128 
129  return retval;
130 }
131 
134 {
135  std::map<std::string, octave_value> m
136  = {{ "name", m_name },
137  { "nesting_depth", m_nesting_depth },
138  { "is_static", m_is_static },
139  { "symbols", dump_symbols_map () },
140  { "subfunction_names", string_vector (m_subfunction_names) },
141  { "subfunctions", dump_function_map (m_subfunctions) }
142  };
143 
144  return octave_value (m);
145 }
146 
149 {
150  std::map<std::string, octave_value> info_map;
151 
152  for (const auto& nm_sr : m_symbols)
153  {
154  std::string nm = nm_sr.first;
155  symbol_record sr = nm_sr.second;
156  info_map[nm] = sr.dump ();
157  }
158 
159  return octave_value (info_map);
160 }
161 
162 std::list<symbol_record> symbol_scope_rep::symbol_list (void) const
163 {
164  std::list<symbol_record> retval;
165 
166  for (const auto& nm_sr : m_symbols)
167  retval.push_back (nm_sr.second);
168 
169  return retval;
170 }
171 
173 symbol_scope_rep::find_subfunction (const std::string& name) const
174 {
176 
177  if (p != m_subfunctions.end ())
178  return p->second;
179 
180  auto t_parent = m_parent.lock ();
181 
182  if (t_parent)
183  return t_parent->find_subfunction (name);
184 
185  return octave_value ();
186 }
187 
188 void
190 {
191  for (auto& nm_sf : m_subfunctions)
192  {
193  octave_function *fcn = nm_sf.second.function_value ();
194 
195  if (fcn)
196  fcn->mark_as_private_function (class_name);
197  }
198 }
199 
200 std::list<std::string>
202 {
203  std::list<std::string> retval;
204 
205  auto pscope = parent_scope_rep ();
206 
207  while (pscope)
208  {
209  retval.push_back (pscope->fcn_name ());
210 
211  pscope = pscope->parent_scope_rep ();
212  }
213 
214  return retval;
215 }
216 
217 void
218 symbol_scope_rep::set_parent (const std::shared_ptr<symbol_scope_rep>& parent)
219 {
220  m_parent = std::weak_ptr<symbol_scope_rep> (parent);
221 }
222 
223 void
224 symbol_scope_rep::set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent)
225 {
226  m_primary_parent = std::weak_ptr<symbol_scope_rep> (parent);
227 }
228 
229 void
230 symbol_scope_rep::cache_dir_name (const std::string& name)
231 {
233 }
234 
235 bool
236 symbol_scope_rep::is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const
237 {
238  if (is_nested ())
239  {
240  // Since is_nested is true, the following should always return a
241  // valid scope.
242 
243  auto t_parent = m_parent.lock ();
244 
245  if (t_parent)
246  {
247  // SCOPE is the parent of this scope: this scope is a child
248  // of SCOPE.
249 
250  if (t_parent == scope)
251  return true;
252  }
253 
254  auto t_primary_parent = m_primary_parent.lock ();
255 
256  if (t_primary_parent)
257  {
258  // SCOPE is the primary parent of this scope: this scope is a
259  // child (or grandchild) of SCOPE.
260  if (t_primary_parent == scope)
261  return true;
262 
263  // SCOPE and this scope share the same primary parent: they are
264  // siblings (or cousins)
265  auto scope_primary_parent = scope->primary_parent_scope_rep ();
266  if (t_primary_parent == scope_primary_parent)
267  return true;
268  }
269  }
270 
271  return false;
272 }
273 
274 void symbol_scope_rep::mark_as_variable (const std::string& nm)
275 {
276  table_iterator p = m_symbols.find (nm);
277 
278  if (p != m_symbols.end ())
279  p->second.mark_as_variable ();
280 }
281 
282 void symbol_scope_rep::mark_as_variables (const std::list<std::string>& lst)
283 {
284  for (const auto& nm : lst)
285  mark_as_variable (nm);
286 }
287 
288 bool symbol_scope_rep::is_variable (const std::string& nm) const
289 {
290  table_const_iterator p = m_symbols.find (nm);
291 
292  // FIXME: maybe we should also mark formal parameters as variables?
293 
294  if (p != m_symbols.end () && p->second.is_variable ())
295  return true;
296 
297  if (is_nested ())
298  {
299  auto t_parent = m_parent.lock ();
300 
301  return t_parent ? t_parent->is_variable (nm) : false;
302  }
303 
304  return false;
305 }
306 
308 {
309  auto t_parent = m_parent.lock ();
310 
311  if (t_parent)
312  {
313  // fix bad symbol_records
314  for (auto& nm_sr : m_symbols)
315  {
316  symbol_record& ours = nm_sr.second;
317 
318  std::size_t offset = 0;
319 
320  if (! ours.is_formal () && is_nested ())
321  t_parent->look_nonlocal (nm_sr.first, offset, ours);
322  }
323 
324  // The scopes of nested functions are static.
325  if (is_nested ())
326  m_is_static = true;
327  }
328  else if (m_children.size ())
329  {
330  // Parents of nested functions have static scopes.
331  m_is_static = true;
332  }
333 
334  for (auto& scope_obj : m_children)
335  scope_obj.update_nest ();
336 }
337 
338 bool symbol_scope_rep::look_nonlocal (const std::string& name,
339  std::size_t offset,
340  symbol_record& result)
341 {
342  offset++;
343 
344  table_iterator p = m_symbols.find (name);
345 
346  if (p == m_symbols.end ())
347  {
348  auto t_parent = m_parent.lock ();
349 
350  if (is_nested () && t_parent)
351  return t_parent->look_nonlocal (name, offset, result);
352  }
353  else
354  {
355  // Add scope offsets because the one we found may be used in
356  // this scope but initially from another parent scope beyond
357  // that. The parent offset will already point to the first
358  // occurrence because we do the overall nesting update from the
359  // parent function down through the lists of all children.
360 
361  std::size_t t_frame_offset = offset + p->second.frame_offset ();
362  std::size_t t_data_offset = p->second.data_offset ();
363 
364  result.set_frame_offset (t_frame_offset);
365  result.set_data_offset (t_data_offset);
366 
367  return true;
368  }
369 
370  return false;
371 }
372 
373 std::list<octave_value> symbol_scope::localfunctions (void) const
374 {
375  if (! m_rep)
376  return std::list<octave_value> ();
377 
378  if (is_primary_fcn_scope ())
379  return m_rep->localfunctions ();
380 
381  std::shared_ptr<symbol_scope_rep> ppsr
382  = m_rep->primary_parent_scope_rep ();
383 
384  if (! ppsr)
385  return std::list<octave_value> ();
386 
387  return ppsr->localfunctions ();
388 }
389 
OCTAVE_END_NAMESPACE(octave)
virtual octave_function * function_value(bool silent=false)
Definition: ov-base.cc:940
virtual void mark_as_private_function(const std::string &cname="")
Definition: ov-fcn.h:157
octave::symbol_scope scope(void)
Definition: ov-usr-fcn.h:94
OCTINTERP_API octave_user_code * user_code_value(bool silent=false) const
void set_data_offset(std::size_t offset)
Definition: symrec.h:202
std::string name(void) const
Definition: symrec.h:209
void set_frame_offset(std::size_t offset)
Definition: symrec.h:197
octave_value dump(void) const
Definition: symrec.h:230
bool is_formal(void) const
Definition: symrec.h:214
void mark_added_static(void)
Definition: symrec.h:220
std::string m_name
Name for this scope (usually the corresponding filename of the function corresponding to the scope).
Definition: symscope.h:315
std::map< std::string, symbol_record > m_symbols
Map from symbol names to symbol info.
Definition: symscope.h:319
std::list< octave_value > localfunctions(void) const
Definition: symscope.cc:95
void mark_subfunctions_in_scope_as_private(const std::string &class_name)
Definition: symscope.cc:189
std::list< std::string > m_subfunction_names
The list of subfunctions (if any) in the order they appear in the function file.
Definition: symscope.h:331
std::map< std::string, octave_value > m_subfunctions
Map from symbol names to subfunctions.
Definition: symscope.h:323
octave_value dump(void) const
Definition: symscope.cc:133
void cache_dir_name(const std::string &name)
Definition: symscope.cc:230
bool m_is_static
If true then no variables can be added.
Definition: symscope.h:368
bool is_relative(const std::shared_ptr< symbol_scope_rep > &scope) const
Definition: symscope.cc:236
std::shared_ptr< symbol_scope_rep > parent_scope_rep(void) const
Definition: symscope.h:108
std::list< symbol_record > symbol_list(void) const
Definition: symscope.cc:162
std::string name(void) const
Definition: symscope.h:251
std::weak_ptr< symbol_scope_rep > m_primary_parent
Primary (top) parent of nested function (may be null).
Definition: symscope.h:356
void set_primary_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:224
std::map< std::string, symbol_record >::iterator table_iterator
Definition: symscope.h:61
void mark_as_variables(const std::list< std::string > &lst)
Definition: symscope.cc:282
bool is_variable(const std::string &nm) const
Definition: symscope.cc:288
void update_nest(void)
Definition: symscope.cc:307
std::map< std::string, octave_value >::const_iterator subfunctions_const_iterator
Definition: symscope.h:64
symbol_record insert(const std::string &name)
Definition: symscope.cc:64
octave_value find_subfunction(const std::string &name) const
Definition: symscope.cc:173
std::list< std::string > parent_fcn_names(void) const
Definition: symscope.cc:201
std::size_t m_nesting_depth
If true, then this scope belongs to a nested function.
Definition: symscope.h:364
std::string m_dir_name
The directory associated with m_code.
Definition: symscope.h:347
void set_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:218
std::vector< symbol_scope > m_children
Child nested functions.
Definition: symscope.h:360
octave_value dump_symbols_map(void) const
Definition: symscope.cc:148
bool is_nested(void) const
Definition: symscope.h:96
void mark_as_variable(const std::string &nm)
Definition: symscope.cc:274
std::size_t num_symbols(void) const
Definition: symscope.h:88
std::map< std::string, symbol_record >::const_iterator table_const_iterator
Definition: symscope.h:59
void insert_symbol_record(symbol_record &sr)
Definition: symscope.cc:54
std::weak_ptr< symbol_scope_rep > m_parent
Parent of nested function (may be null).
Definition: symscope.h:351
bool look_nonlocal(const std::string &name, std::size_t offset, symbol_record &result)
Definition: symscope.cc:338
std::list< std::string > parent_fcn_names(void) const
Definition: symscope.h:593
std::shared_ptr< symbol_scope_rep > m_rep
Definition: symscope.h:726
std::list< octave_value > localfunctions(void) const
Definition: symscope.cc:373
bool is_primary_fcn_scope(void) const
Definition: symscope.h:649
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
Definition: fcn-info.cc:1120
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:744
T octave_idx_type m
Definition: mx-inlines.cc:773
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))