GNU Octave  9.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-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()) ? '\'' :'"'))