1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1993-2021 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 43 namespace octave 44 { insert_local(const std::string & name)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 insert_symbol_record(symbol_record & sr)54 void symbol_scope_rep::insert_symbol_record (symbol_record& sr) 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 insert(const std::string & name)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 localfunctions(void) const95 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 octave::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 132 octave_value dump(void) const133 symbol_scope_rep::dump (void) const 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 146 octave_value dump_symbols_map(void) const147 symbol_scope_rep::dump_symbols_map (void) const 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 symbol_list(void) const161 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 171 octave_value find_subfunction(const std::string & name) const172 symbol_scope_rep::find_subfunction (const std::string& name) const 173 { 174 subfunctions_const_iterator p = m_subfunctions.find (name); 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 mark_subfunctions_in_scope_as_private(const std::string & class_name)188 symbol_scope_rep::mark_subfunctions_in_scope_as_private (const std::string& class_name) 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 void cache_parent_fcn_names(const std::list<std::string> & names)200 symbol_scope_rep::cache_parent_fcn_names (const std::list<std::string>& names) 201 { 202 m_parent_fcn_names = names; 203 204 if (m_code && m_code->is_user_function ()) 205 { 206 octave_user_function *fcn 207 = dynamic_cast<octave_user_function *> (m_code); 208 209 fcn->stash_parent_fcn_name (names.front ()); 210 } 211 } 212 213 void set_parent(const std::shared_ptr<symbol_scope_rep> & parent)214 symbol_scope_rep::set_parent (const std::shared_ptr<symbol_scope_rep>& parent) 215 { 216 m_parent = std::weak_ptr<symbol_scope_rep> (parent); 217 } 218 219 void set_primary_parent(const std::shared_ptr<symbol_scope_rep> & parent)220 symbol_scope_rep::set_primary_parent (const std::shared_ptr<symbol_scope_rep>& parent) 221 { 222 m_primary_parent = std::weak_ptr<symbol_scope_rep> (parent); 223 } 224 225 void cache_dir_name(const std::string & name)226 symbol_scope_rep::cache_dir_name (const std::string& name) 227 { 228 m_dir_name = octave::sys::canonicalize_file_name (name); 229 } 230 231 bool is_relative(const std::shared_ptr<symbol_scope_rep> & scope) const232 symbol_scope_rep::is_relative (const std::shared_ptr<symbol_scope_rep>& scope) const 233 { 234 if (is_nested ()) 235 { 236 // Since is_nested is true, the following should always return a 237 // valid scope. 238 239 auto t_parent = m_parent.lock (); 240 241 if (t_parent) 242 { 243 // SCOPE is the parent of this scope: this scope is a child 244 // of SCOPE. 245 246 if (t_parent == scope) 247 return true; 248 } 249 250 auto t_primary_parent = m_primary_parent.lock (); 251 252 if (t_primary_parent) 253 { 254 // SCOPE is the primary parent of this scope: this scope is a 255 // child (or grandchild) of SCOPE. 256 if (t_primary_parent == scope) 257 return true; 258 259 // SCOPE and this scope share the same primary parent: they are 260 // siblings (or cousins) 261 auto scope_primary_parent = scope->primary_parent_scope_rep (); 262 if (t_primary_parent == scope_primary_parent) 263 return true; 264 } 265 } 266 267 return false; 268 } 269 update_nest(void)270 void symbol_scope_rep::update_nest (void) 271 { 272 auto t_parent = m_parent.lock (); 273 274 if (t_parent) 275 { 276 // fix bad symbol_records 277 for (auto& nm_sr : m_symbols) 278 { 279 symbol_record& ours = nm_sr.second; 280 281 std::size_t offset = 0; 282 283 if (! ours.is_formal () && is_nested ()) 284 t_parent->look_nonlocal (nm_sr.first, offset, ours); 285 } 286 287 // The scopes of nested functions are static. 288 if (is_nested ()) 289 m_is_static = true; 290 } 291 else if (m_children.size ()) 292 { 293 // Parents of nested functions have static scopes. 294 m_is_static = true; 295 } 296 297 std::list<std::string> plst = parent_fcn_names (); 298 plst.push_front (m_fcn_name); 299 300 for (auto& scope_obj : m_children) 301 { 302 scope_obj.cache_parent_fcn_names (plst); 303 scope_obj.update_nest (); 304 } 305 } 306 look_nonlocal(const std::string & name,std::size_t offset,symbol_record & result)307 bool symbol_scope_rep::look_nonlocal (const std::string& name, 308 std::size_t offset, symbol_record& result) 309 { 310 offset++; 311 312 table_iterator p = m_symbols.find (name); 313 314 if (p == m_symbols.end ()) 315 { 316 auto t_parent = m_parent.lock (); 317 318 if (is_nested () && t_parent) 319 return t_parent->look_nonlocal (name, offset, result); 320 } 321 else 322 { 323 // Add scope offsets because the one we found may be used in 324 // this scope but initially from another parent scope beyond 325 // that. The parent offset will already point to the first 326 // occurrence because we do the overall nesting update from the 327 // parent function down through the lists of all children. 328 329 std::size_t t_frame_offset = offset + p->second.frame_offset (); 330 std::size_t t_data_offset = p->second.data_offset (); 331 332 result.set_frame_offset (t_frame_offset); 333 result.set_data_offset (t_data_offset); 334 335 return true; 336 } 337 338 return false; 339 } 340 localfunctions(void) const341 std::list<octave_value> symbol_scope::localfunctions (void) const 342 { 343 if (! m_rep) 344 return std::list<octave_value> (); 345 346 if (is_primary_fcn_scope ()) 347 return m_rep->localfunctions (); 348 349 std::shared_ptr<symbol_scope_rep> ppsr 350 = m_rep->primary_parent_scope_rep (); 351 352 if (! ppsr) 353 return std::list<octave_value> (); 354 355 return ppsr->localfunctions (); 356 } 357 } 358