Mercurial > hg > octave-lyh
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); |