GNU Octave 7.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-2022 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
43namespace octave
44{
46 {
47 symbol_record sym (name);
48
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
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 return octave_value (m);
144 }
145
148 {
149 std::map<std::string, octave_value> info_map;
150
151 for (const auto& nm_sr : m_symbols)
152 {
153 std::string nm = nm_sr.first;
154 symbol_record sr = nm_sr.second;
155 info_map[nm] = sr.dump ();
156 }
157
158 return octave_value (info_map);
159 }
160
161 std::list<symbol_record> symbol_scope_rep::symbol_list (void) const
162 {
163 std::list<symbol_record> retval;
164
165 for (const auto& nm_sr : m_symbols)
166 retval.push_back (nm_sr.second);
167
168 return retval;
169 }
170
172 symbol_scope_rep::find_subfunction (const std::string& name) const
173 {
175
176 if (p != m_subfunctions.end ())
177 return p->second;
178
179 auto t_parent = m_parent.lock ();
180
181 if (t_parent)
182 return t_parent->find_subfunction (name);
183
184 return octave_value ();
185 }
186
187 void
189 {
190 for (auto& nm_sf : m_subfunctions)
191 {
192 octave_function *fcn = nm_sf.second.function_value ();
193
194 if (fcn)
195 fcn->mark_as_private_function (class_name);
196 }
197 }
198
199 std::list<std::string>
201 {
202 std::list<std::string> retval;
203
204 auto pscope = parent_scope_rep ();
205
206 while (pscope)
207 {
208 retval.push_back (pscope->fcn_name ());
209
210 pscope = pscope->parent_scope_rep ();
211 }
212
213 return retval;
214 }
215
216 void
217 symbol_scope_rep::set_parent (const std::shared_ptr<symbol_scope_rep>& parent)
218 {
219 m_parent = std::weak_ptr<symbol_scope_rep> (parent);
220 }
221
222 void
223 symbol_scope_rep::set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent)
224 {
225 m_primary_parent = std::weak_ptr<symbol_scope_rep> (parent);
226 }
227
228 void
230 {
232 }
233
234 bool
235 symbol_scope_rep::is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const
236 {
237 if (is_nested ())
238 {
239 // Since is_nested is true, the following should always return a
240 // valid scope.
241
242 auto t_parent = m_parent.lock ();
243
244 if (t_parent)
245 {
246 // SCOPE is the parent of this scope: this scope is a child
247 // of SCOPE.
248
249 if (t_parent == scope)
250 return true;
251 }
252
253 auto t_primary_parent = m_primary_parent.lock ();
254
255 if (t_primary_parent)
256 {
257 // SCOPE is the primary parent of this scope: this scope is a
258 // child (or grandchild) of SCOPE.
259 if (t_primary_parent == scope)
260 return true;
261
262 // SCOPE and this scope share the same primary parent: they are
263 // siblings (or cousins)
264 auto scope_primary_parent = scope->primary_parent_scope_rep ();
265 if (t_primary_parent == scope_primary_parent)
266 return true;
267 }
268 }
269
270 return false;
271 }
272
273 void symbol_scope_rep::mark_as_variable (const std::string& nm)
274 {
275 table_iterator p = m_symbols.find (nm);
276
277 if (p != m_symbols.end ())
278 p->second.mark_as_variable ();
279 }
280
281 void symbol_scope_rep::mark_as_variables (const std::list<std::string>& lst)
282 {
283 for (const auto& nm : lst)
284 mark_as_variable (nm);
285 }
286
287 bool symbol_scope_rep::is_variable (const std::string& nm) const
288 {
289 table_const_iterator p = m_symbols.find (nm);
290
291 // FIXME: maybe we should also mark formal parameters as variables?
292
293 if (p != m_symbols.end () && p->second.is_variable ())
294 return true;
295
296 if (is_nested ())
297 {
298 auto t_parent = m_parent.lock ();
299
300 return t_parent ? t_parent->is_variable (nm) : false;
301 }
302
303 return false;
304 }
305
307 {
308 auto t_parent = m_parent.lock ();
309
310 if (t_parent)
311 {
312 // fix bad symbol_records
313 for (auto& nm_sr : m_symbols)
314 {
315 symbol_record& ours = nm_sr.second;
316
317 std::size_t offset = 0;
318
319 if (! ours.is_formal () && is_nested ())
320 t_parent->look_nonlocal (nm_sr.first, offset, ours);
321 }
322
323 // The scopes of nested functions are static.
324 if (is_nested ())
325 m_is_static = true;
326 }
327 else if (m_children.size ())
328 {
329 // Parents of nested functions have static scopes.
330 m_is_static = true;
331 }
332
333 for (auto& scope_obj : m_children)
334 scope_obj.update_nest ();
335 }
336
337 bool symbol_scope_rep::look_nonlocal (const std::string& name,
338 std::size_t offset, symbol_record& result)
339 {
340 offset++;
341
342 table_iterator p = m_symbols.find (name);
343
344 if (p == m_symbols.end ())
345 {
346 auto t_parent = m_parent.lock ();
347
348 if (is_nested () && t_parent)
349 return t_parent->look_nonlocal (name, offset, result);
350 }
351 else
352 {
353 // Add scope offsets because the one we found may be used in
354 // this scope but initially from another parent scope beyond
355 // that. The parent offset will already point to the first
356 // occurrence because we do the overall nesting update from the
357 // parent function down through the lists of all children.
358
359 std::size_t t_frame_offset = offset + p->second.frame_offset ();
360 std::size_t t_data_offset = p->second.data_offset ();
361
362 result.set_frame_offset (t_frame_offset);
363 result.set_data_offset (t_data_offset);
364
365 return true;
366 }
367
368 return false;
369 }
370
371 std::list<octave_value> symbol_scope::localfunctions (void) const
372 {
373 if (! m_rep)
374 return std::list<octave_value> ();
375
377 return m_rep->localfunctions ();
378
379 std::shared_ptr<symbol_scope_rep> ppsr
380 = m_rep->primary_parent_scope_rep ();
381
382 if (! ppsr)
383 return std::list<octave_value> ();
384
385 return ppsr->localfunctions ();
386 }
387}
void set_data_offset(std::size_t offset)
Definition: symrec.h:201
void mark_added_static(void)
Definition: symrec.h:218
bool is_formal(void) const
Definition: symrec.h:212
octave_value dump(void) const
Definition: symrec.h:228
void set_frame_offset(std::size_t offset)
Definition: symrec.h:197
std::string name(void) const
Definition: symrec.h:207
std::weak_ptr< symbol_scope_rep > m_primary_parent
Primary (top) parent of nested function (may be null).
Definition: symscope.h:356
std::string m_name
Name for this scope (usually the corresponding filename of the function corresponding to the scope).
Definition: symscope.h:315
std::vector< symbol_scope > m_children
Child nested functions.
Definition: symscope.h:360
std::map< std::string, octave_value >::const_iterator subfunctions_const_iterator
Definition: symscope.h:64
std::string name(void) const
Definition: symscope.h:251
std::string m_dir_name
The directory associated with m_code.
Definition: symscope.h:347
std::map< std::string, octave_value > m_subfunctions
Map from symbol names to subfunctions.
Definition: symscope.h:323
bool is_relative(const std::shared_ptr< symbol_scope_rep > &scope) const
Definition: symscope.cc:235
octave_value dump(void) const
Definition: symscope.cc:133
void set_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:217
std::map< std::string, symbol_record > m_symbols
Map from symbol names to symbol info.
Definition: symscope.h:319
bool is_variable(const std::string &nm) const
Definition: symscope.cc:287
symbol_record insert_local(const std::string &name)
Definition: symscope.cc:45
void mark_subfunctions_in_scope_as_private(const std::string &class_name)
Definition: symscope.cc:188
void mark_as_variable(const std::string &nm)
Definition: symscope.cc:273
octave_value dump_symbols_map(void) const
Definition: symscope.cc:147
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
symbol_record insert(const std::string &name)
Definition: symscope.cc:64
octave_value find_subfunction(const std::string &name) const
Definition: symscope.cc:172
std::list< octave_value > localfunctions(void) const
Definition: symscope.cc:95
std::map< std::string, symbol_record >::const_iterator table_const_iterator
Definition: symscope.h:59
bool m_is_static
If true then no variables can be added.
Definition: symscope.h:368
std::size_t num_symbols(void) const
Definition: symscope.h:88
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:337
bool is_nested(void) const
Definition: symscope.h:96
std::list< std::string > parent_fcn_names(void) const
Definition: symscope.cc:200
std::size_t m_nesting_depth
If true, then this scope belongs to a nested function.
Definition: symscope.h:364
void set_primary_parent(const std::shared_ptr< symbol_scope_rep > &parent)
Definition: symscope.cc:223
std::map< std::string, symbol_record >::iterator table_iterator
Definition: symscope.h:61
void insert_symbol_record(symbol_record &sr)
Definition: symscope.cc:54
void mark_as_variables(const std::list< std::string > &lst)
Definition: symscope.cc:281
std::shared_ptr< symbol_scope_rep > parent_scope_rep(void) const
Definition: symscope.h:108
void cache_dir_name(const std::string &name)
Definition: symscope.cc:229
std::list< symbol_record > symbol_list(void) const
Definition: symscope.cc:161
std::shared_ptr< symbol_scope_rep > m_rep
Definition: symscope.h:726
std::list< std::string > parent_fcn_names(void) const
Definition: symscope.h:593
bool is_primary_fcn_scope(void) const
Definition: symscope.h:649
std::list< octave_value > localfunctions(void) const
Definition: symscope.cc:371
virtual octave_function * function_value(bool silent=false)
Definition: ov-base.cc:935
virtual void mark_as_private_function(const std::string &cname="")
Definition: ov-fcn.h:156
octave::symbol_scope scope(void)
Definition: ov-usr-fcn.h:93
OCTINTERP_API octave_user_code * user_code_value(bool silent=false) const
octave_value dump_function_map(const std::map< std::string, octave_value > &fcn_map)
Definition: fcn-info.cc:1131
QString name
std::string canonicalize_file_name(const std::string &name)
Definition: file-ops.cc:688
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))