Mercurial > hg > octave-nkf
comparison src/interpfcn/symtab.h @ 15093:a132d206a36a gui
maint: periodic merge of default to gui
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 03 Aug 2012 14:59:40 -0400 |
parents | src/symtab.h@fabc0e37ead1 src/symtab.h@60ff2cef569d |
children |
comparison
equal
deleted
inserted
replaced
15081:d02b229ce693 | 15093:a132d206a36a |
---|---|
1 /* | |
2 | |
3 Copyright (C) 1993-2012 John W. Eaton | |
4 Copyright (C) 2009 VZLU Prague | |
5 | |
6 This file is part of Octave. | |
7 | |
8 Octave is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 3 of the License, or (at your | |
11 option) any later version. | |
12 | |
13 Octave is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with Octave; see the file COPYING. If not, see | |
20 <http://www.gnu.org/licenses/>. | |
21 | |
22 */ | |
23 | |
24 #if !defined (octave_symtab_h) | |
25 #define octave_symtab_h 1 | |
26 | |
27 #include <deque> | |
28 #include <list> | |
29 #include <map> | |
30 #include <set> | |
31 #include <string> | |
32 | |
33 #include "glob-match.h" | |
34 #include "regexp.h" | |
35 | |
36 class tree_argument_list; | |
37 class octave_user_function; | |
38 | |
39 #include "oct-obj.h" | |
40 #include "oct-refcount.h" | |
41 #include "ov.h" | |
42 | |
43 class | |
44 OCTINTERP_API | |
45 symbol_table | |
46 { | |
47 public: | |
48 | |
49 typedef int scope_id; | |
50 typedef size_t context_id; | |
51 | |
52 class | |
53 scope_id_cache | |
54 { | |
55 protected: | |
56 | |
57 typedef std::set<scope_id>::iterator set_iterator; | |
58 typedef std::set<scope_id>::const_iterator set_const_iterator; | |
59 | |
60 // We start with 2 because we allocate 0 for the global symbols | |
61 // and 1 for the top-level workspace. | |
62 | |
63 scope_id_cache (void) : next_available (2), in_use (), free_list () { } | |
64 | |
65 public: | |
66 | |
67 ~scope_id_cache (void) { } | |
68 | |
69 static scope_id alloc (void) | |
70 { | |
71 return instance_ok () ? instance->do_alloc () : -1; | |
72 } | |
73 | |
74 static void free (scope_id scope) | |
75 { | |
76 if (instance_ok ()) | |
77 return instance->do_free (scope); | |
78 } | |
79 | |
80 static std::list<scope_id> scopes (void) | |
81 { | |
82 return instance_ok () ? instance->do_scopes () : std::list<scope_id> (); | |
83 } | |
84 | |
85 static void create_instance (void); | |
86 | |
87 static bool instance_ok (void) | |
88 { | |
89 bool retval = true; | |
90 | |
91 if (! instance) | |
92 create_instance (); | |
93 | |
94 if (! instance) | |
95 { | |
96 ::error ("unable to create scope_id_cache object!"); | |
97 | |
98 retval = false; | |
99 } | |
100 | |
101 return retval; | |
102 } | |
103 | |
104 private: | |
105 | |
106 // No copying! | |
107 | |
108 scope_id_cache (const scope_id_cache&); | |
109 | |
110 scope_id_cache& operator = (const scope_id_cache&); | |
111 | |
112 static scope_id_cache *instance; | |
113 | |
114 static void cleanup_instance (void) { delete instance; instance = 0; } | |
115 | |
116 // The next available scope not in the free list. | |
117 scope_id next_available; | |
118 | |
119 // The set of scope IDs that are currently allocated. | |
120 std::set<scope_id> in_use; | |
121 | |
122 // The set of scope IDs that are currently available. | |
123 std::set<scope_id> free_list; | |
124 | |
125 scope_id do_alloc (void) | |
126 { | |
127 scope_id retval; | |
128 | |
129 set_iterator p = free_list.begin (); | |
130 | |
131 if (p != free_list.end ()) | |
132 { | |
133 retval = *p; | |
134 free_list.erase (p); | |
135 } | |
136 else | |
137 retval = next_available++; | |
138 | |
139 in_use.insert (retval); | |
140 | |
141 return retval; | |
142 } | |
143 | |
144 void do_free (scope_id scope) | |
145 { | |
146 set_iterator p = in_use.find (scope); | |
147 | |
148 if (p != in_use.end ()) | |
149 { | |
150 in_use.erase (p); | |
151 free_list.insert (scope); | |
152 } | |
153 else | |
154 error ("free_scope: scope %d not found!", scope); | |
155 } | |
156 | |
157 std::list<scope_id> do_scopes (void) const | |
158 { | |
159 std::list<scope_id> retval; | |
160 | |
161 for (set_const_iterator p = in_use.begin (); p != in_use.end (); p++) | |
162 retval.push_back (*p); | |
163 | |
164 retval.sort (); | |
165 | |
166 return retval; | |
167 } | |
168 }; | |
169 | |
170 class fcn_info; | |
171 | |
172 class | |
173 symbol_record | |
174 { | |
175 public: | |
176 | |
177 // generic variable | |
178 static const unsigned int local = 1; | |
179 | |
180 // varargin, argn, .nargin., .nargout. | |
181 // (FIXME -- is this really used now?) | |
182 static const unsigned int automatic = 2; | |
183 | |
184 // formal parameter | |
185 static const unsigned int formal = 4; | |
186 | |
187 // not listed or cleared (.nargin., .nargout.) | |
188 static const unsigned int hidden = 8; | |
189 | |
190 // inherited from parent scope; not cleared at function exit | |
191 static const unsigned int inherited = 16; | |
192 | |
193 // global (redirects to global scope) | |
194 static const unsigned int global = 32; | |
195 | |
196 // not cleared at function exit | |
197 static const unsigned int persistent = 64; | |
198 | |
199 // temporary variables forced into symbol table for parsing | |
200 static const unsigned int forced = 128; | |
201 | |
202 private: | |
203 | |
204 class | |
205 symbol_record_rep | |
206 { | |
207 public: | |
208 | |
209 symbol_record_rep (scope_id s, const std::string& nm, | |
210 const octave_value& v, unsigned int sc) | |
211 : decl_scope (s), curr_fcn (0), name (nm), value_stack (), | |
212 storage_class (sc), finfo (), valid (true), count (1) | |
213 { | |
214 value_stack.push_back (v); | |
215 } | |
216 | |
217 void force_variable (context_id context = xdefault_context) | |
218 { | |
219 if (context == xdefault_context) | |
220 context = active_context (); | |
221 | |
222 octave_value& val = varref (context); | |
223 | |
224 if (! val.is_defined ()) | |
225 mark_forced (); | |
226 } | |
227 | |
228 octave_value& varref (context_id context = xdefault_context) | |
229 { | |
230 if (is_global ()) | |
231 return symbol_table::global_varref (name); | |
232 else if (is_persistent ()) | |
233 return symbol_table::persistent_varref (name); | |
234 else | |
235 { | |
236 if (context == xdefault_context) | |
237 context = active_context (); | |
238 | |
239 context_id n = value_stack.size (); | |
240 while (n++ <= context) | |
241 value_stack.push_back (octave_value ()); | |
242 | |
243 return value_stack[context]; | |
244 } | |
245 } | |
246 | |
247 octave_value varval (context_id context = xdefault_context) const | |
248 { | |
249 if (is_global ()) | |
250 return symbol_table::global_varval (name); | |
251 else if (is_persistent ()) | |
252 return symbol_table::persistent_varval (name); | |
253 else | |
254 { | |
255 if (context == xdefault_context) | |
256 context = active_context (); | |
257 | |
258 if (context < value_stack.size ()) | |
259 return value_stack[context]; | |
260 else | |
261 return octave_value (); | |
262 } | |
263 } | |
264 | |
265 void push_context (scope_id s) | |
266 { | |
267 if (! (is_persistent () || is_global ()) | |
268 && s == scope ()) | |
269 value_stack.push_back (octave_value ()); | |
270 } | |
271 | |
272 // If pop_context returns 0, we are out of values and this element | |
273 // of the symbol table should be deleted. This can happen for | |
274 // functions like | |
275 // | |
276 // function foo (n) | |
277 // if (n > 0) | |
278 // foo (n-1); | |
279 // else | |
280 // eval ("x = 1"); | |
281 // endif | |
282 // endfunction | |
283 // | |
284 // Here, X should only exist in the final stack frame. | |
285 | |
286 size_t pop_context (scope_id s) | |
287 { | |
288 size_t retval = 1; | |
289 | |
290 if (! (is_persistent () || is_global ()) | |
291 && s == scope ()) | |
292 { | |
293 value_stack.pop_back (); | |
294 retval = value_stack.size (); | |
295 } | |
296 | |
297 return retval; | |
298 } | |
299 | |
300 void clear (void) { clear (scope ()); } | |
301 | |
302 void clear (scope_id s) | |
303 { | |
304 if (! (is_hidden () || is_inherited ()) | |
305 && s == scope ()) | |
306 { | |
307 if (is_global ()) | |
308 unmark_global (); | |
309 | |
310 if (is_persistent ()) | |
311 { | |
312 symbol_table::persistent_varref (name) | |
313 = varval (); | |
314 | |
315 unmark_persistent (); | |
316 } | |
317 | |
318 varref () = octave_value (); | |
319 } | |
320 } | |
321 | |
322 bool is_defined (context_id context = xdefault_context) const | |
323 { | |
324 if (context == xdefault_context) | |
325 context = active_context (); | |
326 | |
327 return varval (context).is_defined (); | |
328 } | |
329 | |
330 bool is_valid (void) const | |
331 { | |
332 return valid; | |
333 } | |
334 | |
335 bool is_variable (context_id context) const | |
336 { | |
337 if (context == xdefault_context) | |
338 context = active_context (); | |
339 | |
340 return (! is_local () || is_defined (context) || is_forced ()); | |
341 } | |
342 | |
343 bool is_local (void) const { return storage_class & local; } | |
344 bool is_automatic (void) const { return storage_class & automatic; } | |
345 bool is_formal (void) const { return storage_class & formal; } | |
346 bool is_hidden (void) const { return storage_class & hidden; } | |
347 bool is_inherited (void) const { return storage_class & inherited; } | |
348 bool is_global (void) const { return storage_class & global; } | |
349 bool is_persistent (void) const { return storage_class & persistent; } | |
350 bool is_forced (void) const { return storage_class & forced; } | |
351 | |
352 void mark_local (void) { storage_class |= local; } | |
353 void mark_automatic (void) { storage_class |= automatic; } | |
354 void mark_formal (void) { storage_class |= formal; } | |
355 void mark_hidden (void) { storage_class |= hidden; } | |
356 void mark_inherited (void) { storage_class |= inherited; } | |
357 void mark_global (void) | |
358 { | |
359 if (is_persistent ()) | |
360 error ("can't make persistent variable %s global", name.c_str ()); | |
361 else | |
362 storage_class |= global; | |
363 } | |
364 void mark_persistent (void) | |
365 { | |
366 if (is_global ()) | |
367 error ("can't make global variable %s persistent", name.c_str ()); | |
368 else | |
369 storage_class |= persistent; | |
370 } | |
371 void mark_forced (void) { storage_class |= forced; } | |
372 | |
373 void unmark_local (void) { storage_class &= ~local; } | |
374 void unmark_automatic (void) { storage_class &= ~automatic; } | |
375 void unmark_formal (void) { storage_class &= ~formal; } | |
376 void unmark_hidden (void) { storage_class &= ~hidden; } | |
377 void unmark_inherited (void) { storage_class &= ~inherited; } | |
378 void unmark_global (void) { storage_class &= ~global; } | |
379 void unmark_persistent (void) { storage_class &= ~persistent; } | |
380 void unmark_forced (void) { storage_class &= ~forced; } | |
381 | |
382 void init_persistent (void) | |
383 { | |
384 if (! is_defined ()) | |
385 { | |
386 mark_persistent (); | |
387 | |
388 varref () = symbol_table::persistent_varval (name); | |
389 } | |
390 // FIXME -- this causes trouble with recursive calls. | |
391 // else | |
392 // error ("unable to declare existing variable persistent"); | |
393 } | |
394 | |
395 void invalidate (void) | |
396 { | |
397 valid = false; | |
398 } | |
399 | |
400 void erase_persistent (void) | |
401 { | |
402 unmark_persistent (); | |
403 symbol_table::erase_persistent (name); | |
404 } | |
405 | |
406 context_id active_context (void) const; | |
407 | |
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 (), | |
418 storage_class); | |
419 } | |
420 | |
421 void dump (std::ostream& os, const std::string& prefix) const; | |
422 | |
423 scope_id decl_scope; | |
424 | |
425 octave_user_function* curr_fcn; | |
426 | |
427 std::string name; | |
428 | |
429 std::deque<octave_value> value_stack; | |
430 | |
431 unsigned int storage_class; | |
432 | |
433 fcn_info *finfo; | |
434 | |
435 bool valid; | |
436 | |
437 octave_refcount<size_t> count; | |
438 | |
439 private: | |
440 | |
441 // No copying! | |
442 | |
443 symbol_record_rep (const symbol_record_rep& ov); | |
444 | |
445 symbol_record_rep& operator = (const symbol_record_rep&); | |
446 }; | |
447 | |
448 public: | |
449 | |
450 symbol_record (scope_id s = xcurrent_scope, | |
451 const std::string& nm = std::string (), | |
452 const octave_value& v = octave_value (), | |
453 unsigned int sc = local) | |
454 : rep (new symbol_record_rep (s, nm, v, sc)) { } | |
455 | |
456 symbol_record (const symbol_record& sr) | |
457 : rep (sr.rep) | |
458 { | |
459 rep->count++; | |
460 } | |
461 | |
462 symbol_record& operator = (const symbol_record& sr) | |
463 { | |
464 if (this != &sr) | |
465 { | |
466 if (--rep->count == 0) | |
467 delete rep; | |
468 | |
469 rep = sr.rep; | |
470 rep->count++; | |
471 } | |
472 | |
473 return *this; | |
474 } | |
475 | |
476 ~symbol_record (void) | |
477 { | |
478 if (--rep->count == 0) | |
479 delete rep; | |
480 } | |
481 | |
482 symbol_record dup (scope_id new_scope) const | |
483 { | |
484 return symbol_record (rep->dup (new_scope)); | |
485 } | |
486 | |
487 const std::string& name (void) const { return rep->name; } | |
488 | |
489 octave_value | |
490 find (const octave_value_list& args = octave_value_list ()) const; | |
491 | |
492 void force_variable (context_id context = xdefault_context) | |
493 { | |
494 rep->force_variable (context); | |
495 } | |
496 | |
497 octave_value& varref (context_id context = xdefault_context) | |
498 { | |
499 return rep->varref (context); | |
500 } | |
501 | |
502 octave_value varval (context_id context = xdefault_context) const | |
503 { | |
504 return rep->varval (context); | |
505 } | |
506 | |
507 void push_context (scope_id s) { rep->push_context (s); } | |
508 | |
509 size_t pop_context (scope_id s) { return rep->pop_context (s); } | |
510 | |
511 void clear (void) { rep->clear (); } | |
512 | |
513 void clear (scope_id s) { rep->clear (s); } | |
514 | |
515 bool is_defined (context_id context = xdefault_context) const | |
516 { | |
517 return rep->is_defined (context); | |
518 } | |
519 | |
520 bool is_valid (void) const | |
521 { | |
522 return rep->is_valid (); | |
523 } | |
524 | |
525 bool is_variable (context_id context = xdefault_context) const | |
526 { | |
527 return rep->is_variable (context); | |
528 } | |
529 | |
530 bool is_local (void) const { return rep->is_local (); } | |
531 bool is_automatic (void) const { return rep->is_automatic (); } | |
532 bool is_formal (void) const { return rep->is_formal (); } | |
533 bool is_global (void) const { return rep->is_global (); } | |
534 bool is_hidden (void) const { return rep->is_hidden (); } | |
535 bool is_inherited (void) const { return rep->is_inherited (); } | |
536 bool is_persistent (void) const { return rep->is_persistent (); } | |
537 bool is_forced (void) const { return rep->is_forced (); } | |
538 | |
539 void mark_local (void) { rep->mark_local (); } | |
540 void mark_automatic (void) { rep->mark_automatic (); } | |
541 void mark_formal (void) { rep->mark_formal (); } | |
542 void mark_hidden (void) { rep->mark_hidden (); } | |
543 void mark_inherited (void) { rep->mark_inherited (); } | |
544 void mark_global (void) { rep->mark_global (); } | |
545 void mark_persistent (void) { rep->mark_persistent (); } | |
546 void mark_forced (void) { rep->mark_forced (); } | |
547 | |
548 void unmark_local (void) { rep->unmark_local (); } | |
549 void unmark_automatic (void) { rep->unmark_automatic (); } | |
550 void unmark_formal (void) { rep->unmark_formal (); } | |
551 void unmark_hidden (void) { rep->unmark_hidden (); } | |
552 void unmark_inherited (void) { rep->unmark_inherited (); } | |
553 void unmark_global (void) { rep->unmark_global (); } | |
554 void unmark_persistent (void) { rep->unmark_persistent (); } | |
555 void unmark_forced (void) { rep->unmark_forced (); } | |
556 | |
557 void init_persistent (void) { rep->init_persistent (); } | |
558 | |
559 void erase_persistent (void) { rep->erase_persistent (); } | |
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 | |
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); } | |
570 | |
571 void | |
572 dump (std::ostream& os, const std::string& prefix = std::string ()) const | |
573 { | |
574 rep->dump (os, prefix); | |
575 } | |
576 | |
577 private: | |
578 | |
579 symbol_record_rep *rep; | |
580 | |
581 symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { } | |
582 }; | |
583 | |
584 // Always access a symbol from the current scope. | |
585 // Useful for scripts, as they may be executed in more than one scope. | |
586 class | |
587 symbol_reference | |
588 { | |
589 public: | |
590 symbol_reference (void) : scope (-1) {} | |
591 | |
592 symbol_reference (symbol_record record, | |
593 scope_id curr_scope = symbol_table::current_scope ()) | |
594 : scope (curr_scope), sym (record) | |
595 {} | |
596 | |
597 symbol_reference& operator = (const symbol_reference& ref) | |
598 { | |
599 scope = ref.scope; | |
600 sym = ref.sym; | |
601 return *this; | |
602 } | |
603 | |
604 // The name is the same regardless of scope. | |
605 const std::string& name (void) const { return sym.name (); } | |
606 | |
607 symbol_record *operator-> (void) | |
608 { | |
609 update (); | |
610 return &sym; | |
611 } | |
612 | |
613 symbol_record *operator-> (void) const | |
614 { | |
615 update (); | |
616 return &sym; | |
617 } | |
618 | |
619 // can be used to place symbol_reference in maps, we don't overload < as | |
620 // it doesn't make any sense for symbol_reference | |
621 struct comparator | |
622 { | |
623 bool operator ()(const symbol_reference& lhs, | |
624 const symbol_reference& rhs) const | |
625 { | |
626 return lhs.name () < rhs.name (); | |
627 } | |
628 }; | |
629 private: | |
630 void update (void) const | |
631 { | |
632 scope_id curr_scope = symbol_table::current_scope (); | |
633 if (scope != curr_scope || ! sym.is_valid ()) | |
634 { | |
635 scope = curr_scope; | |
636 sym = symbol_table::insert (sym.name ()); | |
637 } | |
638 } | |
639 | |
640 mutable scope_id scope; | |
641 mutable symbol_record sym; | |
642 }; | |
643 | |
644 class | |
645 fcn_info | |
646 { | |
647 public: | |
648 | |
649 typedef std::map<std::string, std::string> dispatch_map_type; | |
650 | |
651 typedef std::map<scope_id, octave_value>::const_iterator scope_val_const_iterator; | |
652 typedef std::map<scope_id, octave_value>::iterator scope_val_iterator; | |
653 | |
654 typedef std::map<std::string, octave_value>::const_iterator str_val_const_iterator; | |
655 typedef std::map<std::string, octave_value>::iterator str_val_iterator; | |
656 | |
657 typedef dispatch_map_type::const_iterator dispatch_map_const_iterator; | |
658 typedef dispatch_map_type::iterator dispatch_map_iterator; | |
659 | |
660 private: | |
661 | |
662 class | |
663 fcn_info_rep | |
664 { | |
665 public: | |
666 | |
667 fcn_info_rep (const std::string& nm) | |
668 : name (nm), subfunctions (), private_functions (), | |
669 class_constructors (), class_methods (), dispatch_map (), | |
670 cmdline_function (), autoload_function (), function_on_path (), | |
671 built_in_function (), count (1) { } | |
672 | |
673 octave_value load_private_function (const std::string& dir_name); | |
674 | |
675 octave_value load_class_constructor (void); | |
676 | |
677 octave_value load_class_method (const std::string& dispatch_type); | |
678 | |
679 octave_value find (const octave_value_list& args, bool local_funcs); | |
680 | |
681 octave_value builtin_find (void); | |
682 | |
683 octave_value find_method (const std::string& dispatch_type); | |
684 | |
685 octave_value find_autoload (void); | |
686 | |
687 octave_value find_user_function (void); | |
688 | |
689 bool is_user_function_defined (void) const | |
690 { | |
691 return function_on_path.is_defined (); | |
692 } | |
693 | |
694 octave_value find_function (const octave_value_list& args, bool local_funcs) | |
695 { | |
696 return find (args, local_funcs); | |
697 } | |
698 | |
699 void lock_subfunction (scope_id scope) | |
700 { | |
701 scope_val_iterator p = subfunctions.find (scope); | |
702 | |
703 if (p != subfunctions.end ()) | |
704 p->second.lock (); | |
705 } | |
706 | |
707 void unlock_subfunction (scope_id scope) | |
708 { | |
709 scope_val_iterator p = subfunctions.find (scope); | |
710 | |
711 if (p != subfunctions.end ()) | |
712 p->second.unlock (); | |
713 } | |
714 | |
715 std::pair<std::string, octave_value> | |
716 subfunction_defined_in_scope (scope_id scope) const | |
717 { | |
718 scope_val_const_iterator p = subfunctions.find (scope); | |
719 | |
720 return p == subfunctions.end () | |
721 ? std::pair<std::string, octave_value> () | |
722 : std::pair<std::string, octave_value> (name, p->second); | |
723 } | |
724 | |
725 void erase_subfunction (scope_id scope) | |
726 { | |
727 scope_val_iterator p = subfunctions.find (scope); | |
728 | |
729 if (p != subfunctions.end ()) | |
730 subfunctions.erase (p); | |
731 } | |
732 | |
733 void mark_subfunction_in_scope_as_private (scope_id scope, | |
734 const std::string& class_name); | |
735 | |
736 void install_cmdline_function (const octave_value& f) | |
737 { | |
738 cmdline_function = f; | |
739 } | |
740 | |
741 void install_subfunction (const octave_value& f, scope_id scope) | |
742 { | |
743 subfunctions[scope] = f; | |
744 } | |
745 | |
746 void install_user_function (const octave_value& f) | |
747 { | |
748 function_on_path = f; | |
749 } | |
750 | |
751 void install_built_in_function (const octave_value& f) | |
752 { | |
753 built_in_function = f; | |
754 } | |
755 | |
756 template <class T> | |
757 void | |
758 clear_unlocked (std::map<T, octave_value>& map) | |
759 { | |
760 typename std::map<T, octave_value>::iterator p = map.begin (); | |
761 | |
762 while (p != map.end ()) | |
763 { | |
764 if (p->second.islocked ()) | |
765 p++; | |
766 else | |
767 map.erase (p++); | |
768 } | |
769 } | |
770 | |
771 void clear_autoload_function (void) | |
772 { | |
773 if (! autoload_function.islocked ()) | |
774 autoload_function = octave_value (); | |
775 } | |
776 | |
777 // We also clear command line functions here, as these are both | |
778 // "user defined" | |
779 void clear_user_function (void) | |
780 { | |
781 if (! function_on_path.islocked ()) | |
782 { | |
783 function_on_path.erase_subfunctions (); | |
784 | |
785 function_on_path = octave_value (); | |
786 } | |
787 | |
788 if (! cmdline_function.islocked ()) | |
789 cmdline_function = octave_value (); | |
790 } | |
791 | |
792 void clear_mex_function (void) | |
793 { | |
794 if (function_on_path.is_mex_function ()) | |
795 clear_user_function (); | |
796 } | |
797 | |
798 void clear (void) | |
799 { | |
800 clear_unlocked (subfunctions); | |
801 clear_unlocked (private_functions); | |
802 clear_unlocked (class_constructors); | |
803 clear_unlocked (class_methods); | |
804 clear_autoload_function (); | |
805 clear_user_function (); | |
806 } | |
807 | |
808 void add_dispatch (const std::string& type, const std::string& fname) | |
809 { | |
810 dispatch_map[type] = fname; | |
811 } | |
812 | |
813 void clear_dispatch (const std::string& type) | |
814 { | |
815 dispatch_map_iterator p = dispatch_map.find (type); | |
816 | |
817 if (p != dispatch_map.end ()) | |
818 dispatch_map.erase (p); | |
819 } | |
820 | |
821 void print_dispatch (std::ostream& os) const; | |
822 | |
823 std::string help_for_dispatch (void) const; | |
824 | |
825 dispatch_map_type get_dispatch (void) const { return dispatch_map; } | |
826 | |
827 void dump (std::ostream& os, const std::string& prefix) const; | |
828 | |
829 std::string name; | |
830 | |
831 // Scope id to function object. | |
832 std::map<scope_id, octave_value> subfunctions; | |
833 | |
834 // Directory name to function object. | |
835 std::map<std::string, octave_value> private_functions; | |
836 | |
837 // Class name to function object. | |
838 std::map<std::string, octave_value> class_constructors; | |
839 | |
840 // Dispatch type to function object. | |
841 std::map<std::string, octave_value> class_methods; | |
842 | |
843 // Legacy dispatch map (dispatch type name to function name). | |
844 dispatch_map_type dispatch_map; | |
845 | |
846 octave_value cmdline_function; | |
847 | |
848 octave_value autoload_function; | |
849 | |
850 octave_value function_on_path; | |
851 | |
852 octave_value built_in_function; | |
853 | |
854 octave_refcount<size_t> count; | |
855 | |
856 private: | |
857 | |
858 octave_value xfind (const octave_value_list& args, bool local_funcs); | |
859 | |
860 octave_value x_builtin_find (void); | |
861 | |
862 // No copying! | |
863 | |
864 fcn_info_rep (const fcn_info_rep&); | |
865 | |
866 fcn_info_rep& operator = (const fcn_info_rep&); | |
867 }; | |
868 | |
869 public: | |
870 | |
871 fcn_info (const std::string& nm = std::string ()) | |
872 : rep (new fcn_info_rep (nm)) { } | |
873 | |
874 fcn_info (const fcn_info& fi) : rep (fi.rep) | |
875 { | |
876 rep->count++; | |
877 } | |
878 | |
879 fcn_info& operator = (const fcn_info& fi) | |
880 { | |
881 if (this != &fi) | |
882 { | |
883 if (--rep->count == 0) | |
884 delete rep; | |
885 | |
886 rep = fi.rep; | |
887 rep->count++; | |
888 } | |
889 | |
890 return *this; | |
891 } | |
892 | |
893 ~fcn_info (void) | |
894 { | |
895 if (--rep->count == 0) | |
896 delete rep; | |
897 } | |
898 | |
899 octave_value find (const octave_value_list& args = octave_value_list (), | |
900 bool local_funcs = true) | |
901 { | |
902 return rep->find (args, local_funcs); | |
903 } | |
904 | |
905 octave_value builtin_find (void) | |
906 { | |
907 return rep->builtin_find (); | |
908 } | |
909 | |
910 octave_value find_method (const std::string& dispatch_type) const | |
911 { | |
912 return rep->find_method (dispatch_type); | |
913 } | |
914 | |
915 octave_value find_built_in_function (void) const | |
916 { | |
917 return rep->built_in_function; | |
918 } | |
919 | |
920 octave_value find_cmdline_function (void) const | |
921 { | |
922 return rep->cmdline_function; | |
923 } | |
924 | |
925 octave_value find_autoload (void) | |
926 { | |
927 return rep->find_autoload (); | |
928 } | |
929 | |
930 octave_value find_user_function (void) | |
931 { | |
932 return rep->find_user_function (); | |
933 } | |
934 | |
935 bool is_user_function_defined (void) const | |
936 { | |
937 return rep->is_user_function_defined (); | |
938 } | |
939 | |
940 octave_value find_function (const octave_value_list& args = octave_value_list (), | |
941 bool local_funcs = true) | |
942 { | |
943 return rep->find_function (args, local_funcs); | |
944 } | |
945 | |
946 void lock_subfunction (scope_id scope) | |
947 { | |
948 rep->lock_subfunction (scope); | |
949 } | |
950 | |
951 void unlock_subfunction (scope_id scope) | |
952 { | |
953 rep->unlock_subfunction (scope); | |
954 } | |
955 | |
956 std::pair<std::string, octave_value> | |
957 subfunction_defined_in_scope (scope_id scope = xcurrent_scope) const | |
958 { | |
959 return rep->subfunction_defined_in_scope (scope); | |
960 } | |
961 | |
962 void erase_subfunction (scope_id scope) | |
963 { | |
964 rep->erase_subfunction (scope); | |
965 } | |
966 | |
967 void mark_subfunction_in_scope_as_private (scope_id scope, | |
968 const std::string& class_name) | |
969 { | |
970 rep->mark_subfunction_in_scope_as_private (scope, class_name); | |
971 } | |
972 | |
973 void install_cmdline_function (const octave_value& f) | |
974 { | |
975 rep->install_cmdline_function (f); | |
976 } | |
977 | |
978 void install_subfunction (const octave_value& f, scope_id scope) | |
979 { | |
980 rep->install_subfunction (f, scope); | |
981 } | |
982 | |
983 void install_user_function (const octave_value& f) | |
984 { | |
985 rep->install_user_function (f); | |
986 } | |
987 | |
988 void install_built_in_function (const octave_value& f) | |
989 { | |
990 rep->install_built_in_function (f); | |
991 } | |
992 | |
993 void clear (void) { rep->clear (); } | |
994 | |
995 void clear_user_function (void) { rep->clear_user_function (); } | |
996 | |
997 void clear_autoload_function (void) { rep->clear_autoload_function (); } | |
998 | |
999 void clear_mex_function (void) { rep->clear_mex_function (); } | |
1000 | |
1001 void add_dispatch (const std::string& type, const std::string& fname) | |
1002 { | |
1003 rep->add_dispatch (type, fname); | |
1004 } | |
1005 | |
1006 void clear_dispatch (const std::string& type) | |
1007 { | |
1008 rep->clear_dispatch (type); | |
1009 } | |
1010 | |
1011 void print_dispatch (std::ostream& os) const | |
1012 { | |
1013 rep->print_dispatch (os); | |
1014 } | |
1015 | |
1016 std::string help_for_dispatch (void) const { return rep->help_for_dispatch (); } | |
1017 | |
1018 dispatch_map_type get_dispatch (void) const | |
1019 { | |
1020 return rep->get_dispatch (); | |
1021 } | |
1022 | |
1023 void | |
1024 dump (std::ostream& os, const std::string& prefix = std::string ()) const | |
1025 { | |
1026 rep->dump (os, prefix); | |
1027 } | |
1028 | |
1029 private: | |
1030 | |
1031 fcn_info_rep *rep; | |
1032 }; | |
1033 | |
1034 static scope_id global_scope (void) { return xglobal_scope; } | |
1035 static scope_id top_scope (void) { return xtop_scope; } | |
1036 | |
1037 static scope_id current_scope (void) { return xcurrent_scope; } | |
1038 | |
1039 static context_id current_context (void) { return xcurrent_context; } | |
1040 | |
1041 static scope_id alloc_scope (void) { return scope_id_cache::alloc (); } | |
1042 | |
1043 static void set_scope (scope_id scope) | |
1044 { | |
1045 if (scope == xglobal_scope) | |
1046 error ("can't set scope to global"); | |
1047 else if (scope != xcurrent_scope) | |
1048 { | |
1049 all_instances_iterator p = all_instances.find (scope); | |
1050 | |
1051 if (p == all_instances.end ()) | |
1052 { | |
1053 symbol_table *inst = new symbol_table (scope); | |
1054 | |
1055 if (inst) | |
1056 all_instances[scope] = instance = inst; | |
1057 } | |
1058 else | |
1059 instance = p->second; | |
1060 | |
1061 xcurrent_scope = scope; | |
1062 xcurrent_context = 0; | |
1063 } | |
1064 } | |
1065 | |
1066 static void set_scope_and_context (scope_id scope, context_id context) | |
1067 { | |
1068 if (scope == xglobal_scope) | |
1069 error ("can't set scope to global"); | |
1070 else | |
1071 { | |
1072 if (scope != xcurrent_scope) | |
1073 { | |
1074 all_instances_iterator p = all_instances.find (scope); | |
1075 | |
1076 if (p == all_instances.end ()) | |
1077 error ("scope not found!"); | |
1078 else | |
1079 { | |
1080 instance = p->second; | |
1081 | |
1082 xcurrent_scope = scope; | |
1083 | |
1084 xcurrent_context = context; | |
1085 } | |
1086 } | |
1087 else | |
1088 xcurrent_context = context; | |
1089 } | |
1090 } | |
1091 | |
1092 static void erase_scope (scope_id scope) | |
1093 { | |
1094 assert (scope != xglobal_scope); | |
1095 | |
1096 all_instances_iterator p = all_instances.find (scope); | |
1097 | |
1098 if (p != all_instances.end ()) | |
1099 { | |
1100 delete p->second; | |
1101 | |
1102 all_instances.erase (p); | |
1103 | |
1104 free_scope (scope); | |
1105 } | |
1106 } | |
1107 | |
1108 static void erase_subfunctions_in_scope (scope_id scope) | |
1109 { | |
1110 for (fcn_table_iterator q = fcn_table.begin (); | |
1111 q != fcn_table.end (); q++) | |
1112 q->second.erase_subfunction (scope); | |
1113 } | |
1114 | |
1115 static void | |
1116 mark_subfunctions_in_scope_as_private (scope_id scope, | |
1117 const std::string& class_name) | |
1118 { | |
1119 for (fcn_table_iterator q = fcn_table.begin (); | |
1120 q != fcn_table.end (); q++) | |
1121 q->second.mark_subfunction_in_scope_as_private (scope, class_name); | |
1122 } | |
1123 | |
1124 static scope_id dup_scope (scope_id scope) | |
1125 { | |
1126 scope_id retval = -1; | |
1127 | |
1128 symbol_table *inst = get_instance (scope); | |
1129 | |
1130 if (inst) | |
1131 { | |
1132 scope_id new_scope = alloc_scope (); | |
1133 | |
1134 symbol_table *new_symbol_table = new symbol_table (scope); | |
1135 | |
1136 if (new_symbol_table) | |
1137 { | |
1138 all_instances[new_scope] = new_symbol_table; | |
1139 | |
1140 inst->do_dup_scope (*new_symbol_table); | |
1141 | |
1142 retval = new_scope; | |
1143 } | |
1144 } | |
1145 | |
1146 return retval; | |
1147 } | |
1148 | |
1149 static std::list<scope_id> scopes (void) | |
1150 { | |
1151 return scope_id_cache::scopes (); | |
1152 } | |
1153 | |
1154 static symbol_record | |
1155 find_symbol (const std::string& name, scope_id scope = xcurrent_scope) | |
1156 { | |
1157 symbol_table *inst = get_instance (scope); | |
1158 | |
1159 return inst ? inst->do_find_symbol (name) : | |
1160 symbol_record (scope); | |
1161 } | |
1162 | |
1163 static void | |
1164 inherit (scope_id scope, scope_id donor_scope, context_id donor_context) | |
1165 { | |
1166 symbol_table *inst = get_instance (scope); | |
1167 | |
1168 if (inst) | |
1169 { | |
1170 symbol_table *donor_symbol_table = get_instance (donor_scope); | |
1171 | |
1172 if (donor_symbol_table) | |
1173 inst->do_inherit (*donor_symbol_table, donor_context); | |
1174 } | |
1175 } | |
1176 | |
1177 static bool at_top_level (void) { return xcurrent_scope == xtop_scope; } | |
1178 | |
1179 // Find a value corresponding to the given name in the table. | |
1180 static octave_value | |
1181 find (const std::string& name, | |
1182 const octave_value_list& args = octave_value_list (), | |
1183 bool skip_variables = false, | |
1184 bool local_funcs = true); | |
1185 | |
1186 static octave_value builtin_find (const std::string& name); | |
1187 | |
1188 // Insert a new name in the table. | |
1189 static symbol_record& insert (const std::string& name) | |
1190 { | |
1191 static symbol_record foobar; | |
1192 | |
1193 symbol_table *inst = get_instance (xcurrent_scope); | |
1194 | |
1195 return inst ? inst->do_insert (name) : foobar; | |
1196 } | |
1197 | |
1198 static void force_variable (const std::string& name, | |
1199 scope_id scope = xcurrent_scope, | |
1200 context_id context = xdefault_context) | |
1201 { | |
1202 symbol_table *inst = get_instance (scope); | |
1203 | |
1204 if (inst) | |
1205 inst->do_force_variable (name, context); | |
1206 } | |
1207 | |
1208 static octave_value& varref (const std::string& name, | |
1209 scope_id scope = xcurrent_scope, | |
1210 context_id context = xdefault_context) | |
1211 { | |
1212 static octave_value foobar; | |
1213 | |
1214 symbol_table *inst = get_instance (scope); | |
1215 | |
1216 return inst ? inst->do_varref (name, context) : foobar; | |
1217 } | |
1218 | |
1219 static octave_value varval (const std::string& name, | |
1220 scope_id scope = xcurrent_scope, | |
1221 context_id context = xdefault_context) | |
1222 { | |
1223 symbol_table *inst = get_instance (scope); | |
1224 | |
1225 return inst ? inst->do_varval (name, context) : octave_value (); | |
1226 } | |
1227 | |
1228 static octave_value& | |
1229 global_varref (const std::string& name) | |
1230 { | |
1231 global_table_iterator p = global_table.find (name); | |
1232 | |
1233 return (p == global_table.end ()) ? global_table[name] : p->second; | |
1234 } | |
1235 | |
1236 static octave_value | |
1237 global_varval (const std::string& name) | |
1238 { | |
1239 global_table_const_iterator p = global_table.find (name); | |
1240 | |
1241 return (p != global_table.end ()) ? p->second : octave_value (); | |
1242 } | |
1243 | |
1244 static octave_value& | |
1245 top_level_varref (const std::string& name) | |
1246 { | |
1247 return varref (name, top_scope (), 0); | |
1248 } | |
1249 | |
1250 static octave_value | |
1251 top_level_varval (const std::string& name) | |
1252 { | |
1253 return varval (name, top_scope (), 0); | |
1254 } | |
1255 | |
1256 static octave_value& persistent_varref (const std::string& name) | |
1257 { | |
1258 static octave_value foobar; | |
1259 | |
1260 symbol_table *inst = get_instance (xcurrent_scope); | |
1261 | |
1262 return inst ? inst->do_persistent_varref (name) : foobar; | |
1263 } | |
1264 | |
1265 static octave_value persistent_varval (const std::string& name) | |
1266 { | |
1267 symbol_table *inst = get_instance (xcurrent_scope); | |
1268 | |
1269 return inst ? inst->do_persistent_varval (name) : octave_value (); | |
1270 } | |
1271 | |
1272 static void erase_persistent (const std::string& name) | |
1273 { | |
1274 symbol_table *inst = get_instance (xcurrent_scope); | |
1275 | |
1276 if (inst) | |
1277 inst->do_erase_persistent (name); | |
1278 } | |
1279 | |
1280 static bool is_variable (const std::string& name) | |
1281 { | |
1282 symbol_table *inst = get_instance (xcurrent_scope); | |
1283 | |
1284 return inst ? inst->do_is_variable (name) : false; | |
1285 } | |
1286 | |
1287 static bool | |
1288 is_built_in_function_name (const std::string& name) | |
1289 { | |
1290 octave_value val = find_built_in_function (name); | |
1291 | |
1292 return val.is_defined (); | |
1293 } | |
1294 | |
1295 static octave_value | |
1296 find_method (const std::string& name, const std::string& dispatch_type) | |
1297 { | |
1298 fcn_table_const_iterator p = fcn_table.find (name); | |
1299 | |
1300 if (p != fcn_table.end ()) | |
1301 return p->second.find_method (dispatch_type); | |
1302 else | |
1303 { | |
1304 fcn_info finfo (name); | |
1305 | |
1306 octave_value fcn = finfo.find_method (dispatch_type); | |
1307 | |
1308 if (fcn.is_defined ()) | |
1309 fcn_table[name] = finfo; | |
1310 | |
1311 return fcn; | |
1312 } | |
1313 } | |
1314 | |
1315 static octave_value | |
1316 find_built_in_function (const std::string& name) | |
1317 { | |
1318 fcn_table_const_iterator p = fcn_table.find (name); | |
1319 | |
1320 return (p != fcn_table.end ()) | |
1321 ? p->second.find_built_in_function () : octave_value (); | |
1322 } | |
1323 | |
1324 static octave_value | |
1325 find_autoload (const std::string& name) | |
1326 { | |
1327 fcn_table_iterator p = fcn_table.find (name); | |
1328 | |
1329 return (p != fcn_table.end ()) | |
1330 ? p->second.find_autoload () : octave_value (); | |
1331 } | |
1332 | |
1333 static octave_value | |
1334 find_function (const std::string& name, | |
1335 const octave_value_list& args = octave_value_list (), | |
1336 bool local_funcs = true); | |
1337 | |
1338 static octave_value find_user_function (const std::string& name) | |
1339 { | |
1340 fcn_table_iterator p = fcn_table.find (name); | |
1341 | |
1342 return (p != fcn_table.end ()) | |
1343 ? p->second.find_user_function () : octave_value (); | |
1344 } | |
1345 | |
1346 static void install_cmdline_function (const std::string& name, | |
1347 const octave_value& fcn) | |
1348 { | |
1349 fcn_table_iterator p = fcn_table.find (name); | |
1350 | |
1351 if (p != fcn_table.end ()) | |
1352 { | |
1353 fcn_info& finfo = p->second; | |
1354 | |
1355 finfo.install_cmdline_function (fcn); | |
1356 } | |
1357 else | |
1358 { | |
1359 fcn_info finfo (name); | |
1360 | |
1361 finfo.install_cmdline_function (fcn); | |
1362 | |
1363 fcn_table[name] = finfo; | |
1364 } | |
1365 } | |
1366 | |
1367 static void install_subfunction (const std::string& name, | |
1368 const octave_value& fcn, | |
1369 scope_id scope) | |
1370 { | |
1371 fcn_table_iterator p = fcn_table.find (name); | |
1372 | |
1373 if (p != fcn_table.end ()) | |
1374 { | |
1375 fcn_info& finfo = p->second; | |
1376 | |
1377 finfo.install_subfunction (fcn, scope); | |
1378 } | |
1379 else | |
1380 { | |
1381 fcn_info finfo (name); | |
1382 | |
1383 finfo.install_subfunction (fcn, scope); | |
1384 | |
1385 fcn_table[name] = finfo; | |
1386 } | |
1387 } | |
1388 | |
1389 static void install_nestfunction (const std::string& name, | |
1390 const octave_value& fcn, | |
1391 scope_id parent_scope); | |
1392 | |
1393 static void update_nest (scope_id scope) | |
1394 { | |
1395 symbol_table *inst = get_instance (scope); | |
1396 if (inst) | |
1397 inst->do_update_nest (); | |
1398 } | |
1399 | |
1400 static void install_user_function (const std::string& name, | |
1401 const octave_value& fcn) | |
1402 { | |
1403 fcn_table_iterator p = fcn_table.find (name); | |
1404 | |
1405 if (p != fcn_table.end ()) | |
1406 { | |
1407 fcn_info& finfo = p->second; | |
1408 | |
1409 finfo.install_user_function (fcn); | |
1410 } | |
1411 else | |
1412 { | |
1413 fcn_info finfo (name); | |
1414 | |
1415 finfo.install_user_function (fcn); | |
1416 | |
1417 fcn_table[name] = finfo; | |
1418 } | |
1419 } | |
1420 | |
1421 static void install_built_in_function (const std::string& name, | |
1422 const octave_value& fcn) | |
1423 { | |
1424 fcn_table_iterator p = fcn_table.find (name); | |
1425 | |
1426 if (p != fcn_table.end ()) | |
1427 { | |
1428 fcn_info& finfo = p->second; | |
1429 | |
1430 finfo.install_built_in_function (fcn); | |
1431 } | |
1432 else | |
1433 { | |
1434 fcn_info finfo (name); | |
1435 | |
1436 finfo.install_built_in_function (fcn); | |
1437 | |
1438 fcn_table[name] = finfo; | |
1439 } | |
1440 } | |
1441 | |
1442 static void clear (const std::string& name) | |
1443 { | |
1444 clear_variable (name); | |
1445 } | |
1446 | |
1447 static void clear_all (void) | |
1448 { | |
1449 clear_variables (); | |
1450 | |
1451 clear_global_pattern ("*"); | |
1452 | |
1453 clear_functions (); | |
1454 } | |
1455 | |
1456 static void clear_variables (scope_id scope) | |
1457 { | |
1458 symbol_table *inst = get_instance (scope); | |
1459 | |
1460 if (inst) | |
1461 inst->do_clear_variables (); | |
1462 } | |
1463 | |
1464 // This is split for unwind_protect. | |
1465 static void clear_variables (void) | |
1466 { | |
1467 clear_variables (xcurrent_scope); | |
1468 } | |
1469 | |
1470 static void clear_objects (scope_id scope = xcurrent_scope) | |
1471 { | |
1472 symbol_table *inst = get_instance (scope); | |
1473 | |
1474 if (inst) | |
1475 inst->do_clear_objects (); | |
1476 } | |
1477 | |
1478 static void unmark_forced_variables (scope_id scope = xcurrent_scope) | |
1479 { | |
1480 symbol_table *inst = get_instance (scope); | |
1481 | |
1482 if (inst) | |
1483 inst->do_unmark_forced_variables (); | |
1484 } | |
1485 | |
1486 static void clear_functions (void) | |
1487 { | |
1488 for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) | |
1489 p->second.clear (); | |
1490 } | |
1491 | |
1492 static void clear_function (const std::string& name) | |
1493 { | |
1494 clear_user_function (name); | |
1495 } | |
1496 | |
1497 static void clear_global (const std::string& name) | |
1498 { | |
1499 symbol_table *inst = get_instance (xcurrent_scope); | |
1500 | |
1501 if (inst) | |
1502 inst->do_clear_global (name); | |
1503 } | |
1504 | |
1505 static void clear_variable (const std::string& name) | |
1506 { | |
1507 symbol_table *inst = get_instance (xcurrent_scope); | |
1508 | |
1509 if (inst) | |
1510 inst->do_clear_variable (name); | |
1511 } | |
1512 | |
1513 static void clear_symbol (const std::string& name) | |
1514 { | |
1515 // FIXME -- are we supposed to do both here? | |
1516 | |
1517 clear_variable (name); | |
1518 clear_function (name); | |
1519 } | |
1520 | |
1521 static void clear_function_pattern (const std::string& pat) | |
1522 { | |
1523 glob_match pattern (pat); | |
1524 | |
1525 for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) | |
1526 { | |
1527 if (pattern.match (p->first)) | |
1528 p->second.clear_user_function (); | |
1529 } | |
1530 } | |
1531 | |
1532 static void clear_global_pattern (const std::string& pat) | |
1533 { | |
1534 symbol_table *inst = get_instance (xcurrent_scope); | |
1535 | |
1536 if (inst) | |
1537 inst->do_clear_global_pattern (pat); | |
1538 } | |
1539 | |
1540 static void clear_variable_pattern (const std::string& pat) | |
1541 { | |
1542 symbol_table *inst = get_instance (xcurrent_scope); | |
1543 | |
1544 if (inst) | |
1545 inst->do_clear_variable_pattern (pat); | |
1546 } | |
1547 | |
1548 static void clear_variable_regexp (const std::string& pat) | |
1549 { | |
1550 symbol_table *inst = get_instance (xcurrent_scope); | |
1551 | |
1552 if (inst) | |
1553 inst->do_clear_variable_regexp (pat); | |
1554 } | |
1555 | |
1556 static void clear_symbol_pattern (const std::string& pat) | |
1557 { | |
1558 // FIXME -- are we supposed to do both here? | |
1559 | |
1560 clear_variable_pattern (pat); | |
1561 clear_function_pattern (pat); | |
1562 } | |
1563 | |
1564 static void clear_user_function (const std::string& name) | |
1565 { | |
1566 fcn_table_iterator p = fcn_table.find (name); | |
1567 | |
1568 if (p != fcn_table.end ()) | |
1569 { | |
1570 fcn_info& finfo = p->second; | |
1571 | |
1572 finfo.clear_user_function (); | |
1573 } | |
1574 // FIXME -- is this necessary, or even useful? | |
1575 // else | |
1576 // error ("clear: no such function `%s'", name.c_str ()); | |
1577 } | |
1578 | |
1579 // This clears oct and mex files, incl. autoloads. | |
1580 static void clear_dld_function (const std::string& name) | |
1581 { | |
1582 fcn_table_iterator p = fcn_table.find (name); | |
1583 | |
1584 if (p != fcn_table.end ()) | |
1585 { | |
1586 fcn_info& finfo = p->second; | |
1587 | |
1588 finfo.clear_autoload_function (); | |
1589 finfo.clear_user_function (); | |
1590 } | |
1591 } | |
1592 | |
1593 static void clear_mex_functions (void) | |
1594 { | |
1595 for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++) | |
1596 { | |
1597 fcn_info& finfo = p->second; | |
1598 | |
1599 finfo.clear_mex_function (); | |
1600 } | |
1601 } | |
1602 | |
1603 static bool set_class_relationship (const std::string& sup_class, | |
1604 const std::string& inf_class); | |
1605 | |
1606 static bool is_superiorto (const std::string& a, const std::string& b); | |
1607 | |
1608 static void alias_built_in_function (const std::string& alias, | |
1609 const std::string& name) | |
1610 { | |
1611 octave_value fcn = find_built_in_function (name); | |
1612 | |
1613 if (fcn.is_defined ()) | |
1614 { | |
1615 fcn_info finfo (alias); | |
1616 | |
1617 finfo.install_built_in_function (fcn); | |
1618 | |
1619 fcn_table[alias] = finfo; | |
1620 } | |
1621 else | |
1622 panic ("alias: `%s' is undefined", name.c_str ()); | |
1623 } | |
1624 | |
1625 static void add_dispatch (const std::string& name, const std::string& type, | |
1626 const std::string& fname) | |
1627 { | |
1628 fcn_table_iterator p = fcn_table.find (name); | |
1629 | |
1630 if (p != fcn_table.end ()) | |
1631 { | |
1632 fcn_info& finfo = p->second; | |
1633 | |
1634 finfo.add_dispatch (type, fname); | |
1635 } | |
1636 else | |
1637 { | |
1638 fcn_info finfo (name); | |
1639 | |
1640 finfo.add_dispatch (type, fname); | |
1641 | |
1642 fcn_table[name] = finfo; | |
1643 } | |
1644 } | |
1645 | |
1646 static void clear_dispatch (const std::string& name, const std::string& type) | |
1647 { | |
1648 fcn_table_iterator p = fcn_table.find (name); | |
1649 | |
1650 if (p != fcn_table.end ()) | |
1651 { | |
1652 fcn_info& finfo = p->second; | |
1653 | |
1654 finfo.clear_dispatch (type); | |
1655 } | |
1656 } | |
1657 | |
1658 static void print_dispatch (std::ostream& os, const std::string& name) | |
1659 { | |
1660 fcn_table_iterator p = fcn_table.find (name); | |
1661 | |
1662 if (p != fcn_table.end ()) | |
1663 { | |
1664 fcn_info& finfo = p->second; | |
1665 | |
1666 finfo.print_dispatch (os); | |
1667 } | |
1668 } | |
1669 | |
1670 static fcn_info::dispatch_map_type get_dispatch (const std::string& name) | |
1671 { | |
1672 fcn_info::dispatch_map_type retval; | |
1673 | |
1674 fcn_table_iterator p = fcn_table.find (name); | |
1675 | |
1676 if (p != fcn_table.end ()) | |
1677 { | |
1678 fcn_info& finfo = p->second; | |
1679 | |
1680 retval = finfo.get_dispatch (); | |
1681 } | |
1682 | |
1683 return retval; | |
1684 } | |
1685 | |
1686 static std::string help_for_dispatch (const std::string& name) | |
1687 { | |
1688 std::string retval; | |
1689 | |
1690 fcn_table_iterator p = fcn_table.find (name); | |
1691 | |
1692 if (p != fcn_table.end ()) | |
1693 { | |
1694 fcn_info& finfo = p->second; | |
1695 | |
1696 retval = finfo.help_for_dispatch (); | |
1697 } | |
1698 | |
1699 return retval; | |
1700 } | |
1701 | |
1702 static void push_context (void) | |
1703 { | |
1704 if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) | |
1705 error ("invalid call to xymtab::push_context"); | |
1706 else | |
1707 { | |
1708 symbol_table *inst = get_instance (xcurrent_scope); | |
1709 | |
1710 if (inst) | |
1711 inst->do_push_context (); | |
1712 } | |
1713 } | |
1714 | |
1715 static void pop_context (void) | |
1716 { | |
1717 if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope) | |
1718 error ("invalid call to xymtab::pop_context"); | |
1719 else | |
1720 { | |
1721 symbol_table *inst = get_instance (xcurrent_scope); | |
1722 | |
1723 if (inst) | |
1724 inst->do_pop_context (); | |
1725 } | |
1726 } | |
1727 | |
1728 // For unwind_protect. | |
1729 static void pop_context (void *) { pop_context (); } | |
1730 | |
1731 static void mark_automatic (const std::string& name) | |
1732 { | |
1733 symbol_table *inst = get_instance (xcurrent_scope); | |
1734 | |
1735 if (inst) | |
1736 inst->do_mark_automatic (name); | |
1737 } | |
1738 | |
1739 static void mark_hidden (const std::string& name) | |
1740 { | |
1741 symbol_table *inst = get_instance (xcurrent_scope); | |
1742 | |
1743 if (inst) | |
1744 inst->do_mark_hidden (name); | |
1745 } | |
1746 | |
1747 static void mark_global (const std::string& name) | |
1748 { | |
1749 symbol_table *inst = get_instance (xcurrent_scope); | |
1750 | |
1751 if (inst) | |
1752 inst->do_mark_global (name); | |
1753 } | |
1754 | |
1755 static std::list<symbol_record> | |
1756 all_variables (scope_id scope = xcurrent_scope, | |
1757 context_id context = xdefault_context, | |
1758 bool defined_only = true) | |
1759 { | |
1760 symbol_table *inst = get_instance (scope); | |
1761 | |
1762 return inst | |
1763 ? inst->do_all_variables (context, defined_only) : std::list<symbol_record> (); | |
1764 } | |
1765 | |
1766 static std::list<symbol_record> glob (const std::string& pattern) | |
1767 { | |
1768 symbol_table *inst = get_instance (xcurrent_scope); | |
1769 | |
1770 return inst ? inst->do_glob (pattern) : std::list<symbol_record> (); | |
1771 } | |
1772 | |
1773 static std::list<symbol_record> regexp (const std::string& pattern) | |
1774 { | |
1775 symbol_table *inst = get_instance (xcurrent_scope); | |
1776 | |
1777 return inst ? inst->do_regexp (pattern) : std::list<symbol_record> (); | |
1778 } | |
1779 | |
1780 static std::list<symbol_record> glob_variables (const std::string& pattern) | |
1781 { | |
1782 symbol_table *inst = get_instance (xcurrent_scope); | |
1783 | |
1784 return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> (); | |
1785 } | |
1786 | |
1787 static std::list<symbol_record> regexp_variables (const std::string& pattern) | |
1788 { | |
1789 symbol_table *inst = get_instance (xcurrent_scope); | |
1790 | |
1791 return inst ? inst->do_regexp (pattern, true) : std::list<symbol_record> (); | |
1792 } | |
1793 | |
1794 static std::list<symbol_record> | |
1795 glob_global_variables (const std::string& pattern) | |
1796 { | |
1797 std::list<symbol_record> retval; | |
1798 | |
1799 glob_match pat (pattern); | |
1800 | |
1801 for (global_table_const_iterator p = global_table.begin (); | |
1802 p != global_table.end (); p++) | |
1803 { | |
1804 // We generate a list of symbol_record objects so that | |
1805 // the results from glob_variables and glob_global_variables | |
1806 // may be handled the same way. | |
1807 | |
1808 if (pat.match (p->first)) | |
1809 retval.push_back (symbol_record (xglobal_scope, | |
1810 p->first, p->second, | |
1811 symbol_record::global)); | |
1812 } | |
1813 | |
1814 return retval; | |
1815 } | |
1816 | |
1817 static std::list<symbol_record> | |
1818 regexp_global_variables (const std::string& pattern) | |
1819 { | |
1820 std::list<symbol_record> retval; | |
1821 | |
1822 ::regexp pat (pattern); | |
1823 | |
1824 for (global_table_const_iterator p = global_table.begin (); | |
1825 p != global_table.end (); p++) | |
1826 { | |
1827 // We generate a list of symbol_record objects so that | |
1828 // the results from regexp_variables and regexp_global_variables | |
1829 // may be handled the same way. | |
1830 | |
1831 if (pat.is_match (p->first)) | |
1832 retval.push_back (symbol_record (xglobal_scope, | |
1833 p->first, p->second, | |
1834 symbol_record::global)); | |
1835 } | |
1836 | |
1837 return retval; | |
1838 } | |
1839 | |
1840 static std::list<symbol_record> glob_variables (const string_vector& patterns) | |
1841 { | |
1842 std::list<symbol_record> retval; | |
1843 | |
1844 size_t len = patterns.length (); | |
1845 | |
1846 for (size_t i = 0; i < len; i++) | |
1847 { | |
1848 std::list<symbol_record> tmp = glob_variables (patterns[i]); | |
1849 | |
1850 retval.insert (retval.begin (), tmp.begin (), tmp.end ()); | |
1851 } | |
1852 | |
1853 return retval; | |
1854 } | |
1855 | |
1856 static std::list<symbol_record> regexp_variables | |
1857 (const string_vector& patterns) | |
1858 { | |
1859 std::list<symbol_record> retval; | |
1860 | |
1861 size_t len = patterns.length (); | |
1862 | |
1863 for (size_t i = 0; i < len; i++) | |
1864 { | |
1865 std::list<symbol_record> tmp = regexp_variables (patterns[i]); | |
1866 | |
1867 retval.insert (retval.begin (), tmp.begin (), tmp.end ()); | |
1868 } | |
1869 | |
1870 return retval; | |
1871 } | |
1872 | |
1873 static std::list<std::string> user_function_names (void) | |
1874 { | |
1875 std::list<std::string> retval; | |
1876 | |
1877 for (fcn_table_iterator p = fcn_table.begin (); | |
1878 p != fcn_table.end (); p++) | |
1879 { | |
1880 if (p->second.is_user_function_defined ()) | |
1881 retval.push_back (p->first); | |
1882 } | |
1883 | |
1884 if (! retval.empty ()) | |
1885 retval.sort (); | |
1886 | |
1887 return retval; | |
1888 } | |
1889 | |
1890 static std::list<std::string> global_variable_names (void) | |
1891 { | |
1892 std::list<std::string> retval; | |
1893 | |
1894 for (global_table_const_iterator p = global_table.begin (); | |
1895 p != global_table.end (); p++) | |
1896 retval.push_back (p->first); | |
1897 | |
1898 retval.sort (); | |
1899 | |
1900 return retval; | |
1901 } | |
1902 | |
1903 static std::list<std::string> top_level_variable_names (void) | |
1904 { | |
1905 symbol_table *inst = get_instance (xtop_scope); | |
1906 | |
1907 return inst ? inst->do_variable_names () : std::list<std::string> (); | |
1908 } | |
1909 | |
1910 static std::list<std::string> variable_names (void) | |
1911 { | |
1912 symbol_table *inst = get_instance (xcurrent_scope); | |
1913 | |
1914 return inst ? inst->do_variable_names () : std::list<std::string> (); | |
1915 } | |
1916 | |
1917 static std::list<std::string> built_in_function_names (void) | |
1918 { | |
1919 std::list<std::string> retval; | |
1920 | |
1921 for (fcn_table_const_iterator p = fcn_table.begin (); | |
1922 p != fcn_table.end (); p++) | |
1923 { | |
1924 octave_value fcn = p->second.find_built_in_function (); | |
1925 | |
1926 if (fcn.is_defined ()) | |
1927 retval.push_back (p->first); | |
1928 } | |
1929 | |
1930 if (! retval.empty ()) | |
1931 retval.sort (); | |
1932 | |
1933 return retval; | |
1934 } | |
1935 | |
1936 static std::list<std::string> cmdline_function_names (void) | |
1937 { | |
1938 std::list<std::string> retval; | |
1939 | |
1940 for (fcn_table_const_iterator p = fcn_table.begin (); | |
1941 p != fcn_table.end (); p++) | |
1942 { | |
1943 octave_value fcn = p->second.find_cmdline_function (); | |
1944 | |
1945 if (fcn.is_defined ()) | |
1946 retval.push_back (p->first); | |
1947 } | |
1948 | |
1949 if (! retval.empty ()) | |
1950 retval.sort (); | |
1951 | |
1952 return retval; | |
1953 } | |
1954 | |
1955 static bool is_local_variable (const std::string& name) | |
1956 { | |
1957 if (xcurrent_scope == xglobal_scope) | |
1958 return false; | |
1959 else | |
1960 { | |
1961 symbol_table *inst = get_instance (xcurrent_scope); | |
1962 | |
1963 return inst ? inst->do_is_local_variable (name) : false; | |
1964 } | |
1965 } | |
1966 | |
1967 static bool is_global (const std::string& name) | |
1968 { | |
1969 if (xcurrent_scope == xglobal_scope) | |
1970 return true; | |
1971 else | |
1972 { | |
1973 symbol_table *inst = get_instance (xcurrent_scope); | |
1974 | |
1975 return inst ? inst->do_is_global (name) : false; | |
1976 } | |
1977 } | |
1978 | |
1979 static void dump (std::ostream& os, scope_id scope = xcurrent_scope); | |
1980 | |
1981 static void dump_global (std::ostream& os); | |
1982 | |
1983 static void dump_functions (std::ostream& os); | |
1984 | |
1985 static void cache_name (scope_id scope, const std::string& name) | |
1986 { | |
1987 symbol_table *inst = get_instance (scope, false); | |
1988 | |
1989 if (inst) | |
1990 inst->do_cache_name (name); | |
1991 } | |
1992 | |
1993 static void lock_subfunctions (scope_id scope = xcurrent_scope) | |
1994 { | |
1995 for (fcn_table_iterator p = fcn_table.begin (); | |
1996 p != fcn_table.end (); p++) | |
1997 p->second.lock_subfunction (scope); | |
1998 } | |
1999 | |
2000 static void unlock_subfunctions (scope_id scope = xcurrent_scope) | |
2001 { | |
2002 for (fcn_table_iterator p = fcn_table.begin (); | |
2003 p != fcn_table.end (); p++) | |
2004 p->second.unlock_subfunction (scope); | |
2005 } | |
2006 | |
2007 static void free_scope (scope_id scope) | |
2008 { | |
2009 if (scope == xglobal_scope || scope == xtop_scope) | |
2010 error ("can't free global or top-level scopes!"); | |
2011 else | |
2012 symbol_table::scope_id_cache::free (scope); | |
2013 } | |
2014 | |
2015 static void stash_dir_name_for_subfunctions (scope_id scope, | |
2016 const std::string& dir_name); | |
2017 | |
2018 static void add_to_parent_map (const std::string& classname, | |
2019 const std::list<std::string>& parent_list) | |
2020 { | |
2021 parent_map[classname] = parent_list; | |
2022 } | |
2023 | |
2024 static std::list<std::string> | |
2025 parent_classes (const std::string& dispatch_type) | |
2026 { | |
2027 std::list<std::string> retval; | |
2028 | |
2029 const_parent_map_iterator it = parent_map.find (dispatch_type); | |
2030 | |
2031 if (it != parent_map.end ()) | |
2032 retval = it->second; | |
2033 | |
2034 for (std::list<std::string>::const_iterator lit = retval.begin (); | |
2035 lit != retval.end (); lit++) | |
2036 { | |
2037 // Search for parents of parents and append them to the list. | |
2038 | |
2039 // FIXME -- should we worry about a circular inheritance graph? | |
2040 | |
2041 std::list<std::string> parents = parent_classes (*lit); | |
2042 | |
2043 if (! parents.empty ()) | |
2044 retval.insert (retval.end (), parents.begin (), parents.end ()); | |
2045 } | |
2046 | |
2047 return retval; | |
2048 } | |
2049 | |
2050 static octave_user_function *get_curr_fcn (scope_id scope = xcurrent_scope) | |
2051 { | |
2052 symbol_table *inst = get_instance (scope); | |
2053 return inst->curr_fcn; | |
2054 } | |
2055 | |
2056 static void set_curr_fcn (octave_user_function *curr_fcn, | |
2057 scope_id scope = xcurrent_scope) | |
2058 { | |
2059 assert (scope != xtop_scope && scope != xglobal_scope); | |
2060 symbol_table *inst = get_instance (scope); | |
2061 // FIXME: normally, functions should not usurp each other's scope. | |
2062 // If for any incredible reason this is needed, call | |
2063 // set_user_function (0, scope) first. This may cause problems with | |
2064 // nested functions, as the curr_fcn of symbol_records must be updated. | |
2065 assert (inst->curr_fcn == 0 || curr_fcn == 0); | |
2066 inst->curr_fcn = curr_fcn; | |
2067 } | |
2068 | |
2069 static void cleanup (void); | |
2070 | |
2071 private: | |
2072 | |
2073 // No copying! | |
2074 | |
2075 symbol_table (const symbol_table&); | |
2076 | |
2077 symbol_table& operator = (const symbol_table&); | |
2078 | |
2079 typedef std::map<std::string, symbol_record>::const_iterator table_const_iterator; | |
2080 typedef std::map<std::string, symbol_record>::iterator table_iterator; | |
2081 | |
2082 typedef std::map<std::string, octave_value>::const_iterator global_table_const_iterator; | |
2083 typedef std::map<std::string, octave_value>::iterator global_table_iterator; | |
2084 | |
2085 typedef std::map<std::string, octave_value>::const_iterator persistent_table_const_iterator; | |
2086 typedef std::map<std::string, octave_value>::iterator persistent_table_iterator; | |
2087 | |
2088 typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator; | |
2089 typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator; | |
2090 | |
2091 typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator; | |
2092 typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator; | |
2093 | |
2094 // The scope of this symbol table. | |
2095 scope_id my_scope; | |
2096 | |
2097 // Name for this table (usually the file name of the function | |
2098 // corresponding to the scope); | |
2099 std::string table_name; | |
2100 | |
2101 // Map from symbol names to symbol info. | |
2102 std::map<std::string, symbol_record> table; | |
2103 | |
2104 // Child nested functions. | |
2105 std::vector<symbol_table*> nest_children; | |
2106 | |
2107 // Parent nested function (may be null). | |
2108 symbol_table *nest_parent; | |
2109 | |
2110 // The associated user code (may be null). | |
2111 octave_user_function *curr_fcn; | |
2112 | |
2113 // Map from names of global variables to values. | |
2114 static std::map<std::string, octave_value> global_table; | |
2115 | |
2116 // Map from names of persistent variables to values. | |
2117 std::map<std::string, octave_value> persistent_table; | |
2118 | |
2119 // Pointer to symbol table for current scope (variables only). | |
2120 static symbol_table *instance; | |
2121 | |
2122 // Map from scope id to symbol table instances. | |
2123 static std::map<scope_id, symbol_table*> all_instances; | |
2124 | |
2125 // Map from function names to function info (subfunctions, private | |
2126 // functions, class constructors, class methods, etc.) | |
2127 static std::map<std::string, fcn_info> fcn_table; | |
2128 | |
2129 // Mape from class names to set of classes that have lower | |
2130 // precedence. | |
2131 static std::map<std::string, std::set<std::string> > class_precedence_table; | |
2132 | |
2133 typedef std::map<std::string, std::set<std::string> >::const_iterator class_precedence_table_const_iterator; | |
2134 typedef std::map<std::string, std::set<std::string> >::iterator class_precedence_table_iterator; | |
2135 | |
2136 // Map from class names to parent class names. | |
2137 static std::map<std::string, std::list<std::string> > parent_map; | |
2138 | |
2139 typedef std::map<std::string, std::list<std::string> >::const_iterator const_parent_map_iterator; | |
2140 typedef std::map<std::string, std::list<std::string> >::iterator parent_map_iterator; | |
2141 | |
2142 static const scope_id xglobal_scope; | |
2143 static const scope_id xtop_scope; | |
2144 | |
2145 static scope_id xcurrent_scope; | |
2146 | |
2147 static context_id xcurrent_context; | |
2148 | |
2149 static const context_id xdefault_context = static_cast<context_id> (-1); | |
2150 | |
2151 symbol_table (scope_id scope) | |
2152 : my_scope (scope), table_name (), table (), nest_children (), nest_parent (0), | |
2153 curr_fcn (0), persistent_table () { } | |
2154 | |
2155 ~symbol_table (void) { } | |
2156 | |
2157 static symbol_table *get_instance (scope_id scope, bool create = true) | |
2158 { | |
2159 symbol_table *retval = 0; | |
2160 | |
2161 bool ok = true; | |
2162 | |
2163 if (scope != xglobal_scope) | |
2164 { | |
2165 if (scope == xcurrent_scope) | |
2166 { | |
2167 if (! instance && create) | |
2168 { | |
2169 symbol_table *inst = new symbol_table (scope); | |
2170 | |
2171 if (inst) | |
2172 { | |
2173 all_instances[scope] = instance = inst; | |
2174 | |
2175 if (scope == xtop_scope) | |
2176 instance->do_cache_name ("top-level"); | |
2177 } | |
2178 } | |
2179 | |
2180 if (! instance) | |
2181 ok = false; | |
2182 | |
2183 retval = instance; | |
2184 } | |
2185 else | |
2186 { | |
2187 all_instances_iterator p = all_instances.find (scope); | |
2188 | |
2189 if (p == all_instances.end ()) | |
2190 { | |
2191 if (create) | |
2192 { | |
2193 retval = new symbol_table (scope); | |
2194 | |
2195 if (retval) | |
2196 all_instances[scope] = retval; | |
2197 else | |
2198 ok = false; | |
2199 } | |
2200 else | |
2201 ok = false; | |
2202 } | |
2203 else | |
2204 retval = p->second; | |
2205 } | |
2206 } | |
2207 | |
2208 if (! ok) | |
2209 error ("unable to %s symbol_table object for scope %d!", | |
2210 create ? "create" : "find", scope); | |
2211 | |
2212 return retval; | |
2213 } | |
2214 | |
2215 void add_nest_child (symbol_table& st) | |
2216 { | |
2217 assert (!st.nest_parent); | |
2218 nest_children.push_back (&st); | |
2219 st.nest_parent = this; | |
2220 } | |
2221 | |
2222 void insert_symbol_record (const symbol_record& sr) | |
2223 { | |
2224 table[sr.name ()] = sr; | |
2225 } | |
2226 | |
2227 void | |
2228 do_dup_scope (symbol_table& new_symbol_table) const | |
2229 { | |
2230 for (table_const_iterator p = table.begin (); p != table.end (); p++) | |
2231 new_symbol_table.insert_symbol_record (p->second.dup (new_symbol_table.my_scope)); | |
2232 } | |
2233 | |
2234 symbol_record do_find_symbol (const std::string& name) | |
2235 { | |
2236 table_iterator p = table.find (name); | |
2237 | |
2238 if (p == table.end ()) | |
2239 return do_insert (name); | |
2240 else | |
2241 return p->second; | |
2242 } | |
2243 | |
2244 void do_inherit (symbol_table& donor_table, context_id donor_context) | |
2245 { | |
2246 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2247 { | |
2248 symbol_record& sr = p->second; | |
2249 | |
2250 if (! (sr.is_automatic () || sr.is_formal ())) | |
2251 { | |
2252 std::string nm = sr.name (); | |
2253 | |
2254 if (nm != "__retval__") | |
2255 { | |
2256 octave_value val = donor_table.do_varval (nm, donor_context); | |
2257 | |
2258 if (val.is_defined ()) | |
2259 { | |
2260 sr.varref (0) = val; | |
2261 | |
2262 sr.mark_inherited (); | |
2263 } | |
2264 } | |
2265 } | |
2266 } | |
2267 } | |
2268 | |
2269 static fcn_info *get_fcn_info (const std::string& name) | |
2270 { | |
2271 fcn_table_iterator p = fcn_table.find (name); | |
2272 return p != fcn_table.end () ? &p->second : 0; | |
2273 } | |
2274 | |
2275 octave_value | |
2276 do_find (const std::string& name, const octave_value_list& args, | |
2277 bool skip_variables, bool local_funcs); | |
2278 | |
2279 octave_value do_builtin_find (const std::string& name); | |
2280 | |
2281 symbol_record& do_insert (const std::string& name) | |
2282 { | |
2283 table_iterator p = table.find (name); | |
2284 | |
2285 if (p == table.end ()) | |
2286 { | |
2287 symbol_record parent_symbol; | |
2288 | |
2289 if (nest_parent && nest_parent->look_nonlocal (name, parent_symbol)) | |
2290 return table[name] = parent_symbol; | |
2291 else | |
2292 return table[name] = symbol_record (my_scope, name, octave_value ()); | |
2293 } | |
2294 else | |
2295 return p->second; | |
2296 } | |
2297 | |
2298 void do_force_variable (const std::string& name, context_id context) | |
2299 { | |
2300 table_iterator p = table.find (name); | |
2301 | |
2302 if (p == table.end ()) | |
2303 { | |
2304 symbol_record& sr = do_insert (name); | |
2305 | |
2306 sr.force_variable (context); | |
2307 } | |
2308 else | |
2309 p->second.force_variable (context); | |
2310 } | |
2311 | |
2312 octave_value& do_varref (const std::string& name, context_id context) | |
2313 { | |
2314 table_iterator p = table.find (name); | |
2315 | |
2316 if (p == table.end ()) | |
2317 { | |
2318 symbol_record& sr = do_insert (name); | |
2319 | |
2320 return sr.varref (context); | |
2321 } | |
2322 else | |
2323 return p->second.varref (context); | |
2324 } | |
2325 | |
2326 octave_value do_varval (const std::string& name, context_id context) const | |
2327 { | |
2328 table_const_iterator p = table.find (name); | |
2329 | |
2330 return (p != table.end ()) ? p->second.varval (context) : octave_value (); | |
2331 } | |
2332 | |
2333 octave_value& do_persistent_varref (const std::string& name) | |
2334 { | |
2335 persistent_table_iterator p = persistent_table.find (name); | |
2336 | |
2337 return (p == persistent_table.end ()) | |
2338 ? persistent_table[name] : p->second; | |
2339 } | |
2340 | |
2341 octave_value do_persistent_varval (const std::string& name) | |
2342 { | |
2343 persistent_table_const_iterator p = persistent_table.find (name); | |
2344 | |
2345 return (p != persistent_table.end ()) ? p->second : octave_value (); | |
2346 } | |
2347 | |
2348 void do_erase_persistent (const std::string& name) | |
2349 { | |
2350 persistent_table_iterator p = persistent_table.find (name); | |
2351 | |
2352 if (p != persistent_table.end ()) | |
2353 persistent_table.erase (p); | |
2354 } | |
2355 | |
2356 bool do_is_variable (const std::string& name) const | |
2357 { | |
2358 bool retval = false; | |
2359 | |
2360 table_const_iterator p = table.find (name); | |
2361 | |
2362 if (p != table.end ()) | |
2363 { | |
2364 const symbol_record& sr = p->second; | |
2365 | |
2366 retval = sr.is_variable (); | |
2367 } | |
2368 | |
2369 return retval; | |
2370 } | |
2371 | |
2372 void do_push_context (void) | |
2373 { | |
2374 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2375 p->second.push_context (my_scope); | |
2376 } | |
2377 | |
2378 void do_pop_context (void) | |
2379 { | |
2380 for (table_iterator p = table.begin (); p != table.end (); ) | |
2381 { | |
2382 if (p->second.pop_context (my_scope) == 0) | |
2383 table.erase (p++); | |
2384 else | |
2385 p++; | |
2386 } | |
2387 } | |
2388 | |
2389 void do_clear_variables (void) | |
2390 { | |
2391 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2392 p->second.clear (my_scope); | |
2393 } | |
2394 | |
2395 void do_clear_objects (void) | |
2396 { | |
2397 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2398 { | |
2399 symbol_record& sr = p->second; | |
2400 octave_value& val = sr.varref (); | |
2401 if (val.is_object ()) | |
2402 p->second.clear (my_scope); | |
2403 } | |
2404 } | |
2405 | |
2406 void do_unmark_forced_variables (void) | |
2407 { | |
2408 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2409 p->second.unmark_forced (); | |
2410 } | |
2411 | |
2412 void do_clear_global (const std::string& name) | |
2413 { | |
2414 table_iterator p = table.find (name); | |
2415 | |
2416 if (p != table.end ()) | |
2417 { | |
2418 symbol_record& sr = p->second; | |
2419 | |
2420 if (sr.is_global ()) | |
2421 sr.unmark_global (); | |
2422 } | |
2423 | |
2424 global_table_iterator q = global_table.find (name); | |
2425 | |
2426 if (q != global_table.end ()) | |
2427 global_table.erase (q); | |
2428 | |
2429 } | |
2430 | |
2431 void do_clear_variable (const std::string& name) | |
2432 { | |
2433 table_iterator p = table.find (name); | |
2434 | |
2435 if (p != table.end ()) | |
2436 p->second.clear (my_scope); | |
2437 } | |
2438 | |
2439 void do_clear_global_pattern (const std::string& pat) | |
2440 { | |
2441 glob_match pattern (pat); | |
2442 | |
2443 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2444 { | |
2445 symbol_record& sr = p->second; | |
2446 | |
2447 if (sr.is_global () && pattern.match (sr.name ())) | |
2448 sr.unmark_global (); | |
2449 } | |
2450 | |
2451 | |
2452 for (global_table_iterator q = global_table.begin (); | |
2453 q != global_table.end ();) | |
2454 { | |
2455 if (pattern.match (q->first)) | |
2456 global_table.erase (q++); //Gotta be careful to not | |
2457 //invalidate iterators | |
2458 else | |
2459 q++; | |
2460 } | |
2461 | |
2462 | |
2463 } | |
2464 | |
2465 void do_clear_variable_pattern (const std::string& pat) | |
2466 { | |
2467 glob_match pattern (pat); | |
2468 | |
2469 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2470 { | |
2471 symbol_record& sr = p->second; | |
2472 | |
2473 if (sr.is_defined () || sr.is_global ()) | |
2474 { | |
2475 if (pattern.match (sr.name ())) | |
2476 sr.clear (my_scope); | |
2477 } | |
2478 } | |
2479 } | |
2480 | |
2481 void do_clear_variable_regexp (const std::string& pat) | |
2482 { | |
2483 ::regexp pattern (pat); | |
2484 | |
2485 for (table_iterator p = table.begin (); p != table.end (); p++) | |
2486 { | |
2487 symbol_record& sr = p->second; | |
2488 | |
2489 if (sr.is_defined () || sr.is_global ()) | |
2490 { | |
2491 if (pattern.is_match (sr.name ())) | |
2492 sr.clear (my_scope); | |
2493 } | |
2494 } | |
2495 } | |
2496 | |
2497 void do_mark_automatic (const std::string& name) | |
2498 { | |
2499 do_insert (name).mark_automatic (); | |
2500 } | |
2501 | |
2502 void do_mark_hidden (const std::string& name) | |
2503 { | |
2504 do_insert (name).mark_hidden (); | |
2505 } | |
2506 | |
2507 void do_mark_global (const std::string& name) | |
2508 { | |
2509 do_insert (name).mark_global (); | |
2510 } | |
2511 | |
2512 std::list<symbol_record> | |
2513 do_all_variables (context_id context, bool defined_only) const | |
2514 { | |
2515 std::list<symbol_record> retval; | |
2516 | |
2517 for (table_const_iterator p = table.begin (); p != table.end (); p++) | |
2518 { | |
2519 const symbol_record& sr = p->second; | |
2520 | |
2521 if (defined_only && ! sr.is_defined (context)) | |
2522 continue; | |
2523 | |
2524 retval.push_back (sr); | |
2525 } | |
2526 | |
2527 return retval; | |
2528 } | |
2529 | |
2530 std::list<symbol_record> do_glob (const std::string& pattern, | |
2531 bool vars_only = false) const | |
2532 { | |
2533 std::list<symbol_record> retval; | |
2534 | |
2535 glob_match pat (pattern); | |
2536 | |
2537 for (table_const_iterator p = table.begin (); p != table.end (); p++) | |
2538 { | |
2539 if (pat.match (p->first)) | |
2540 { | |
2541 const symbol_record& sr = p->second; | |
2542 | |
2543 if (vars_only && ! sr.is_variable ()) | |
2544 continue; | |
2545 | |
2546 retval.push_back (sr); | |
2547 } | |
2548 } | |
2549 | |
2550 return retval; | |
2551 } | |
2552 | |
2553 std::list<symbol_record> do_regexp (const std::string& pattern, | |
2554 bool vars_only = false) const | |
2555 { | |
2556 std::list<symbol_record> retval; | |
2557 | |
2558 ::regexp pat (pattern); | |
2559 | |
2560 for (table_const_iterator p = table.begin (); p != table.end (); p++) | |
2561 { | |
2562 if (pat.is_match (p->first)) | |
2563 { | |
2564 const symbol_record& sr = p->second; | |
2565 | |
2566 if (vars_only && ! sr.is_variable ()) | |
2567 continue; | |
2568 | |
2569 retval.push_back (sr); | |
2570 } | |
2571 } | |
2572 | |
2573 return retval; | |
2574 } | |
2575 | |
2576 std::list<std::string> do_variable_names (void) | |
2577 { | |
2578 std::list<std::string> retval; | |
2579 | |
2580 for (table_const_iterator p = table.begin (); p != table.end (); p++) | |
2581 { | |
2582 if (p->second.is_variable ()) | |
2583 retval.push_back (p->first); | |
2584 } | |
2585 | |
2586 retval.sort (); | |
2587 | |
2588 return retval; | |
2589 } | |
2590 | |
2591 static std::map<std::string, octave_value> | |
2592 subfunctions_defined_in_scope (scope_id scope = xcurrent_scope) | |
2593 { | |
2594 std::map<std::string, octave_value> retval; | |
2595 | |
2596 for (fcn_table_const_iterator p = fcn_table.begin (); | |
2597 p != fcn_table.end (); p++) | |
2598 { | |
2599 std::pair<std::string, octave_value> tmp | |
2600 = p->second.subfunction_defined_in_scope (scope); | |
2601 | |
2602 std::string nm = tmp.first; | |
2603 | |
2604 if (! nm.empty ()) | |
2605 retval[nm] = tmp.second; | |
2606 } | |
2607 | |
2608 return retval; | |
2609 } | |
2610 | |
2611 bool do_is_local_variable (const std::string& name) const | |
2612 { | |
2613 table_const_iterator p = table.find (name); | |
2614 | |
2615 return (p != table.end () | |
2616 && ! p->second.is_global () | |
2617 && p->second.is_defined ()); | |
2618 } | |
2619 | |
2620 bool do_is_global (const std::string& name) const | |
2621 { | |
2622 table_const_iterator p = table.find (name); | |
2623 | |
2624 return p != table.end () && p->second.is_global (); | |
2625 } | |
2626 | |
2627 void do_dump (std::ostream& os); | |
2628 | |
2629 void do_cache_name (const std::string& name) { table_name = name; } | |
2630 | |
2631 void do_update_nest (void); | |
2632 | |
2633 bool look_nonlocal (const std::string& name, symbol_record& result) | |
2634 { | |
2635 table_iterator p = table.find (name); | |
2636 if (p == table.end ()) | |
2637 { | |
2638 if (nest_parent) | |
2639 return nest_parent->look_nonlocal (name, result); | |
2640 } | |
2641 else if (! p->second.is_automatic ()) | |
2642 { | |
2643 result = p->second; | |
2644 return true; | |
2645 } | |
2646 | |
2647 return false; | |
2648 } | |
2649 }; | |
2650 | |
2651 extern bool out_of_date_check (octave_value& function, | |
2652 const std::string& dispatch_type = std::string (), | |
2653 bool check_relative = true); | |
2654 | |
2655 extern OCTINTERP_API std::string | |
2656 get_dispatch_type (const octave_value_list& args); | |
2657 extern OCTINTERP_API std::string | |
2658 get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type); | |
2659 | |
2660 #endif |