comparison src/symtab.h @ 14544:be18c9e359bf

Nested function support (bug #35772) * src/oct-parse.yy (push_fcn_symtab, recover_from_parsing_function) (eval_string): Keep track of a stack of nested functions. (parse_fcn_file): Keep track of a stack of nested functions and remove warning that nested functions are not supported. (frob_function): Call symbol_table::install_nestfunction for nested functions. (finish_function): Call symbol_table::update_nest on top level functions. * src/ov-fcn-handle.cc (octave_fcn_handle::octave_fcn_handle): Error when creating a handle to a nested function. * src/ov-usr-fcn.cc (octave_user_function::octave_user_function): Initialize new members. (octave_user_function::do_multi_index_op): Use active_context to determine execution context. * src/ov-usr-fcn.h (octave_user_function::active_context, octave_user_function::is_nested_function, octave_user_function::mark_as_nested_function): New functions. * src/pt-id.h (symbol_table::xsym): Check symbol validity. * src/symtab.cc (symbol_table::symbol_record::symbol_record_rep::active_context, symbol_table::install_nestfunction, symbol_table::do_update_nest): New functions. (symbol_table::symbol_record::symbol_record_rep::dump): Use varval () instead of varval (current_context). (symbol_table::fcn_info::fcn_info_rep::xfind, symbol_table::fcn_info::fcn_info_rep::x_builtin_find): Allow for parents of parents in subfunction search. * src/symtab.h (symbol_table::symbol_record::symbol_record_rep::symbol_record_rep, symbol_table::symbol_record::symbol_record): New parameter, decl_scope. (symbol_table::symbol_record::symbol_record_rep::force_variable, symbol_table::symbol_record::force_variable, symbol_table::symbol_record::symbol_record_rep::varref, symbol_table::symbol_record::varref, symbol_table::symbol_record::symbol_record_rep::varval, symbol_table::symbol_record::varval, symbol_table::symbol_record::symbol_record_rep::is_defined, symbol_table::symbol_record::is_defined, symbol_table::symbol_record::symbol_record_rep::is_variable, symbol_table::symbol_record::is_variable, symbol_table::symbol_record::varval, symbol_table::symbol_record::symbol_record_rep::varval): Use xdefault_context. symbol_table::symbol_record::symbol_record_rep::push_context, symbol_table::symbol_record::push_context, symbol_table::symbol_record::symbol_record_rep::pop_context, symbol_table::symbol_record::pop_context, symbol_table::symbol_record::symbol_record_rep::clear, symbol_table::symbol_record::clear): Only work when the decl_scope of the symbol is the active scope. (symbol_table::symbol_record::symbol_record_rep::is_valid, symbol_table::symbol_record::is_valid, symbol_table::symbol_record::symbol_record_rep::invalidate, symbol_table::symbol_record::invalidate, symbol_table::symbol_record::symbol_record_rep::set_curr_fcn, symbol_table::symbol_record::set_curr_fcn, symbol_table::symbol_record::symbol_record_rep::scope, symbol_table::symbol_record::scope, symbol_table::symbol_record::active_context, symbol_table::update_nest, symbol_table::symbol_table, symbol_table::add_nest_child, symbol_table::look_nonlocal): New functions. (symbol_table::symbol_record::symbol_record_rep::init_persistent): Init to xdefault_context instead of xcurrent_context. (symbol_table::symbol_record::symbol_record_rep::dup, symbol_table::symbol_record::dup): New parameter, scope. (symbol_table::set_scope, symbol_table::dup_scope, symbol_table:;get_instance): Pass scope_id to symbol_table constructor. (symbol_table::find_symbol, symbol_table::glob_global_variables, symbol_table::regexp_global_variables): Specify scope when creating symbol_record. (symbol_table::force_variable, symbol_table::varref, symbol_table::varval, symbol_table::all_variables): Default to xdefault_context instead of xcurrent_context. (symbol_table::do_dup_scope): Pass scope of new symbol table to symbol dup. (symbol_table::do_insert): Check nest_parent for nonlocals. (symbol_table::do_push_context, symbol_table::do_pop_context, symbol_table::do_clear_variables, symbol_table::do_clear_objects, symbol_table::do_clear_variable, symbol_table::do_clear_variable_pattern, symbol_table::do_clear_variable_regexp): Pass my_scope to symbol. * test/Makefile.am: Include nest/module.mk. * test/nest/arg_nest.m: New file. * test/nest/arg_ret.m: New file. * test/nest/module.mk: New file. * test/nest/no_closure.m: New file. * test/nest/persistent_nest.m: New file. * test/nest/recursive_nest.m: New file. * test/nest/recursive_nest2.m: New file. * test/nest/recursive_nest3.m: New file. * test/nest/scope0.m: New file. * test/nest/scope1.m: New file. * test/nest/scope2.m: New file. * test/nest/scope3.m: New file. * test/nest/script_nest.m: New file. * test/nest/script_nest_script.m: New file. * test/nest/test_nest.m: New file. * test/nest/varg_nest.m: New file. * test/nest/varg_nest2.m: New file.
author Max Brister <max@2bass.com>
date Tue, 10 Apr 2012 20:42:22 -0400
parents 72c96de7a403
children e4d380c01dcf 460a3c6d8bf1 f25d2224fa02
comparison
equal deleted inserted replaced
14543:e47d929fde8f 14544:be18c9e359bf
204 class 204 class
205 symbol_record_rep 205 symbol_record_rep
206 { 206 {
207 public: 207 public:
208 208
209 symbol_record_rep (const std::string& nm, const octave_value& v, 209 symbol_record_rep (scope_id s, const std::string& nm,
210 unsigned int sc) 210 const octave_value& v, unsigned int sc)
211 : name (nm), value_stack (), storage_class (sc), finfo (), count (1) 211 : decl_scope (s), curr_fcn (0), name (nm), value_stack (),
212 storage_class (sc), finfo (), valid (true), count (1)
212 { 213 {
213 value_stack.push_back (v); 214 value_stack.push_back (v);
214 } 215 }
215 216
216 void force_variable (context_id context) 217 void force_variable (context_id context = xdefault_context)
217 { 218 {
219 if (context == xdefault_context)
220 context = active_context ();
221
218 octave_value& val = varref (context); 222 octave_value& val = varref (context);
219 223
220 if (! val.is_defined ()) 224 if (! val.is_defined ())
221 mark_forced (); 225 mark_forced ();
222 } 226 }
223 227
224 octave_value& varref (context_id context) 228 octave_value& varref (context_id context = xdefault_context)
225 { 229 {
226 if (is_global ()) 230 if (is_global ())
227 return symbol_table::global_varref (name); 231 return symbol_table::global_varref (name);
228 else if (is_persistent ()) 232 else if (is_persistent ())
229 return symbol_table::persistent_varref (name); 233 return symbol_table::persistent_varref (name);
230 else 234 else
231 { 235 {
236 if (context == xdefault_context)
237 context = active_context ();
238
232 context_id n = value_stack.size (); 239 context_id n = value_stack.size ();
233 while (n++ <= context) 240 while (n++ <= context)
234 value_stack.push_back (octave_value ()); 241 value_stack.push_back (octave_value ());
235 242
236 return value_stack[context]; 243 return value_stack[context];
237 } 244 }
238 } 245 }
239 246
240 octave_value varval (context_id context) const 247 octave_value varval (context_id context = xdefault_context) const
241 { 248 {
242 if (is_global ()) 249 if (is_global ())
243 return symbol_table::global_varval (name); 250 return symbol_table::global_varval (name);
244 else if (is_persistent ()) 251 else if (is_persistent ())
245 return symbol_table::persistent_varval (name); 252 return symbol_table::persistent_varval (name);
246 else 253 else
247 { 254 {
255 if (context == xdefault_context)
256 context = active_context ();
257
248 if (context < value_stack.size ()) 258 if (context < value_stack.size ())
249 return value_stack[context]; 259 return value_stack[context];
250 else 260 else
251 return octave_value (); 261 return octave_value ();
252 } 262 }
253 } 263 }
254 264
255 void push_context (void) 265 void push_context (scope_id s)
256 { 266 {
257 if (! (is_persistent () || is_global ())) 267 if (! (is_persistent () || is_global ())
268 && s == scope ())
258 value_stack.push_back (octave_value ()); 269 value_stack.push_back (octave_value ());
259 } 270 }
260 271
261 // If pop_context returns 0, we are out of values and this element 272 // If pop_context returns 0, we are out of values and this element
262 // of the symbol table should be deleted. This can happen for 273 // of the symbol table should be deleted. This can happen for
270 // endif 281 // endif
271 // endfunction 282 // endfunction
272 // 283 //
273 // Here, X should only exist in the final stack frame. 284 // Here, X should only exist in the final stack frame.
274 285
275 size_t pop_context (void) 286 size_t pop_context (scope_id s)
276 { 287 {
277 size_t retval = 1; 288 size_t retval = 1;
278 289
279 if (! (is_persistent () || is_global ())) 290 if (! (is_persistent () || is_global ())
291 && s == scope ())
280 { 292 {
281 value_stack.pop_back (); 293 value_stack.pop_back ();
282 retval = value_stack.size (); 294 retval = value_stack.size ();
283 } 295 }
284 296
285 return retval; 297 return retval;
286 } 298 }
287 299
288 void clear (void) 300 void clear (void) { clear (scope ()); }
289 { 301
290 if (! (is_hidden () || is_inherited ())) 302 void clear (scope_id s)
303 {
304 if (! (is_hidden () || is_inherited ())
305 && s == scope ())
291 { 306 {
292 if (is_global ()) 307 if (is_global ())
293 unmark_global (); 308 unmark_global ();
294 309
295 if (is_persistent ()) 310 if (is_persistent ())
296 { 311 {
297 symbol_table::persistent_varref (name) 312 symbol_table::persistent_varref (name)
298 = varval (xcurrent_context); 313 = varval ();
299 314
300 unmark_persistent (); 315 unmark_persistent ();
301 } 316 }
302 317
303 varref (xcurrent_context) = octave_value (); 318 varref () = octave_value ();
304 } 319 }
305 } 320 }
306 321
307 bool is_defined (context_id context) const 322 bool is_defined (context_id context = xdefault_context) const
308 { 323 {
324 if (context == xdefault_context)
325 context = active_context ();
326
309 return varval (context).is_defined (); 327 return varval (context).is_defined ();
310 } 328 }
311 329
330 bool is_valid (void) const
331 {
332 return valid;
333 }
334
312 bool is_variable (context_id context) const 335 bool is_variable (context_id context) const
313 { 336 {
337 if (context == xdefault_context)
338 context = active_context ();
339
314 return (! is_local () || is_defined (context) || is_forced ()); 340 return (! is_local () || is_defined (context) || is_forced ());
315 } 341 }
316 342
317 bool is_local (void) const { return storage_class & local; } 343 bool is_local (void) const { return storage_class & local; }
318 bool is_automatic (void) const { return storage_class & automatic; } 344 bool is_automatic (void) const { return storage_class & automatic; }
353 void unmark_persistent (void) { storage_class &= ~persistent; } 379 void unmark_persistent (void) { storage_class &= ~persistent; }
354 void unmark_forced (void) { storage_class &= ~forced; } 380 void unmark_forced (void) { storage_class &= ~forced; }
355 381
356 void init_persistent (void) 382 void init_persistent (void)
357 { 383 {
358 if (! is_defined (xcurrent_context)) 384 if (! is_defined ())
359 { 385 {
360 mark_persistent (); 386 mark_persistent ();
361 387
362 varref (xcurrent_context) = symbol_table::persistent_varval (name); 388 varref () = symbol_table::persistent_varval (name);
363 } 389 }
364 // FIXME -- this causes trouble with recursive calls. 390 // FIXME -- this causes trouble with recursive calls.
365 // else 391 // else
366 // error ("unable to declare existing variable persistent"); 392 // error ("unable to declare existing variable persistent");
367 } 393 }
368 394
395 void invalidate (void)
396 {
397 valid = false;
398 }
399
369 void erase_persistent (void) 400 void erase_persistent (void)
370 { 401 {
371 unmark_persistent (); 402 unmark_persistent ();
372 symbol_table::erase_persistent (name); 403 symbol_table::erase_persistent (name);
373 } 404 }
374 405
375 symbol_record_rep *dup (void) const 406 context_id active_context (void) const;
376 { 407
377 return new symbol_record_rep (name, varval (xcurrent_context), 408 scope_id scope (void) const { return decl_scope; }
409
410 void set_curr_fcn (octave_user_function *fcn)
411 {
412 curr_fcn = fcn;
413 }
414
415 symbol_record_rep *dup (scope_id new_scope) const
416 {
417 return new symbol_record_rep (new_scope, name, varval (),
378 storage_class); 418 storage_class);
379 } 419 }
380 420
381 void dump (std::ostream& os, const std::string& prefix) const; 421 void dump (std::ostream& os, const std::string& prefix) const;
382 422
423 scope_id decl_scope;
424
425 octave_user_function* curr_fcn;
426
383 std::string name; 427 std::string name;
384 428
385 std::deque<octave_value> value_stack; 429 std::deque<octave_value> value_stack;
386 430
387 unsigned int storage_class; 431 unsigned int storage_class;
388 432
389 fcn_info *finfo; 433 fcn_info *finfo;
434
435 bool valid;
390 436
391 octave_refcount<size_t> count; 437 octave_refcount<size_t> count;
392 438
393 private: 439 private:
394 440
399 symbol_record_rep& operator = (const symbol_record_rep&); 445 symbol_record_rep& operator = (const symbol_record_rep&);
400 }; 446 };
401 447
402 public: 448 public:
403 449
404 symbol_record (const std::string& nm = std::string (), 450 symbol_record (scope_id s = xcurrent_scope,
451 const std::string& nm = std::string (),
405 const octave_value& v = octave_value (), 452 const octave_value& v = octave_value (),
406 unsigned int sc = local) 453 unsigned int sc = local)
407 : rep (new symbol_record_rep (nm, v, sc)) { } 454 : rep (new symbol_record_rep (s, nm, v, sc)) { }
408 455
409 symbol_record (const symbol_record& sr) 456 symbol_record (const symbol_record& sr)
410 : rep (sr.rep) 457 : rep (sr.rep)
411 { 458 {
412 rep->count++; 459 rep->count++;
430 { 477 {
431 if (--rep->count == 0) 478 if (--rep->count == 0)
432 delete rep; 479 delete rep;
433 } 480 }
434 481
435 symbol_record dup (void) const { return symbol_record (rep->dup ()); } 482 symbol_record dup (scope_id new_scope) const
483 {
484 return symbol_record (rep->dup (new_scope));
485 }
436 486
437 std::string name (void) const { return rep->name; } 487 std::string name (void) const { return rep->name; }
438 488
439 octave_value find (const octave_value_list& args = octave_value_list ()) const; 489 octave_value
440 490 find (const octave_value_list& args = octave_value_list ()) const;
441 void force_variable (context_id context = xcurrent_context) 491
492 void force_variable (context_id context = xdefault_context)
442 { 493 {
443 rep->force_variable (context); 494 rep->force_variable (context);
444 } 495 }
445 496
446 octave_value& varref (context_id context = xcurrent_context) 497 octave_value& varref (context_id context = xdefault_context)
447 { 498 {
448 return rep->varref (context); 499 return rep->varref (context);
449 } 500 }
450 501
451 octave_value varval (context_id context = xcurrent_context) const 502 octave_value varval (context_id context = xdefault_context) const
452 { 503 {
453 return rep->varval (context); 504 return rep->varval (context);
454 } 505 }
455 506
456 void push_context (void) { rep->push_context (); } 507 void push_context (scope_id s) { rep->push_context (s); }
457 508
458 size_t pop_context (void) { return rep->pop_context (); } 509 size_t pop_context (scope_id s) { return rep->pop_context (s); }
459 510
460 void clear (void) { rep->clear (); } 511 void clear (void) { rep->clear (); }
461 512
462 bool is_defined (context_id context = xcurrent_context) const 513 void clear (scope_id s) { rep->clear (s); }
514
515 bool is_defined (context_id context = xdefault_context) const
463 { 516 {
464 return rep->is_defined (context); 517 return rep->is_defined (context);
465 } 518 }
466 519
467 bool is_variable (context_id context = xcurrent_context) const 520 bool is_valid (void) const
521 {
522 return rep->is_valid ();
523 }
524
525 bool is_variable (context_id context = xdefault_context) const
468 { 526 {
469 return rep->is_variable (context); 527 return rep->is_variable (context);
470 } 528 }
471 529
472 bool is_local (void) const { return rep->is_local (); } 530 bool is_local (void) const { return rep->is_local (); }
498 556
499 void init_persistent (void) { rep->init_persistent (); } 557 void init_persistent (void) { rep->init_persistent (); }
500 558
501 void erase_persistent (void) { rep->erase_persistent (); } 559 void erase_persistent (void) { rep->erase_persistent (); }
502 560
561 void invalidate (void) { rep->invalidate (); }
562
563 context_id active_context (void) const { return rep->active_context (); }
564
565 scope_id scope (void) const { return rep->scope (); }
566
503 unsigned int xstorage_class (void) const { return rep->storage_class; } 567 unsigned int xstorage_class (void) const { return rep->storage_class; }
568
569 void set_curr_fcn (octave_user_function *fcn) { rep->set_curr_fcn (fcn); }
504 570
505 void 571 void
506 dump (std::ostream& os, const std::string& prefix = std::string ()) const 572 dump (std::ostream& os, const std::string& prefix = std::string ()) const
507 { 573 {
508 rep->dump (os, prefix); 574 rep->dump (os, prefix);
926 { 992 {
927 all_instances_iterator p = all_instances.find (scope); 993 all_instances_iterator p = all_instances.find (scope);
928 994
929 if (p == all_instances.end ()) 995 if (p == all_instances.end ())
930 { 996 {
931 symbol_table *inst = new symbol_table (); 997 symbol_table *inst = new symbol_table (scope);
932 998
933 if (inst) 999 if (inst)
934 all_instances[scope] = instance = inst; 1000 all_instances[scope] = instance = inst;
935 } 1001 }
936 else 1002 else
1007 1073
1008 if (inst) 1074 if (inst)
1009 { 1075 {
1010 scope_id new_scope = alloc_scope (); 1076 scope_id new_scope = alloc_scope ();
1011 1077
1012 symbol_table *new_symbol_table = new symbol_table (); 1078 symbol_table *new_symbol_table = new symbol_table (scope);
1013 1079
1014 if (new_symbol_table) 1080 if (new_symbol_table)
1015 { 1081 {
1016 all_instances[new_scope] = new_symbol_table; 1082 all_instances[new_scope] = new_symbol_table;
1017 1083
1032 static symbol_record 1098 static symbol_record
1033 find_symbol (const std::string& name, scope_id scope = xcurrent_scope) 1099 find_symbol (const std::string& name, scope_id scope = xcurrent_scope)
1034 { 1100 {
1035 symbol_table *inst = get_instance (scope); 1101 symbol_table *inst = get_instance (scope);
1036 1102
1037 return inst ? inst->do_find_symbol (name) : symbol_record (); 1103 return inst ? inst->do_find_symbol (name) :
1104 symbol_record (scope);
1038 } 1105 }
1039 1106
1040 static void 1107 static void
1041 inherit (scope_id scope, scope_id donor_scope, context_id donor_context) 1108 inherit (scope_id scope, scope_id donor_scope, context_id donor_context)
1042 { 1109 {
1072 return inst ? inst->do_insert (name) : foobar; 1139 return inst ? inst->do_insert (name) : foobar;
1073 } 1140 }
1074 1141
1075 static void force_variable (const std::string& name, 1142 static void force_variable (const std::string& name,
1076 scope_id scope = xcurrent_scope, 1143 scope_id scope = xcurrent_scope,
1077 context_id context = xcurrent_context) 1144 context_id context = xdefault_context)
1078 { 1145 {
1079 symbol_table *inst = get_instance (scope); 1146 symbol_table *inst = get_instance (scope);
1080 1147
1081 if (inst) 1148 if (inst)
1082 inst->do_force_variable (name, context); 1149 inst->do_force_variable (name, context);
1083 } 1150 }
1084 1151
1085 static octave_value& varref (const std::string& name, 1152 static octave_value& varref (const std::string& name,
1086 scope_id scope = xcurrent_scope, 1153 scope_id scope = xcurrent_scope,
1087 context_id context = xcurrent_context) 1154 context_id context = xdefault_context)
1088 { 1155 {
1089 static octave_value foobar; 1156 static octave_value foobar;
1090 1157
1091 symbol_table *inst = get_instance (scope); 1158 symbol_table *inst = get_instance (scope);
1092 1159
1093 return inst ? inst->do_varref (name, context) : foobar; 1160 return inst ? inst->do_varref (name, context) : foobar;
1094 } 1161 }
1095 1162
1096 static octave_value varval (const std::string& name, 1163 static octave_value varval (const std::string& name,
1097 scope_id scope = xcurrent_scope, 1164 scope_id scope = xcurrent_scope,
1098 context_id context = xcurrent_context) 1165 context_id context = xdefault_context)
1099 { 1166 {
1100 symbol_table *inst = get_instance (scope); 1167 symbol_table *inst = get_instance (scope);
1101 1168
1102 return inst ? inst->do_varval (name, context) : octave_value (); 1169 return inst ? inst->do_varval (name, context) : octave_value ();
1103 } 1170 }
1261 1328
1262 fcn_table[name] = finfo; 1329 fcn_table[name] = finfo;
1263 } 1330 }
1264 } 1331 }
1265 1332
1333 static void install_nestfunction (const std::string& name,
1334 const octave_value& fcn,
1335 scope_id parent_scope);
1336
1337 static void update_nest (scope_id scope)
1338 {
1339 symbol_table *inst = get_instance (scope);
1340 if (inst)
1341 inst->do_update_nest ();
1342 }
1343
1266 static void install_user_function (const std::string& name, 1344 static void install_user_function (const std::string& name,
1267 const octave_value& fcn) 1345 const octave_value& fcn)
1268 { 1346 {
1269 fcn_table_iterator p = fcn_table.find (name); 1347 fcn_table_iterator p = fcn_table.find (name);
1270 1348
1618 inst->do_mark_global (name); 1696 inst->do_mark_global (name);
1619 } 1697 }
1620 1698
1621 static std::list<symbol_record> 1699 static std::list<symbol_record>
1622 all_variables (scope_id scope = xcurrent_scope, 1700 all_variables (scope_id scope = xcurrent_scope,
1623 context_id context = xcurrent_context, 1701 context_id context = xdefault_context,
1624 bool defined_only = true) 1702 bool defined_only = true)
1625 { 1703 {
1626 symbol_table *inst = get_instance (scope); 1704 symbol_table *inst = get_instance (scope);
1627 1705
1628 return inst 1706 return inst
1670 // We generate a list of symbol_record objects so that 1748 // We generate a list of symbol_record objects so that
1671 // the results from glob_variables and glob_global_variables 1749 // the results from glob_variables and glob_global_variables
1672 // may be handled the same way. 1750 // may be handled the same way.
1673 1751
1674 if (pat.match (p->first)) 1752 if (pat.match (p->first))
1675 retval.push_back (symbol_record (p->first, p->second, 1753 retval.push_back (symbol_record (xglobal_scope,
1754 p->first, p->second,
1676 symbol_record::global)); 1755 symbol_record::global));
1677 } 1756 }
1678 1757
1679 return retval; 1758 return retval;
1680 } 1759 }
1692 // We generate a list of symbol_record objects so that 1771 // We generate a list of symbol_record objects so that
1693 // the results from regexp_variables and regexp_global_variables 1772 // the results from regexp_variables and regexp_global_variables
1694 // may be handled the same way. 1773 // may be handled the same way.
1695 1774
1696 if (pat.is_match (p->first)) 1775 if (pat.is_match (p->first))
1697 retval.push_back (symbol_record (p->first, p->second, 1776 retval.push_back (symbol_record (xglobal_scope,
1777 p->first, p->second,
1698 symbol_record::global)); 1778 symbol_record::global));
1699 } 1779 }
1700 1780
1701 return retval; 1781 return retval;
1702 } 1782 }
1922 { 2002 {
1923 assert (scope != xtop_scope && scope != xglobal_scope); 2003 assert (scope != xtop_scope && scope != xglobal_scope);
1924 symbol_table *inst = get_instance (scope); 2004 symbol_table *inst = get_instance (scope);
1925 // FIXME: normally, functions should not usurp each other's scope. 2005 // FIXME: normally, functions should not usurp each other's scope.
1926 // If for any incredible reason this is needed, call 2006 // If for any incredible reason this is needed, call
1927 // set_user_function (0, scope) first. 2007 // set_user_function (0, scope) first. This may cause problems with
2008 // nested functions, as the curr_fcn of symbol_records must be updated.
1928 assert (inst->curr_fcn == 0 || curr_fcn == 0); 2009 assert (inst->curr_fcn == 0 || curr_fcn == 0);
1929 inst->curr_fcn = curr_fcn; 2010 inst->curr_fcn = curr_fcn;
1930 } 2011 }
1931 2012
1932 static void cleanup (void); 2013 static void cleanup (void);
1951 typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator; 2032 typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator;
1952 typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator; 2033 typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator;
1953 2034
1954 typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator; 2035 typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator;
1955 typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator; 2036 typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator;
2037
2038 // The scope of this symbol table.
2039 scope_id my_scope;
1956 2040
1957 // Name for this table (usually the file name of the function 2041 // Name for this table (usually the file name of the function
1958 // corresponding to the scope); 2042 // corresponding to the scope);
1959 std::string table_name; 2043 std::string table_name;
1960 2044
1961 // Map from symbol names to symbol info. 2045 // Map from symbol names to symbol info.
1962 std::map<std::string, symbol_record> table; 2046 std::map<std::string, symbol_record> table;
1963 2047
2048 // Child nested functions.
2049 std::vector<symbol_table*> nest_children;
2050
2051 // Parent nested function (may be null).
2052 symbol_table *nest_parent;
2053
1964 // The associated user code (may be null). 2054 // The associated user code (may be null).
1965 octave_user_function *curr_fcn; 2055 octave_user_function *curr_fcn;
1966 2056
1967 // Map from names of global variables to values. 2057 // Map from names of global variables to values.
1968 static std::map<std::string, octave_value> global_table; 2058 static std::map<std::string, octave_value> global_table;
1998 2088
1999 static scope_id xcurrent_scope; 2089 static scope_id xcurrent_scope;
2000 2090
2001 static context_id xcurrent_context; 2091 static context_id xcurrent_context;
2002 2092
2003 symbol_table (void) 2093 static const context_id xdefault_context = static_cast<context_id> (-1);
2004 : table_name (), table (), curr_fcn (0), persistent_table () { } 2094
2095 symbol_table (scope_id scope)
2096 : my_scope (scope), table_name (), table (), nest_children (), nest_parent (0),
2097 curr_fcn (0), persistent_table () { }
2005 2098
2006 ~symbol_table (void) { } 2099 ~symbol_table (void) { }
2007 2100
2008 static symbol_table *get_instance (scope_id scope, bool create = true) 2101 static symbol_table *get_instance (scope_id scope, bool create = true)
2009 { 2102 {
2015 { 2108 {
2016 if (scope == xcurrent_scope) 2109 if (scope == xcurrent_scope)
2017 { 2110 {
2018 if (! instance && create) 2111 if (! instance && create)
2019 { 2112 {
2020 symbol_table *inst = new symbol_table (); 2113 symbol_table *inst = new symbol_table (scope);
2021 2114
2022 if (inst) 2115 if (inst)
2023 { 2116 {
2024 all_instances[scope] = instance = inst; 2117 all_instances[scope] = instance = inst;
2025 2118
2039 2132
2040 if (p == all_instances.end ()) 2133 if (p == all_instances.end ())
2041 { 2134 {
2042 if (create) 2135 if (create)
2043 { 2136 {
2044 retval = new symbol_table (); 2137 retval = new symbol_table (scope);
2045 2138
2046 if (retval) 2139 if (retval)
2047 all_instances[scope] = retval; 2140 all_instances[scope] = retval;
2048 else 2141 else
2049 ok = false; 2142 ok = false;
2061 create ? "create" : "find", scope); 2154 create ? "create" : "find", scope);
2062 2155
2063 return retval; 2156 return retval;
2064 } 2157 }
2065 2158
2159 void add_nest_child (symbol_table& st)
2160 {
2161 assert (!st.nest_parent);
2162 nest_children.push_back (&st);
2163 st.nest_parent = this;
2164 }
2165
2066 void insert_symbol_record (const symbol_record& sr) 2166 void insert_symbol_record (const symbol_record& sr)
2067 { 2167 {
2068 table[sr.name ()] = sr; 2168 table[sr.name ()] = sr;
2069 } 2169 }
2070 2170
2071 void 2171 void
2072 do_dup_scope (symbol_table& new_symbol_table) const 2172 do_dup_scope (symbol_table& new_symbol_table) const
2073 { 2173 {
2074 for (table_const_iterator p = table.begin (); p != table.end (); p++) 2174 for (table_const_iterator p = table.begin (); p != table.end (); p++)
2075 new_symbol_table.insert_symbol_record (p->second.dup ()); 2175 new_symbol_table.insert_symbol_record (p->second.dup (new_symbol_table.my_scope));
2076 } 2176 }
2077 2177
2078 symbol_record do_find_symbol (const std::string& name) 2178 symbol_record do_find_symbol (const std::string& name)
2079 { 2179 {
2080 table_iterator p = table.find (name); 2180 table_iterator p = table.find (name);
2124 2224
2125 symbol_record& do_insert (const std::string& name) 2225 symbol_record& do_insert (const std::string& name)
2126 { 2226 {
2127 table_iterator p = table.find (name); 2227 table_iterator p = table.find (name);
2128 2228
2129 return p == table.end () 2229 if (p == table.end ())
2130 ? (table[name] = symbol_record (name)) : p->second; 2230 {
2231 symbol_record parent_symbol;
2232
2233 if (nest_parent && nest_parent->look_nonlocal (name, parent_symbol))
2234 return table[name] = parent_symbol;
2235 else
2236 return table[name] = symbol_record (my_scope, name, octave_value ());
2237 }
2238 else
2239 return p->second;
2131 } 2240 }
2132 2241
2133 void do_force_variable (const std::string& name, context_id context) 2242 void do_force_variable (const std::string& name, context_id context)
2134 { 2243 {
2135 table_iterator p = table.find (name); 2244 table_iterator p = table.find (name);
2205 } 2314 }
2206 2315
2207 void do_push_context (void) 2316 void do_push_context (void)
2208 { 2317 {
2209 for (table_iterator p = table.begin (); p != table.end (); p++) 2318 for (table_iterator p = table.begin (); p != table.end (); p++)
2210 p->second.push_context (); 2319 p->second.push_context (my_scope);
2211 } 2320 }
2212 2321
2213 void do_pop_context (void) 2322 void do_pop_context (void)
2214 { 2323 {
2215 for (table_iterator p = table.begin (); p != table.end (); ) 2324 for (table_iterator p = table.begin (); p != table.end (); )
2216 { 2325 {
2217 if (p->second.pop_context () == 0) 2326 if (p->second.pop_context (my_scope) == 0)
2218 table.erase (p++); 2327 table.erase (p++);
2219 else 2328 else
2220 p++; 2329 p++;
2221 } 2330 }
2222 } 2331 }
2223 2332
2224 void do_clear_variables (void) 2333 void do_clear_variables (void)
2225 { 2334 {
2226 for (table_iterator p = table.begin (); p != table.end (); p++) 2335 for (table_iterator p = table.begin (); p != table.end (); p++)
2227 p->second.clear (); 2336 p->second.clear (my_scope);
2228 } 2337 }
2229 2338
2230 void do_clear_objects (void) 2339 void do_clear_objects (void)
2231 { 2340 {
2232 for (table_iterator p = table.begin (); p != table.end (); p++) 2341 for (table_iterator p = table.begin (); p != table.end (); p++)
2233 { 2342 {
2234 symbol_record& sr = p->second; 2343 symbol_record& sr = p->second;
2235 octave_value& val = sr.varref (); 2344 octave_value& val = sr.varref ();
2236 if (val.is_object()) 2345 if (val.is_object())
2237 p->second.clear (); 2346 p->second.clear (my_scope);
2238 } 2347 }
2239 } 2348 }
2240 2349
2241 void do_unmark_forced_variables (void) 2350 void do_unmark_forced_variables (void)
2242 { 2351 {
2266 void do_clear_variable (const std::string& name) 2375 void do_clear_variable (const std::string& name)
2267 { 2376 {
2268 table_iterator p = table.find (name); 2377 table_iterator p = table.find (name);
2269 2378
2270 if (p != table.end ()) 2379 if (p != table.end ())
2271 p->second.clear (); 2380 p->second.clear (my_scope);
2272 } 2381 }
2273 2382
2274 void do_clear_global_pattern (const std::string& pat) 2383 void do_clear_global_pattern (const std::string& pat)
2275 { 2384 {
2276 glob_match pattern (pat); 2385 glob_match pattern (pat);
2306 symbol_record& sr = p->second; 2415 symbol_record& sr = p->second;
2307 2416
2308 if (sr.is_defined () || sr.is_global ()) 2417 if (sr.is_defined () || sr.is_global ())
2309 { 2418 {
2310 if (pattern.match (sr.name ())) 2419 if (pattern.match (sr.name ()))
2311 sr.clear (); 2420 sr.clear (my_scope);
2312 } 2421 }
2313 } 2422 }
2314 } 2423 }
2315 2424
2316 void do_clear_variable_regexp (const std::string& pat) 2425 void do_clear_variable_regexp (const std::string& pat)
2322 symbol_record& sr = p->second; 2431 symbol_record& sr = p->second;
2323 2432
2324 if (sr.is_defined () || sr.is_global ()) 2433 if (sr.is_defined () || sr.is_global ())
2325 { 2434 {
2326 if (pattern.is_match (sr.name ())) 2435 if (pattern.is_match (sr.name ()))
2327 sr.clear (); 2436 sr.clear (my_scope);
2328 } 2437 }
2329 } 2438 }
2330 } 2439 }
2331 2440
2332 void do_mark_automatic (const std::string& name) 2441 void do_mark_automatic (const std::string& name)
2460 } 2569 }
2461 2570
2462 void do_dump (std::ostream& os); 2571 void do_dump (std::ostream& os);
2463 2572
2464 void do_cache_name (const std::string& name) { table_name = name; } 2573 void do_cache_name (const std::string& name) { table_name = name; }
2574
2575 void do_update_nest (void);
2576
2577 bool look_nonlocal (const std::string& name, symbol_record& result)
2578 {
2579 table_iterator p = table.find (name);
2580 if (p == table.end ())
2581 {
2582 if (nest_parent)
2583 return nest_parent->look_nonlocal (name, result);
2584 }
2585 else if (! p->second.is_automatic ())
2586 {
2587 result = p->second;
2588 return true;
2589 }
2590
2591 return false;
2592 }
2465 }; 2593 };
2466 2594
2467 extern bool out_of_date_check (octave_value& function, 2595 extern bool out_of_date_check (octave_value& function,
2468 const std::string& dispatch_type = std::string (), 2596 const std::string& dispatch_type = std::string (),
2469 bool check_relative = true); 2597 bool check_relative = true);