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