GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
symscope.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <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 
54 void
56 {
57  std::size_t data_offset = num_symbols ();
58  std::string name = sr.name ();
59 
60  sr.set_data_offset (data_offset);
61 
62  m_symbols[name] = sr;
63 }
64 
66 symbol_scope_rep::insert (const std::string& name)
67 {
68  table_iterator p = m_symbols.find (name);
69 
70  if (p == m_symbols.end ())
71  {
72  symbol_record ret (name);
73 
74  std::size_t data_offset = num_symbols ();
75 
76  ret.set_data_offset (data_offset);
77 
78  auto t_parent = m_parent.lock ();
79 
80  std::size_t offset = 0;
81 
82  if (is_nested () && t_parent
83  && t_parent->look_nonlocal (name, offset, ret))
84  return m_symbols[name] = ret;
85  else
86  {
87  if (m_is_static)
88  ret.mark_added_static ();
89 
90  return m_symbols[name] = ret;
91  }
92  }
93  else
94  return p->second;
95 }
96 
97 std::list<octave_value>
99 {
100  std::list<octave_value> retval;
101 
102  // Find the subfunctions of this function (which should be the
103  // primary parent function for this scope).
104 
105  // 1) m_subfunction_names contains only valid subfunctions
106  // 2) m_subfunctions contains both nested functions and subfunctions
107 
108  // loop over them.
109 
110  for (const auto& nm : m_subfunction_names)
111  {
112  auto nm_fcn_iter = m_subfunctions.find (nm);
113 
114  if (nm_fcn_iter != m_subfunctions.end ())
115  {
116  octave_value ov_fcn = nm_fcn_iter->second;
117  octave_user_code *fcn = ov_fcn.user_code_value ();
118 
119  if (! fcn)
120  continue;
121 
122  symbol_scope scope = fcn->scope ();
123 
124  std::list<std::string> plst = scope.parent_fcn_names ();
125 
126  octave_fcn_handle *fh = new octave_fcn_handle (ov_fcn, nm, plst);
127 
128  retval.push_back (octave_value (fh));
129  }
130  }
131 
132  return retval;
133 }
134 
137 {
138  std::map<std::string, octave_value> m
139  = {{ "name", m_name },
140  { "nesting_depth", m_nesting_depth },
141  { "is_static", m_is_static },
142  { "symbols", dump_symbols_map () },
143  { "subfunction_names", string_vector (m_subfunction_names) },
144  { "subfunctions", dump_function_map (m_subfunctions) }
145  };
146 
147  return octave_value (m);
148 }
149 
152 {
153  std::map<std::string, octave_value> info_map;
154 
155  for (const auto& nm_sr : m_symbols)
156  {
157  std::string nm = nm_sr.first;
158  symbol_record sr = nm_sr.second;
159  info_map[nm] = sr.dump ();
160  }
161 
162  return octave_value (info_map);
163 }
164 
165 std::list<symbol_record>
167 {
168  std::list<symbol_record> retval;
169 
170  for (const auto& nm_sr : m_symbols)
171  retval.push_back (nm_sr.second);
172 
173  return retval;
174 }
175 
177 symbol_scope_rep::find_subfunction (const std::string& name) const
178 {
179  subfunctions_const_iterator p = m_subfunctions.find (name);
180 
181  if (p != m_subfunctions.end ())
182  return p->second;
183 
184  auto t_parent = m_parent.lock ();
185 
186  if (t_parent)
187  return t_parent->find_subfunction (name);
188 
189  return octave_value ();
190 }
191 
192 void
194 {
195  for (auto& nm_sf : m_subfunctions)
196  {
197  octave_function *fcn = nm_sf.second.function_value ();
198 
199  if (fcn)
200  fcn->mark_as_private_function (class_name);
201  }
202 }
203 
204 std::list<std::string>
206 {
207  std::list<std::string> retval;
208 
209  auto pscope = parent_scope_rep ();
210 
211  while (pscope)
212  {
213  retval.push_back (pscope->fcn_name ());
214 
215  pscope = pscope->parent_scope_rep ();
216  }
217 
218  return retval;
219 }
220 
221 void
222 symbol_scope_rep::set_parent (const std::shared_ptr<symbol_scope_rep>& parent)
223 {
224  m_parent = std::weak_ptr<symbol_scope_rep> (parent);
225 }
226 
227 void
228 symbol_scope_rep::set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent)
229 {
230  m_primary_parent = std::weak_ptr<symbol_scope_rep> (parent);
231 }
232 
233 void
234 symbol_scope_rep::cache_dir_name (const std::string& name)
235 {
236  m_dir_name = sys::canonicalize_file_name (name);
237 }
238 
239 bool
240 symbol_scope_rep::is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const
241 {
242  if (is_nested ())
243  {
244  // Since is_nested is true, the following should always return a
245  // valid scope.
246 
247  auto t_parent = m_parent.lock ();
248 
249  if (t_parent)
250  {
251  // SCOPE is the parent of this scope: this scope is a child
252  // of SCOPE.
253 
254  if (t_parent == scope)
255  return true;
256  }
257 
258  auto t_primary_parent = m_primary_parent.lock ();
259 
260  if (t_primary_parent)
261  {
262  // SCOPE is the primary parent of this scope: this scope is a
263  // child (or grandchild) of SCOPE.
264  if (t_primary_parent == scope)
265  return true;
266 
267  // SCOPE and this scope share the same primary parent: they are
268  // siblings (or cousins)
269  auto scope_primary_parent = scope->primary_parent_scope_rep ();
270  if (t_primary_parent == scope_primary_parent)
271  return true;
272  }
273  }
274 
275  return false;
276 }
277 
278 void
279 symbol_scope_rep::mark_as_variable (const std::string& nm)
280 {
281  table_iterator p = m_symbols.find (nm);
282 
283  if (p != m_symbols.end ())
284  p->second.mark_as_variable ();
285 }
286 
287 void
288 symbol_scope_rep::mark_as_variables (const std::list<std::string>& lst)
289 {
290  for (const auto& nm : lst)
291  mark_as_variable (nm);
292 }
293 
294 bool
295 symbol_scope_rep::is_variable (const std::string& nm) const
296 {
297  table_const_iterator p = m_symbols.find (nm);
298 
299  // FIXME: maybe we should also mark formal parameters as variables?
300 
301  if (p != m_symbols.end () && p->second.is_variable ())
302  return true;
303 
304  if (is_nested ())
305  {
306  auto t_parent = m_parent.lock ();
307 
308  return t_parent ? t_parent->is_variable (nm) : false;
309  }
310 
311  return false;
312 }
313 
314 void
316 {
317  auto t_parent = m_parent.lock ();
318 
319  if (t_parent)
320  {
321  // fix bad symbol_records
322  for (auto& nm_sr : m_symbols)
323  {
324  symbol_record& ours = nm_sr.second;
325 
326  std::size_t offset = 0;
327 
328  if (! ours.is_formal () && is_nested ())
329  t_parent->look_nonlocal (nm_sr.first, offset, ours);
330  }
331 
332  // The scopes of nested functions are static.
333  if (is_nested ())
334  m_is_static = true;
335  }
336  else if (m_children.size ())
337  {
338  // Parents of nested functions have static scopes.
339  m_is_static = true;
340  }
341 
342  for (auto& scope_obj : m_children)
343  scope_obj.update_nest ();
344 }
345 
346 bool
347 symbol_scope_rep::look_nonlocal (const std::string& name,
348  std::size_t offset,
349  symbol_record& result)
350 {
351  offset++;
352 
353  table_iterator p = m_symbols.find (name);
354 
355  if (p == m_symbols.end ())
356  {
357  auto t_parent = m_parent.lock ();
358 
359  if (is_nested () && t_parent)
360  return t_parent->look_nonlocal (name, offset, result);
361  }
362  else
363  {
364  // Add scope offsets because the one we found may be used in
365  // this scope but initially from another parent scope beyond
366  // that. The parent offset will already point to the first
367  // occurrence because we do the overall nesting update from the
368  // parent function down through the lists of all children.
369 
370  std::size_t t_frame_offset = offset + p->second.frame_offset ();
371  std::size_t t_data_offset = p->second.data_offset ();
372 
373  result.set_frame_offset (t_frame_offset);
374  result.set_data_offset (t_data_offset);
375 
376  return true;
377  }
378 
379  return false;
380 }
381 
382 std::list<octave_value>
384 {
385  if (! m_rep)
386  return std::list<octave_value> ();
387 
388  if (is_primary_fcn_scope ())
389  return m_rep->localfunctions ();
390 
391  std::shared_ptr<symbol_scope_rep> ppsr
392  = m_rep->primary_parent_scope_rep ();
393 
394  if (! ppsr)
395  return std::list<octave_value> ();
396 
397  return ppsr->localfunctions ();
398 }
399 
400 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:155
octave::symbol_scope scope()
Definition: ov-usr-fcn.h:90
octave_user_code * user_code_value(bool silent=false) const
void set_data_offset(std::size_t offset)
Definition: symrec.h:200
std::string name() const
Definition: symrec.h:207
void set_frame_offset(std::size_t offset)
Definition: symrec.h:195
void mark_added_static()
Definition: symrec.h:218
bool is_formal() const
Definition: symrec.h:212
octave_value dump() const
Definition: symrec.h:228
void mark_subfunctions_in_scope_as_private(const std::string &class_name)
Definition: symscope.cc:193
std::shared_ptr< symbol_scope_rep > parent_scope_rep() const
Definition: symscope.h:104
octave_value dump_symbols_map() const
Definition: symscope.cc:151
void cache_dir_name(const std::string &name)
Definition: symscope.cc:234
bool is_relative(const std::shared_ptr< symbol_scope_rep > &scope) const
Definition: symscope.cc:240
std::string name() const
Definition: symscope.h:247
void set_primary_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:228
std::map< std::string, symbol_record >::iterator table_iterator
Definition: symscope.h:61
std::list< std::string > parent_fcn_names() const
Definition: symscope.cc:205
void mark_as_variables(const std::list< std::string > &lst)
Definition: symscope.cc:288
bool is_variable(const std::string &nm) const
Definition: symscope.cc:295
std::map< std::string, octave_value >::const_iterator subfunctions_const_iterator
Definition: symscope.h:64
std::size_t num_symbols() const
Definition: symscope.h:84
void update_nest()
Definition: symscope.cc:315
symbol_record insert(const std::string &name)
Definition: symscope.cc:66
octave_value find_subfunction(const std::string &name) const
Definition: symscope.cc:177
octave_value dump() const
Definition: symscope.cc:136
bool is_nested() const
Definition: symscope.h:92
void set_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:222
void mark_as_variable(const std::string &nm)
Definition: symscope.cc:279
std::list< symbol_record > symbol_list() const
Definition: symscope.cc:166
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:55
std::list< octave_value > localfunctions() const
Definition: symscope.cc:98
bool look_nonlocal(const std::string &name, std::size_t offset, symbol_record &result)
Definition: symscope.cc:347
bool is_primary_fcn_scope() const
Definition: symscope.h:664
std::list< octave_value > localfunctions() const
Definition: symscope.cc:383
std::list< std::string > parent_fcn_names() const
Definition: symscope.h:608
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
T octave_idx_type m
Definition: mx-inlines.cc:781
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:798
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))