symtab.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2009 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #if !defined (octave_symtab_h)
00025 #define octave_symtab_h 1
00026 
00027 #include <deque>
00028 #include <list>
00029 #include <map>
00030 #include <set>
00031 #include <string>
00032 
00033 #include "glob-match.h"
00034 #include "regexp.h"
00035 
00036 class tree_argument_list;
00037 class octave_user_function;
00038 
00039 #include "oct-obj.h"
00040 #include "oct-refcount.h"
00041 #include "ov.h"
00042 
00043 class
00044 OCTINTERP_API
00045 symbol_table
00046 {
00047 public:
00048 
00049   typedef int scope_id;
00050   typedef size_t context_id;
00051 
00052   class
00053   scope_id_cache
00054   {
00055   protected:
00056 
00057     typedef std::set<scope_id>::iterator set_iterator;
00058     typedef std::set<scope_id>::const_iterator set_const_iterator;
00059 
00060     // We start with 2 because we allocate 0 for the global symbols
00061     // and 1 for the top-level workspace.
00062 
00063     scope_id_cache (void) : next_available (2), in_use (), free_list () { }
00064 
00065   public:
00066 
00067     ~scope_id_cache (void) { }
00068 
00069     static scope_id alloc (void)
00070     {
00071       return instance_ok () ? instance->do_alloc () : -1;
00072     }
00073 
00074     static void free (scope_id scope)
00075     {
00076       if (instance_ok ())
00077         return instance->do_free (scope);
00078     }
00079 
00080     static std::list<scope_id> scopes (void)
00081     {
00082       return instance_ok () ? instance->do_scopes () : std::list<scope_id> ();
00083     }
00084 
00085     static void create_instance (void);
00086 
00087     static bool instance_ok (void)
00088     {
00089       bool retval = true;
00090 
00091       if (! instance)
00092         create_instance ();
00093 
00094       if (! instance)
00095         {
00096           ::error ("unable to create scope_id_cache object!");
00097 
00098           retval = false;
00099         }
00100 
00101       return retval;
00102     }
00103 
00104   private:
00105 
00106     // No copying!
00107 
00108     scope_id_cache (const scope_id_cache&);
00109 
00110     scope_id_cache& operator = (const scope_id_cache&);
00111 
00112     static scope_id_cache *instance;
00113 
00114     static void cleanup_instance (void) { delete instance; instance = 0; }
00115 
00116     // The next available scope not in the free list.
00117     scope_id next_available;
00118 
00119     // The set of scope IDs that are currently allocated.
00120     std::set<scope_id> in_use;
00121 
00122     // The set of scope IDs that are currently available.
00123     std::set<scope_id> free_list;
00124 
00125     scope_id do_alloc (void)
00126     {
00127       scope_id retval;
00128 
00129       set_iterator p = free_list.begin ();
00130 
00131       if (p != free_list.end ())
00132         {
00133           retval = *p;
00134           free_list.erase (p);
00135         }
00136       else
00137         retval = next_available++;
00138 
00139       in_use.insert (retval);
00140 
00141       return retval;
00142     }
00143 
00144     void do_free (scope_id scope)
00145     {
00146       set_iterator p = in_use.find (scope);
00147 
00148       if (p != in_use.end ())
00149         {
00150           in_use.erase (p);
00151           free_list.insert (scope);
00152         }
00153       else
00154         error ("free_scope: scope %d not found!", scope);
00155     }
00156 
00157     std::list<scope_id> do_scopes (void) const
00158     {
00159       std::list<scope_id> retval;
00160 
00161       for (set_const_iterator p = in_use.begin (); p != in_use.end (); p++)
00162         retval.push_back (*p);
00163 
00164       retval.sort ();
00165 
00166       return retval;
00167     }
00168   };
00169 
00170   class fcn_info;
00171 
00172   class
00173   symbol_record
00174   {
00175   public:
00176 
00177     // generic variable
00178     static const unsigned int local = 1;
00179 
00180     // varargin, argn, .nargin., .nargout.
00181     // (FIXME -- is this really used now?)
00182     static const unsigned int automatic = 2;
00183 
00184     // formal parameter
00185     static const unsigned int formal = 4;
00186 
00187     // not listed or cleared (.nargin., .nargout.)
00188     static const unsigned int hidden = 8;
00189 
00190     // inherited from parent scope; not cleared at function exit
00191     static const unsigned int inherited = 16;
00192 
00193     // global (redirects to global scope)
00194     static const unsigned int global = 32;
00195 
00196     // not cleared at function exit
00197     static const unsigned int persistent = 64;
00198 
00199     // temporary variables forced into symbol table for parsing
00200     static const unsigned int forced = 128;
00201 
00202   private:
00203 
00204     class
00205     symbol_record_rep
00206     {
00207     public:
00208 
00209       symbol_record_rep (const std::string& nm, const octave_value& v,
00210                          unsigned int sc)
00211         : name (nm), value_stack (), storage_class (sc), finfo (), count (1)
00212       {
00213         value_stack.push_back (v);
00214       }
00215 
00216       void force_variable (context_id context)
00217       {
00218         octave_value& val = varref (context);
00219 
00220         if (! val.is_defined ())
00221           mark_forced ();
00222       }
00223 
00224       octave_value& varref (context_id context)
00225       {
00226         if (is_global ())
00227           return symbol_table::global_varref (name);
00228         else if (is_persistent ())
00229           return symbol_table::persistent_varref (name);
00230         else
00231           {
00232             context_id n = value_stack.size ();
00233             while (n++ <= context)
00234               value_stack.push_back (octave_value ());
00235 
00236             return value_stack[context];
00237           }
00238       }
00239 
00240       octave_value varval (context_id context) const
00241       {
00242         if (is_global ())
00243           return symbol_table::global_varval (name);
00244         else if (is_persistent ())
00245           return symbol_table::persistent_varval (name);
00246         else
00247           {
00248             if (context < value_stack.size ())
00249               return value_stack[context];
00250             else
00251               return octave_value ();
00252           }
00253       }
00254 
00255       void push_context (void)
00256       {
00257         if (! (is_persistent () || is_global ()))
00258           value_stack.push_back (octave_value ());
00259       }
00260 
00261       // If pop_context returns 0, we are out of values and this element
00262       // of the symbol table should be deleted.  This can happen for
00263       // functions like
00264       //
00265       //   function foo (n)
00266       //     if (n > 0)
00267       //       foo (n-1);
00268       //     else
00269       //       eval ("x = 1");
00270       //     endif
00271       //   endfunction
00272       //
00273       // Here, X should only exist in the final stack frame.
00274 
00275       size_t pop_context (void)
00276       {
00277         size_t retval = 1;
00278 
00279         if (! (is_persistent () || is_global ()))
00280           {
00281             value_stack.pop_back ();
00282             retval = value_stack.size ();
00283           }
00284 
00285         return retval;
00286       }
00287 
00288       void clear (void)
00289       {
00290         if (! (is_hidden () || is_inherited ()))
00291           {
00292             if (is_global ())
00293               unmark_global ();
00294 
00295             if (is_persistent ())
00296               {
00297                 symbol_table::persistent_varref (name)
00298                   = varval (xcurrent_context);
00299 
00300                 unmark_persistent ();
00301               }
00302 
00303             varref (xcurrent_context) = octave_value ();
00304           }
00305       }
00306 
00307       bool is_defined (context_id context) const
00308       {
00309         return varval (context).is_defined ();
00310       }
00311 
00312       bool is_variable (context_id context) const
00313       {
00314         return (! is_local () || is_defined (context) || is_forced ());
00315       }
00316 
00317       bool is_local (void) const { return storage_class & local; }
00318       bool is_automatic (void) const { return storage_class & automatic; }
00319       bool is_formal (void) const { return storage_class & formal; }
00320       bool is_hidden (void) const { return storage_class & hidden; }
00321       bool is_inherited (void) const { return storage_class & inherited; }
00322       bool is_global (void) const { return storage_class & global; }
00323       bool is_persistent (void) const { return storage_class & persistent; }
00324       bool is_forced (void) const { return storage_class & forced; }
00325 
00326       void mark_local (void) { storage_class |= local; }
00327       void mark_automatic (void) { storage_class |= automatic; }
00328       void mark_formal (void) { storage_class |= formal; }
00329       void mark_hidden (void) { storage_class |= hidden; }
00330       void mark_inherited (void) { storage_class |= inherited; }
00331       void mark_global (void)
00332       {
00333         if (is_persistent ())
00334           error ("can't make persistent variable %s global", name.c_str ());
00335         else
00336           storage_class |= global;
00337       }
00338       void mark_persistent (void)
00339       {
00340         if (is_global ())
00341           error ("can't make global variable %s persistent", name.c_str ());
00342         else
00343           storage_class |= persistent;
00344       }
00345       void mark_forced (void) { storage_class |= forced; }
00346 
00347       void unmark_local (void) { storage_class &= ~local; }
00348       void unmark_automatic (void) { storage_class &= ~automatic; }
00349       void unmark_formal (void) { storage_class &= ~formal; }
00350       void unmark_hidden (void) { storage_class &= ~hidden; }
00351       void unmark_inherited (void) { storage_class &= ~inherited; }
00352       void unmark_global (void) { storage_class &= ~global; }
00353       void unmark_persistent (void) { storage_class &= ~persistent; }
00354       void unmark_forced (void) { storage_class &= ~forced; }
00355 
00356       void init_persistent (void)
00357       {
00358         if (! is_defined (xcurrent_context))
00359           {
00360             mark_persistent ();
00361 
00362             varref (xcurrent_context) = symbol_table::persistent_varval (name);
00363           }
00364         // FIXME -- this causes trouble with recursive calls.
00365         // else
00366         //   error ("unable to declare existing variable persistent");
00367       }
00368 
00369       void erase_persistent (void)
00370       {
00371         unmark_persistent ();
00372         symbol_table::erase_persistent (name);
00373       }
00374 
00375       symbol_record_rep *dup (void) const
00376       {
00377         return new symbol_record_rep (name, varval (xcurrent_context),
00378                                       storage_class);
00379       }
00380 
00381       void dump (std::ostream& os, const std::string& prefix) const;
00382 
00383       std::string name;
00384 
00385       std::deque<octave_value> value_stack;
00386 
00387       unsigned int storage_class;
00388 
00389       fcn_info *finfo;
00390 
00391       octave_refcount<size_t> count;
00392 
00393     private:
00394 
00395       // No copying!
00396 
00397       symbol_record_rep (const symbol_record_rep& ov);
00398 
00399       symbol_record_rep& operator = (const symbol_record_rep&);
00400     };
00401 
00402   public:
00403 
00404     symbol_record (const std::string& nm = std::string (),
00405                    const octave_value& v = octave_value (),
00406                    unsigned int sc = local)
00407       : rep (new symbol_record_rep (nm, v, sc)) { }
00408 
00409     symbol_record (const symbol_record& sr)
00410       : rep (sr.rep)
00411     {
00412       rep->count++;
00413     }
00414 
00415     symbol_record& operator = (const symbol_record& sr)
00416     {
00417       if (this != &sr)
00418         {
00419           if (--rep->count == 0)
00420             delete rep;
00421 
00422           rep = sr.rep;
00423           rep->count++;
00424         }
00425 
00426       return *this;
00427     }
00428 
00429     ~symbol_record (void)
00430     {
00431       if (--rep->count == 0)
00432         delete rep;
00433     }
00434 
00435     symbol_record dup (void) const { return symbol_record (rep->dup ()); }
00436 
00437     std::string name (void) const { return rep->name; }
00438 
00439     octave_value find (const octave_value_list& args = octave_value_list ()) const;
00440 
00441     void force_variable (context_id context = xcurrent_context)
00442     {
00443       rep->force_variable (context);
00444     }
00445 
00446     octave_value& varref (context_id context = xcurrent_context)
00447     {
00448       return rep->varref (context);
00449     }
00450 
00451     octave_value varval (context_id context = xcurrent_context) const
00452     {
00453       return rep->varval (context);
00454     }
00455 
00456     void push_context (void) { rep->push_context (); }
00457 
00458     size_t pop_context (void) { return rep->pop_context (); }
00459 
00460     void clear (void) { rep->clear (); }
00461 
00462     bool is_defined (context_id context = xcurrent_context) const
00463     {
00464       return rep->is_defined (context);
00465     }
00466 
00467     bool is_variable (context_id context = xcurrent_context) const
00468     {
00469       return rep->is_variable (context);
00470     }
00471 
00472     bool is_local (void) const { return rep->is_local (); }
00473     bool is_automatic (void) const { return rep->is_automatic (); }
00474     bool is_formal (void) const { return rep->is_formal (); }
00475     bool is_global (void) const { return rep->is_global (); }
00476     bool is_hidden (void) const { return rep->is_hidden (); }
00477     bool is_inherited (void) const { return rep->is_inherited (); }
00478     bool is_persistent (void) const { return rep->is_persistent (); }
00479     bool is_forced (void) const { return rep->is_forced (); }
00480 
00481     void mark_local (void) { rep->mark_local (); }
00482     void mark_automatic (void) { rep->mark_automatic (); }
00483     void mark_formal (void) { rep->mark_formal (); }
00484     void mark_hidden (void) { rep->mark_hidden (); }
00485     void mark_inherited (void) { rep->mark_inherited (); }
00486     void mark_global (void) { rep->mark_global (); }
00487     void mark_persistent (void) { rep->mark_persistent (); }
00488     void mark_forced (void) { rep->mark_forced (); }
00489 
00490     void unmark_local (void) { rep->unmark_local (); }
00491     void unmark_automatic (void) { rep->unmark_automatic (); }
00492     void unmark_formal (void) { rep->unmark_formal (); }
00493     void unmark_hidden (void) { rep->unmark_hidden (); }
00494     void unmark_inherited (void) { rep->unmark_inherited (); }
00495     void unmark_global (void) { rep->unmark_global (); }
00496     void unmark_persistent (void) { rep->unmark_persistent (); }
00497     void unmark_forced (void) { rep->unmark_forced (); }
00498 
00499     void init_persistent (void) { rep->init_persistent (); }
00500 
00501     void erase_persistent (void) { rep->erase_persistent (); }
00502 
00503     unsigned int xstorage_class (void) const { return rep->storage_class; }
00504 
00505     void
00506     dump (std::ostream& os, const std::string& prefix = std::string ()) const
00507     {
00508       rep->dump (os, prefix);
00509     }
00510 
00511   private:
00512 
00513     symbol_record_rep *rep;
00514 
00515     symbol_record (symbol_record_rep *new_rep) : rep (new_rep) { }
00516   };
00517 
00518   class
00519   fcn_info
00520   {
00521   public:
00522 
00523     typedef std::map<std::string, std::string> dispatch_map_type;
00524 
00525     typedef std::map<scope_id, octave_value>::const_iterator scope_val_const_iterator;
00526     typedef std::map<scope_id, octave_value>::iterator scope_val_iterator;
00527 
00528     typedef std::map<std::string, octave_value>::const_iterator str_val_const_iterator;
00529     typedef std::map<std::string, octave_value>::iterator str_val_iterator;
00530 
00531     typedef dispatch_map_type::const_iterator dispatch_map_const_iterator;
00532     typedef dispatch_map_type::iterator dispatch_map_iterator;
00533 
00534   private:
00535 
00536     class
00537     fcn_info_rep
00538     {
00539     public:
00540 
00541       fcn_info_rep (const std::string& nm)
00542         : name (nm), subfunctions (), private_functions (),
00543           class_constructors (), class_methods (), dispatch_map (),
00544           cmdline_function (), autoload_function (), function_on_path (),
00545           built_in_function (), count (1) { }
00546 
00547       octave_value load_private_function (const std::string& dir_name);
00548 
00549       octave_value load_class_constructor (void);
00550 
00551       octave_value load_class_method (const std::string& dispatch_type);
00552 
00553       octave_value find (const octave_value_list& args, bool local_funcs);
00554 
00555       octave_value builtin_find (void);
00556 
00557       octave_value find_method (const std::string& dispatch_type);
00558 
00559       octave_value find_autoload (void);
00560 
00561       octave_value find_user_function (void);
00562 
00563       bool is_user_function_defined (void) const
00564       {
00565         return function_on_path.is_defined ();
00566       }
00567 
00568       octave_value find_function (const octave_value_list& args, bool local_funcs)
00569       {
00570         return find (args, local_funcs);
00571       }
00572 
00573       void lock_subfunction (scope_id scope)
00574       {
00575         scope_val_iterator p = subfunctions.find (scope);
00576 
00577         if (p != subfunctions.end ())
00578           p->second.lock ();
00579       }
00580 
00581       void unlock_subfunction (scope_id scope)
00582       {
00583         scope_val_iterator p = subfunctions.find (scope);
00584 
00585         if (p != subfunctions.end ())
00586           p->second.unlock ();
00587       }
00588 
00589       std::pair<std::string, octave_value>
00590       subfunction_defined_in_scope (scope_id scope) const
00591       {
00592         scope_val_const_iterator p = subfunctions.find (scope);
00593 
00594         return p == subfunctions.end ()
00595           ? std::pair<std::string, octave_value> ()
00596           : std::pair<std::string, octave_value> (name, p->second);
00597       }
00598 
00599       void erase_subfunction (scope_id scope)
00600       {
00601         scope_val_iterator p = subfunctions.find (scope);
00602 
00603         if (p != subfunctions.end ())
00604           subfunctions.erase (p);
00605       }
00606 
00607       void mark_subfunction_in_scope_as_private (scope_id scope,
00608                                                  const std::string& class_name);
00609 
00610       void install_cmdline_function (const octave_value& f)
00611       {
00612         cmdline_function = f;
00613       }
00614 
00615       void install_subfunction (const octave_value& f, scope_id scope)
00616       {
00617         subfunctions[scope] = f;
00618       }
00619 
00620       void install_user_function (const octave_value& f)
00621       {
00622         function_on_path = f;
00623       }
00624 
00625       void install_built_in_function (const octave_value& f)
00626       {
00627         built_in_function = f;
00628       }
00629 
00630       template <class T>
00631       void
00632       clear_unlocked (std::map<T, octave_value>& map)
00633       {
00634         typename std::map<T, octave_value>::iterator p = map.begin ();
00635 
00636         while (p != map.end ())
00637           {
00638             if (p->second.islocked ())
00639               p++;
00640             else
00641               map.erase (p++);
00642           }
00643       }
00644 
00645       void clear_cmdline_function (void)
00646       {
00647         if (! cmdline_function.islocked ())
00648           cmdline_function = octave_value ();
00649       }
00650 
00651       void clear_autoload_function (void)
00652       {
00653         if (! autoload_function.islocked ())
00654           autoload_function = octave_value ();
00655       }
00656 
00657       // FIXME -- should this also clear the cmdline and other "user
00658       // defined" functions?
00659       void clear_user_function (void)
00660       {
00661         if (! function_on_path.islocked ())
00662           {
00663             function_on_path.erase_subfunctions ();
00664 
00665             function_on_path = octave_value ();
00666           }
00667       }
00668 
00669       void clear_mex_function (void)
00670       {
00671         if (function_on_path.is_mex_function ())
00672           clear_user_function ();
00673       }
00674 
00675       void clear (void)
00676       {
00677         clear_unlocked (subfunctions);
00678         clear_unlocked (private_functions);
00679         clear_unlocked (class_constructors);
00680         clear_unlocked (class_methods);
00681         clear_cmdline_function ();
00682         clear_autoload_function ();
00683         clear_user_function ();
00684       }
00685 
00686       void add_dispatch (const std::string& type, const std::string& fname)
00687       {
00688         dispatch_map[type] = fname;
00689       }
00690 
00691       void clear_dispatch (const std::string& type)
00692       {
00693         dispatch_map_iterator p = dispatch_map.find (type);
00694 
00695         if (p != dispatch_map.end ())
00696           dispatch_map.erase (p);
00697       }
00698 
00699       void print_dispatch (std::ostream& os) const;
00700 
00701       std::string help_for_dispatch (void) const;
00702 
00703       dispatch_map_type get_dispatch (void) const { return dispatch_map; }
00704 
00705       void dump (std::ostream& os, const std::string& prefix) const;
00706 
00707       std::string name;
00708 
00709       // Scope id to function object.
00710       std::map<scope_id, octave_value> subfunctions;
00711 
00712       // Directory name to function object.
00713       std::map<std::string, octave_value> private_functions;
00714 
00715       // Class name to function object.
00716       std::map<std::string, octave_value> class_constructors;
00717 
00718       // Dispatch type to function object.
00719       std::map<std::string, octave_value> class_methods;
00720 
00721       // Legacy dispatch map (dispatch type name to function name).
00722       dispatch_map_type dispatch_map;
00723 
00724       octave_value cmdline_function;
00725 
00726       octave_value autoload_function;
00727 
00728       octave_value function_on_path;
00729 
00730       octave_value built_in_function;
00731 
00732       octave_refcount<size_t> count;
00733 
00734     private:
00735 
00736       octave_value xfind (const octave_value_list& args, bool local_funcs);
00737 
00738       octave_value x_builtin_find (void);
00739 
00740       // No copying!
00741 
00742       fcn_info_rep (const fcn_info_rep&);
00743 
00744       fcn_info_rep& operator = (const fcn_info_rep&);
00745     };
00746 
00747   public:
00748 
00749     fcn_info (const std::string& nm = std::string ())
00750       : rep (new fcn_info_rep (nm)) { }
00751 
00752     fcn_info (const fcn_info& fi) : rep (fi.rep)
00753     {
00754       rep->count++;
00755     }
00756 
00757     fcn_info& operator = (const fcn_info& fi)
00758     {
00759       if (this != &fi)
00760         {
00761           if (--rep->count == 0)
00762             delete rep;
00763 
00764           rep = fi.rep;
00765           rep->count++;
00766         }
00767 
00768       return *this;
00769     }
00770 
00771     ~fcn_info (void)
00772     {
00773       if (--rep->count == 0)
00774         delete rep;
00775     }
00776 
00777     octave_value find (const octave_value_list& args = octave_value_list (),
00778                        bool local_funcs = true)
00779     {
00780       return rep->find (args, local_funcs);
00781     }
00782 
00783     octave_value builtin_find (void)
00784     {
00785       return rep->builtin_find ();
00786     }
00787 
00788     octave_value find_method (const std::string& dispatch_type) const
00789     {
00790       return rep->find_method (dispatch_type);
00791     }
00792 
00793     octave_value find_built_in_function (void) const
00794     {
00795       return rep->built_in_function;
00796     }
00797 
00798     octave_value find_cmdline_function (void) const
00799     {
00800       return rep->cmdline_function;
00801     }
00802 
00803     octave_value find_autoload (void)
00804     {
00805       return rep->find_autoload ();
00806     }
00807 
00808     octave_value find_user_function (void)
00809     {
00810       return rep->find_user_function ();
00811     }
00812 
00813     bool is_user_function_defined (void) const
00814     {
00815       return rep->is_user_function_defined ();
00816     }
00817 
00818     octave_value find_function (const octave_value_list& args = octave_value_list (),
00819                                 bool local_funcs = true)
00820     {
00821       return rep->find_function (args, local_funcs);
00822     }
00823 
00824     void lock_subfunction (scope_id scope)
00825     {
00826       rep->lock_subfunction (scope);
00827     }
00828 
00829     void unlock_subfunction (scope_id scope)
00830     {
00831       rep->unlock_subfunction (scope);
00832     }
00833 
00834     std::pair<std::string, octave_value>
00835     subfunction_defined_in_scope (scope_id scope = xcurrent_scope) const
00836     {
00837       return rep->subfunction_defined_in_scope (scope);
00838     }
00839 
00840     void erase_subfunction (scope_id scope)
00841     {
00842       rep->erase_subfunction (scope);
00843     }
00844 
00845     void mark_subfunction_in_scope_as_private (scope_id scope,
00846                                                const std::string& class_name)
00847     {
00848       rep->mark_subfunction_in_scope_as_private (scope, class_name);
00849     }
00850 
00851     void install_cmdline_function (const octave_value& f)
00852     {
00853       rep->install_cmdline_function (f);
00854     }
00855 
00856     void install_subfunction (const octave_value& f, scope_id scope)
00857     {
00858       rep->install_subfunction (f, scope);
00859     }
00860 
00861     void install_user_function (const octave_value& f)
00862     {
00863       rep->install_user_function (f);
00864     }
00865 
00866     void install_built_in_function (const octave_value& f)
00867     {
00868       rep->install_built_in_function (f);
00869     }
00870 
00871     void clear (void) { rep->clear (); }
00872 
00873     void clear_user_function (void) { rep->clear_user_function (); }
00874 
00875     void clear_autoload_function (void) { rep->clear_autoload_function (); }
00876 
00877     void clear_mex_function (void) { rep->clear_mex_function (); }
00878 
00879     void add_dispatch (const std::string& type, const std::string& fname)
00880     {
00881       rep->add_dispatch (type, fname);
00882     }
00883 
00884     void clear_dispatch (const std::string& type)
00885     {
00886       rep->clear_dispatch (type);
00887     }
00888 
00889     void print_dispatch (std::ostream& os) const
00890     {
00891       rep->print_dispatch (os);
00892     }
00893 
00894     std::string help_for_dispatch (void) const { return rep->help_for_dispatch (); }
00895 
00896     dispatch_map_type get_dispatch (void) const
00897     {
00898       return rep->get_dispatch ();
00899     }
00900 
00901     void
00902     dump (std::ostream& os, const std::string& prefix = std::string ()) const
00903     {
00904       rep->dump (os, prefix);
00905     }
00906 
00907   private:
00908 
00909     fcn_info_rep *rep;
00910   };
00911 
00912   static scope_id global_scope (void) { return xglobal_scope; }
00913   static scope_id top_scope (void) { return xtop_scope; }
00914 
00915   static scope_id current_scope (void) { return xcurrent_scope; }
00916 
00917   static context_id current_context (void) { return xcurrent_context; }
00918 
00919   static scope_id alloc_scope (void) { return scope_id_cache::alloc (); }
00920 
00921   static void set_scope (scope_id scope)
00922   {
00923     if (scope == xglobal_scope)
00924       error ("can't set scope to global");
00925     else if (scope != xcurrent_scope)
00926       {
00927         all_instances_iterator p = all_instances.find (scope);
00928 
00929         if (p == all_instances.end ())
00930           {
00931             symbol_table *inst = new symbol_table ();
00932 
00933             if (inst)
00934               all_instances[scope] = instance = inst;
00935           }
00936         else
00937           instance = p->second;
00938 
00939         xcurrent_scope = scope;
00940         xcurrent_context = 0;
00941       }
00942   }
00943 
00944   static void set_scope_and_context (scope_id scope, context_id context)
00945   {
00946     if (scope == xglobal_scope)
00947       error ("can't set scope to global");
00948     else
00949       {
00950         if (scope != xcurrent_scope)
00951           {
00952             all_instances_iterator p = all_instances.find (scope);
00953 
00954             if (p == all_instances.end ())
00955               error ("scope not found!");
00956             else
00957               {
00958                 instance = p->second;
00959 
00960                 xcurrent_scope = scope;
00961 
00962                 xcurrent_context = context;
00963               }
00964           }
00965         else
00966           xcurrent_context = context;
00967       }
00968   }
00969 
00970   static void erase_scope (scope_id scope)
00971   {
00972     assert (scope != xglobal_scope);
00973 
00974     all_instances_iterator p = all_instances.find (scope);
00975 
00976     if (p != all_instances.end ())
00977       {
00978         delete p->second;
00979 
00980         all_instances.erase (p);
00981 
00982         free_scope (scope);
00983       }
00984   }
00985 
00986   static void erase_subfunctions_in_scope (scope_id scope)
00987   {
00988     for (fcn_table_iterator q = fcn_table.begin ();
00989          q != fcn_table.end (); q++)
00990       q->second.erase_subfunction (scope);
00991   }
00992 
00993   static void
00994   mark_subfunctions_in_scope_as_private (scope_id scope,
00995                                          const std::string& class_name)
00996   {
00997     for (fcn_table_iterator q = fcn_table.begin ();
00998          q != fcn_table.end (); q++)
00999       q->second.mark_subfunction_in_scope_as_private (scope, class_name);
01000   }
01001 
01002   static scope_id dup_scope (scope_id scope)
01003   {
01004     scope_id retval = -1;
01005 
01006     symbol_table *inst = get_instance (scope);
01007 
01008     if (inst)
01009       {
01010         scope_id new_scope = alloc_scope ();
01011 
01012         symbol_table *new_symbol_table = new symbol_table ();
01013 
01014         if (new_symbol_table)
01015           {
01016             all_instances[new_scope] = new_symbol_table;
01017 
01018             inst->do_dup_scope (*new_symbol_table);
01019 
01020             retval = new_scope;
01021           }
01022       }
01023 
01024     return retval;
01025   }
01026 
01027   static std::list<scope_id> scopes (void)
01028   {
01029     return scope_id_cache::scopes ();
01030   }
01031 
01032   static symbol_record
01033   find_symbol (const std::string& name, scope_id scope = xcurrent_scope)
01034   {
01035     symbol_table *inst = get_instance (scope);
01036 
01037     return inst ? inst->do_find_symbol (name) : symbol_record ();
01038   }
01039 
01040   static void
01041   inherit (scope_id scope, scope_id donor_scope, context_id donor_context)
01042   {
01043     symbol_table *inst = get_instance (scope);
01044 
01045     if (inst)
01046       {
01047         symbol_table *donor_symbol_table = get_instance (donor_scope);
01048 
01049         if (donor_symbol_table)
01050           inst->do_inherit (*donor_symbol_table, donor_context);
01051       }
01052   }
01053 
01054   static bool at_top_level (void) { return xcurrent_scope == xtop_scope; }
01055 
01056   // Find a value corresponding to the given name in the table.
01057   static octave_value
01058   find (const std::string& name,
01059         const octave_value_list& args = octave_value_list (),
01060         bool skip_variables = false,
01061         bool local_funcs = true);
01062 
01063   static octave_value builtin_find (const std::string& name);
01064 
01065   // Insert a new name in the table.
01066   static symbol_record& insert (const std::string& name)
01067   {
01068     static symbol_record foobar;
01069 
01070     symbol_table *inst = get_instance (xcurrent_scope);
01071 
01072     return inst ? inst->do_insert (name) : foobar;
01073   }
01074 
01075   static void force_variable (const std::string& name,
01076                               scope_id scope = xcurrent_scope,
01077                               context_id context = xcurrent_context)
01078   {
01079     symbol_table *inst = get_instance (scope);
01080 
01081     if (inst)
01082       inst->do_force_variable (name, context);
01083   }
01084 
01085   static octave_value& varref (const std::string& name,
01086                                scope_id scope = xcurrent_scope,
01087                                context_id context = xcurrent_context)
01088   {
01089     static octave_value foobar;
01090 
01091     symbol_table *inst = get_instance (scope);
01092 
01093     return inst ? inst->do_varref (name, context) : foobar;
01094   }
01095 
01096   static octave_value varval (const std::string& name,
01097                               scope_id scope = xcurrent_scope,
01098                               context_id context = xcurrent_context)
01099   {
01100     symbol_table *inst = get_instance (scope);
01101 
01102     return inst ? inst->do_varval (name, context) : octave_value ();
01103   }
01104 
01105   static octave_value&
01106   global_varref (const std::string& name)
01107   {
01108     global_table_iterator p = global_table.find (name);
01109 
01110     return (p == global_table.end ()) ? global_table[name] : p->second;
01111   }
01112 
01113   static octave_value
01114   global_varval (const std::string& name)
01115   {
01116     global_table_const_iterator p = global_table.find (name);
01117 
01118     return (p != global_table.end ()) ? p->second : octave_value ();
01119   }
01120 
01121   static octave_value&
01122   top_level_varref (const std::string& name)
01123   {
01124     return varref (name, top_scope (), 0);
01125   }
01126 
01127   static octave_value
01128   top_level_varval (const std::string& name)
01129   {
01130     return varval (name, top_scope (), 0);
01131   }
01132 
01133   static octave_value& persistent_varref (const std::string& name)
01134   {
01135     static octave_value foobar;
01136 
01137     symbol_table *inst = get_instance (xcurrent_scope);
01138 
01139     return inst ? inst->do_persistent_varref (name) : foobar;
01140   }
01141 
01142   static octave_value persistent_varval (const std::string& name)
01143   {
01144     symbol_table *inst = get_instance (xcurrent_scope);
01145 
01146     return inst ? inst->do_persistent_varval (name) : octave_value ();
01147   }
01148 
01149   static void erase_persistent (const std::string& name)
01150   {
01151     symbol_table *inst = get_instance (xcurrent_scope);
01152 
01153     if (inst)
01154       inst->do_erase_persistent (name);
01155   }
01156 
01157   static bool is_variable (const std::string& name)
01158   {
01159     symbol_table *inst = get_instance (xcurrent_scope);
01160 
01161     return inst ? inst->do_is_variable (name) : false;
01162   }
01163 
01164   static bool
01165   is_built_in_function_name (const std::string& name)
01166   {
01167     octave_value val = find_built_in_function (name);
01168 
01169     return val.is_defined ();
01170   }
01171 
01172   static octave_value
01173   find_method (const std::string& name, const std::string& dispatch_type)
01174   {
01175     fcn_table_const_iterator p = fcn_table.find (name);
01176 
01177     if (p != fcn_table.end ())
01178       return p->second.find_method (dispatch_type);
01179     else
01180       {
01181         fcn_info finfo (name);
01182 
01183         octave_value fcn = finfo.find_method (dispatch_type);
01184 
01185         if (fcn.is_defined ())
01186           fcn_table[name] = finfo;
01187 
01188         return fcn;
01189       }
01190   }
01191 
01192   static octave_value
01193   find_built_in_function (const std::string& name)
01194   {
01195     fcn_table_const_iterator p = fcn_table.find (name);
01196 
01197     return (p != fcn_table.end ())
01198       ? p->second.find_built_in_function () : octave_value ();
01199   }
01200 
01201   static octave_value
01202   find_autoload (const std::string& name)
01203   {
01204     fcn_table_iterator p = fcn_table.find (name);
01205 
01206     return (p != fcn_table.end ())
01207       ? p->second.find_autoload () : octave_value ();
01208   }
01209 
01210   static octave_value
01211   find_function (const std::string& name,
01212                  const octave_value_list& args = octave_value_list (),
01213                  bool local_funcs = true);
01214 
01215   static octave_value find_user_function (const std::string& name)
01216   {
01217     fcn_table_iterator p = fcn_table.find (name);
01218 
01219     return (p != fcn_table.end ())
01220       ? p->second.find_user_function () : octave_value ();
01221   }
01222 
01223   static void install_cmdline_function (const std::string& name,
01224                                         const octave_value& fcn)
01225   {
01226     fcn_table_iterator p = fcn_table.find (name);
01227 
01228     if (p != fcn_table.end ())
01229       {
01230         fcn_info& finfo = p->second;
01231 
01232         finfo.install_cmdline_function (fcn);
01233       }
01234     else
01235       {
01236         fcn_info finfo (name);
01237 
01238         finfo.install_cmdline_function (fcn);
01239 
01240         fcn_table[name] = finfo;
01241       }
01242   }
01243 
01244   static void install_subfunction (const std::string& name,
01245                                    const octave_value& fcn,
01246                                    scope_id scope)
01247   {
01248     fcn_table_iterator p = fcn_table.find (name);
01249 
01250     if (p != fcn_table.end ())
01251       {
01252         fcn_info& finfo = p->second;
01253 
01254         finfo.install_subfunction (fcn, scope);
01255       }
01256     else
01257       {
01258         fcn_info finfo (name);
01259 
01260         finfo.install_subfunction (fcn, scope);
01261 
01262         fcn_table[name] = finfo;
01263       }
01264   }
01265 
01266   static void install_user_function (const std::string& name,
01267                                      const octave_value& fcn)
01268   {
01269     fcn_table_iterator p = fcn_table.find (name);
01270 
01271     if (p != fcn_table.end ())
01272       {
01273         fcn_info& finfo = p->second;
01274 
01275         finfo.install_user_function (fcn);
01276       }
01277     else
01278       {
01279         fcn_info finfo (name);
01280 
01281         finfo.install_user_function (fcn);
01282 
01283         fcn_table[name] = finfo;
01284       }
01285   }
01286 
01287   static void install_built_in_function (const std::string& name,
01288                                          const octave_value& fcn)
01289   {
01290     fcn_table_iterator p = fcn_table.find (name);
01291 
01292     if (p != fcn_table.end ())
01293       {
01294         fcn_info& finfo = p->second;
01295 
01296         finfo.install_built_in_function (fcn);
01297       }
01298     else
01299       {
01300         fcn_info finfo (name);
01301 
01302         finfo.install_built_in_function (fcn);
01303 
01304         fcn_table[name] = finfo;
01305       }
01306   }
01307 
01308   static void clear (const std::string& name)
01309   {
01310     clear_variable (name);
01311   }
01312 
01313   static void clear_all (void)
01314   {
01315     clear_variables ();
01316 
01317     clear_global_pattern ("*");
01318 
01319     clear_functions ();
01320   }
01321 
01322   static void clear_variables (scope_id scope)
01323   {
01324     symbol_table *inst = get_instance (scope);
01325 
01326     if (inst)
01327       inst->do_clear_variables ();
01328   }
01329 
01330   // This is split for unwind_protect.
01331   static void clear_variables (void)
01332   {
01333     clear_variables (xcurrent_scope);
01334   }
01335 
01336   static void clear_objects (scope_id scope = xcurrent_scope)
01337   {
01338     symbol_table *inst = get_instance (scope);
01339 
01340     if (inst)
01341       inst->do_clear_objects ();
01342   }
01343 
01344   static void unmark_forced_variables (scope_id scope = xcurrent_scope)
01345   {
01346     symbol_table *inst = get_instance (scope);
01347 
01348     if (inst)
01349       inst->do_unmark_forced_variables ();
01350   }
01351 
01352   static void clear_functions (void)
01353   {
01354     for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
01355       p->second.clear ();
01356   }
01357 
01358   static void clear_function (const std::string& name)
01359   {
01360     clear_user_function (name);
01361   }
01362 
01363   static void clear_global (const std::string& name)
01364   {
01365     symbol_table *inst = get_instance (xcurrent_scope);
01366 
01367     if (inst)
01368       inst->do_clear_global (name);
01369   }
01370 
01371   static void clear_variable (const std::string& name)
01372   {
01373     symbol_table *inst = get_instance (xcurrent_scope);
01374 
01375     if (inst)
01376       inst->do_clear_variable (name);
01377   }
01378 
01379   static void clear_symbol (const std::string& name)
01380   {
01381     // FIXME -- are we supposed to do both here?
01382 
01383     clear_variable (name);
01384     clear_function (name);
01385   }
01386 
01387   static void clear_function_pattern (const std::string& pat)
01388   {
01389     glob_match pattern (pat);
01390 
01391     for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
01392       {
01393         if (pattern.match (p->first))
01394           p->second.clear_user_function ();
01395       }
01396   }
01397 
01398   static void clear_global_pattern (const std::string& pat)
01399   {
01400     symbol_table *inst = get_instance (xcurrent_scope);
01401 
01402     if (inst)
01403       inst->do_clear_global_pattern (pat);
01404   }
01405 
01406   static void clear_variable_pattern (const std::string& pat)
01407   {
01408     symbol_table *inst = get_instance (xcurrent_scope);
01409 
01410     if (inst)
01411       inst->do_clear_variable_pattern (pat);
01412   }
01413 
01414   static void clear_variable_regexp (const std::string& pat)
01415   {
01416     symbol_table *inst = get_instance (xcurrent_scope);
01417 
01418     if (inst)
01419       inst->do_clear_variable_regexp (pat);
01420   }
01421 
01422   static void clear_symbol_pattern (const std::string& pat)
01423   {
01424     // FIXME -- are we supposed to do both here?
01425 
01426     clear_variable_pattern (pat);
01427     clear_function_pattern (pat);
01428   }
01429 
01430   static void clear_user_function (const std::string& name)
01431   {
01432     fcn_table_iterator p = fcn_table.find (name);
01433 
01434     if (p != fcn_table.end ())
01435       {
01436         fcn_info& finfo = p->second;
01437 
01438         finfo.clear_user_function ();
01439       }
01440     // FIXME -- is this necessary, or even useful?
01441     // else
01442     //   error ("clear: no such function '%s'", name.c_str ());
01443   }
01444 
01445   // This clears oct and mex files, incl. autoloads.
01446   static void clear_dld_function (const std::string& name)
01447   {
01448     fcn_table_iterator p = fcn_table.find (name);
01449 
01450     if (p != fcn_table.end ())
01451       {
01452         fcn_info& finfo = p->second;
01453 
01454         finfo.clear_autoload_function ();
01455         finfo.clear_user_function ();
01456       }
01457   }
01458 
01459   static void clear_mex_functions (void)
01460   {
01461     for (fcn_table_iterator p = fcn_table.begin (); p != fcn_table.end (); p++)
01462       {
01463         fcn_info& finfo = p->second;
01464 
01465         finfo.clear_mex_function ();
01466       }
01467   }
01468 
01469   static bool set_class_relationship (const std::string& sup_class,
01470                                       const std::string& inf_class);
01471 
01472   static bool is_superiorto (const std::string& a, const std::string& b);
01473 
01474   static void alias_built_in_function (const std::string& alias,
01475                                        const std::string& name)
01476   {
01477     octave_value fcn = find_built_in_function (name);
01478 
01479     if (fcn.is_defined ())
01480       {
01481         fcn_info finfo (alias);
01482 
01483         finfo.install_built_in_function (fcn);
01484 
01485         fcn_table[alias] = finfo;
01486       }
01487     else
01488       panic ("alias: '%s' is undefined", name.c_str ());
01489   }
01490 
01491   static void add_dispatch (const std::string& name, const std::string& type,
01492                             const std::string& fname)
01493   {
01494     fcn_table_iterator p = fcn_table.find (name);
01495 
01496     if (p != fcn_table.end ())
01497       {
01498         fcn_info& finfo = p->second;
01499 
01500         finfo.add_dispatch (type, fname);
01501       }
01502     else
01503       {
01504         fcn_info finfo (name);
01505 
01506         finfo.add_dispatch (type, fname);
01507 
01508         fcn_table[name] = finfo;
01509       }
01510   }
01511 
01512   static void clear_dispatch (const std::string& name, const std::string& type)
01513   {
01514     fcn_table_iterator p = fcn_table.find (name);
01515 
01516     if (p != fcn_table.end ())
01517       {
01518         fcn_info& finfo = p->second;
01519 
01520         finfo.clear_dispatch (type);
01521       }
01522   }
01523 
01524   static void print_dispatch (std::ostream& os, const std::string& name)
01525   {
01526     fcn_table_iterator p = fcn_table.find (name);
01527 
01528     if (p != fcn_table.end ())
01529       {
01530         fcn_info& finfo = p->second;
01531 
01532         finfo.print_dispatch (os);
01533       }
01534   }
01535 
01536   static fcn_info::dispatch_map_type get_dispatch (const std::string& name)
01537   {
01538     fcn_info::dispatch_map_type retval;
01539 
01540     fcn_table_iterator p = fcn_table.find (name);
01541 
01542     if (p != fcn_table.end ())
01543       {
01544         fcn_info& finfo = p->second;
01545 
01546         retval = finfo.get_dispatch ();
01547       }
01548 
01549     return retval;
01550   }
01551 
01552   static std::string help_for_dispatch (const std::string& name)
01553   {
01554     std::string retval;
01555 
01556     fcn_table_iterator p = fcn_table.find (name);
01557 
01558     if (p != fcn_table.end ())
01559       {
01560         fcn_info& finfo = p->second;
01561 
01562         retval = finfo.help_for_dispatch ();
01563       }
01564 
01565     return retval;
01566   }
01567 
01568   static void push_context (void)
01569   {
01570     if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope)
01571       error ("invalid call to xymtab::push_context");
01572     else
01573       {
01574         symbol_table *inst = get_instance (xcurrent_scope);
01575 
01576         if (inst)
01577           inst->do_push_context ();
01578       }
01579   }
01580 
01581   static void pop_context (void)
01582   {
01583     if (xcurrent_scope == xglobal_scope || xcurrent_scope == xtop_scope)
01584       error ("invalid call to xymtab::pop_context");
01585     else
01586       {
01587         symbol_table *inst = get_instance (xcurrent_scope);
01588 
01589         if (inst)
01590           inst->do_pop_context ();
01591       }
01592   }
01593 
01594   // For unwind_protect.
01595   static void pop_context (void *) { pop_context (); }
01596 
01597   static void mark_automatic (const std::string& name)
01598   {
01599     symbol_table *inst = get_instance (xcurrent_scope);
01600 
01601     if (inst)
01602       inst->do_mark_automatic (name);
01603   }
01604 
01605   static void mark_hidden (const std::string& name)
01606   {
01607     symbol_table *inst = get_instance (xcurrent_scope);
01608 
01609     if (inst)
01610       inst->do_mark_hidden (name);
01611   }
01612 
01613   static void mark_global (const std::string& name)
01614   {
01615     symbol_table *inst = get_instance (xcurrent_scope);
01616 
01617     if (inst)
01618       inst->do_mark_global (name);
01619   }
01620 
01621   static std::list<symbol_record>
01622   all_variables (scope_id scope = xcurrent_scope,
01623                  context_id context = xcurrent_context,
01624                  bool defined_only = true)
01625   {
01626     symbol_table *inst = get_instance (scope);
01627 
01628     return inst
01629       ? inst->do_all_variables (context, defined_only) : std::list<symbol_record> ();
01630   }
01631 
01632   static std::list<symbol_record> glob (const std::string& pattern)
01633   {
01634     symbol_table *inst = get_instance (xcurrent_scope);
01635 
01636     return inst ? inst->do_glob (pattern) : std::list<symbol_record> ();
01637   }
01638 
01639   static std::list<symbol_record> regexp (const std::string& pattern)
01640   {
01641     symbol_table *inst = get_instance (xcurrent_scope);
01642 
01643     return inst ? inst->do_regexp (pattern) : std::list<symbol_record> ();
01644   }
01645 
01646   static std::list<symbol_record> glob_variables (const std::string& pattern)
01647   {
01648     symbol_table *inst = get_instance (xcurrent_scope);
01649 
01650     return inst ? inst->do_glob (pattern, true) : std::list<symbol_record> ();
01651   }
01652 
01653   static std::list<symbol_record> regexp_variables (const std::string& pattern)
01654   {
01655     symbol_table *inst = get_instance (xcurrent_scope);
01656 
01657     return inst ? inst->do_regexp (pattern, true) : std::list<symbol_record> ();
01658   }
01659 
01660   static std::list<symbol_record>
01661   glob_global_variables (const std::string& pattern)
01662   {
01663     std::list<symbol_record> retval;
01664 
01665     glob_match pat (pattern);
01666 
01667     for (global_table_const_iterator p = global_table.begin ();
01668          p != global_table.end (); p++)
01669       {
01670         // We generate a list of symbol_record objects so that
01671         // the results from glob_variables and glob_global_variables
01672         // may be handled the same way.
01673 
01674         if (pat.match (p->first))
01675           retval.push_back (symbol_record (p->first, p->second,
01676                                            symbol_record::global));
01677       }
01678 
01679     return retval;
01680   }
01681 
01682   static std::list<symbol_record>
01683   regexp_global_variables (const std::string& pattern)
01684   {
01685     std::list<symbol_record> retval;
01686 
01687     ::regexp pat (pattern);
01688 
01689     for (global_table_const_iterator p = global_table.begin ();
01690          p != global_table.end (); p++)
01691       {
01692         // We generate a list of symbol_record objects so that
01693         // the results from regexp_variables and regexp_global_variables
01694         // may be handled the same way.
01695 
01696         if (pat.is_match (p->first))
01697           retval.push_back (symbol_record (p->first, p->second,
01698                                            symbol_record::global));
01699       }
01700 
01701     return retval;
01702   }
01703 
01704   static std::list<symbol_record> glob_variables (const string_vector& patterns)
01705   {
01706     std::list<symbol_record> retval;
01707 
01708     size_t len = patterns.length ();
01709 
01710     for (size_t i = 0; i < len; i++)
01711       {
01712         std::list<symbol_record> tmp = glob_variables (patterns[i]);
01713 
01714         retval.insert (retval.begin (), tmp.begin (), tmp.end ());
01715       }
01716 
01717     return retval;
01718   }
01719 
01720   static std::list<symbol_record> regexp_variables
01721     (const string_vector& patterns)
01722   {
01723     std::list<symbol_record> retval;
01724 
01725     size_t len = patterns.length ();
01726 
01727     for (size_t i = 0; i < len; i++)
01728       {
01729         std::list<symbol_record> tmp = regexp_variables (patterns[i]);
01730 
01731         retval.insert (retval.begin (), tmp.begin (), tmp.end ());
01732       }
01733 
01734     return retval;
01735   }
01736 
01737   static std::list<std::string> user_function_names (void)
01738   {
01739     std::list<std::string> retval;
01740 
01741     for (fcn_table_iterator p = fcn_table.begin ();
01742          p != fcn_table.end (); p++)
01743       {
01744         if (p->second.is_user_function_defined ())
01745           retval.push_back (p->first);
01746       }
01747 
01748     if (! retval.empty ())
01749       retval.sort ();
01750 
01751     return retval;
01752   }
01753 
01754   static std::list<std::string> global_variable_names (void)
01755   {
01756     std::list<std::string> retval;
01757 
01758     for (global_table_const_iterator p = global_table.begin ();
01759          p != global_table.end (); p++)
01760       retval.push_back (p->first);
01761 
01762     retval.sort ();
01763 
01764     return retval;
01765   }
01766 
01767   static std::list<std::string> top_level_variable_names (void)
01768   {
01769     symbol_table *inst = get_instance (xtop_scope);
01770 
01771     return inst ? inst->do_variable_names () : std::list<std::string> ();
01772   }
01773 
01774   static std::list<std::string> variable_names (void)
01775   {
01776     symbol_table *inst = get_instance (xcurrent_scope);
01777 
01778     return inst ? inst->do_variable_names () : std::list<std::string> ();
01779   }
01780 
01781   static std::list<std::string> built_in_function_names (void)
01782   {
01783     std::list<std::string> retval;
01784 
01785     for (fcn_table_const_iterator p = fcn_table.begin ();
01786          p != fcn_table.end (); p++)
01787       {
01788         octave_value fcn = p->second.find_built_in_function ();
01789 
01790         if (fcn.is_defined ())
01791           retval.push_back (p->first);
01792       }
01793 
01794     if (! retval.empty ())
01795       retval.sort ();
01796 
01797     return retval;
01798   }
01799 
01800   static std::list<std::string> cmdline_function_names (void)
01801   {
01802     std::list<std::string> retval;
01803 
01804     for (fcn_table_const_iterator p = fcn_table.begin ();
01805          p != fcn_table.end (); p++)
01806       {
01807         octave_value fcn = p->second.find_cmdline_function ();
01808 
01809         if (fcn.is_defined ())
01810           retval.push_back (p->first);
01811       }
01812 
01813     if (! retval.empty ())
01814       retval.sort ();
01815 
01816     return retval;
01817   }
01818 
01819   static bool is_local_variable (const std::string& name)
01820   {
01821     if (xcurrent_scope == xglobal_scope)
01822       return false;
01823     else
01824       {
01825         symbol_table *inst = get_instance (xcurrent_scope);
01826 
01827         return inst ? inst->do_is_local_variable (name) : false;
01828       }
01829   }
01830 
01831   static bool is_global (const std::string& name)
01832   {
01833     if (xcurrent_scope == xglobal_scope)
01834       return true;
01835     else
01836       {
01837         symbol_table *inst = get_instance (xcurrent_scope);
01838 
01839         return inst ? inst->do_is_global (name) : false;
01840       }
01841   }
01842 
01843   static void dump (std::ostream& os, scope_id scope = xcurrent_scope);
01844 
01845   static void dump_global (std::ostream& os);
01846 
01847   static void dump_functions (std::ostream& os);
01848 
01849   static void cache_name (scope_id scope, const std::string& name)
01850   {
01851     symbol_table *inst = get_instance (scope, false);
01852 
01853     if (inst)
01854       inst->do_cache_name (name);
01855   }
01856 
01857   static void lock_subfunctions (scope_id scope = xcurrent_scope)
01858   {
01859     for (fcn_table_iterator p = fcn_table.begin ();
01860          p != fcn_table.end (); p++)
01861       p->second.lock_subfunction (scope);
01862   }
01863 
01864   static void unlock_subfunctions (scope_id scope = xcurrent_scope)
01865   {
01866     for (fcn_table_iterator p = fcn_table.begin ();
01867          p != fcn_table.end (); p++)
01868       p->second.unlock_subfunction (scope);
01869   }
01870 
01871   static void free_scope (scope_id scope)
01872   {
01873     if (scope == xglobal_scope || scope == xtop_scope)
01874       error ("can't free global or top-level scopes!");
01875     else
01876       symbol_table::scope_id_cache::free (scope);
01877   }
01878 
01879   static void stash_dir_name_for_subfunctions (scope_id scope,
01880                                                const std::string& dir_name);
01881 
01882   static void add_to_parent_map (const std::string& classname,
01883                                  const std::list<std::string>& parent_list)
01884   {
01885     parent_map[classname] = parent_list;
01886   }
01887 
01888   static std::list<std::string>
01889   parent_classes (const std::string& dispatch_type)
01890   {
01891     std::list<std::string> retval;
01892 
01893     const_parent_map_iterator it = parent_map.find (dispatch_type);
01894 
01895     if (it != parent_map.end ())
01896       retval = it->second;
01897 
01898     for (std::list<std::string>::const_iterator lit = retval.begin ();
01899          lit != retval.end (); lit++)
01900       {
01901         // Search for parents of parents and append them to the list.
01902 
01903         // FIXME -- should we worry about a circular inheritance graph?
01904 
01905         std::list<std::string> parents = parent_classes (*lit);
01906 
01907         if (! parents.empty ())
01908           retval.insert (retval.end (), parents.begin (), parents.end ());
01909       }
01910 
01911     return retval;
01912   }
01913 
01914   static octave_user_function *get_curr_fcn (scope_id scope = xcurrent_scope)
01915     {
01916       symbol_table *inst = get_instance (scope);
01917       return inst->curr_fcn;
01918     }
01919 
01920   static void set_curr_fcn (octave_user_function *curr_fcn,
01921                             scope_id scope = xcurrent_scope)
01922     {
01923       assert (scope != xtop_scope && scope != xglobal_scope);
01924       symbol_table *inst = get_instance (scope);
01925       // FIXME: normally, functions should not usurp each other's scope.
01926       // If for any incredible reason this is needed, call
01927       // set_user_function (0, scope) first.
01928       assert (inst->curr_fcn == 0 || curr_fcn == 0);
01929       inst->curr_fcn = curr_fcn;
01930     }
01931 
01932   static void cleanup (void);
01933 
01934 private:
01935 
01936   // No copying!
01937 
01938   symbol_table (const symbol_table&);
01939 
01940   symbol_table& operator = (const symbol_table&);
01941 
01942   typedef std::map<std::string, symbol_record>::const_iterator table_const_iterator;
01943   typedef std::map<std::string, symbol_record>::iterator table_iterator;
01944 
01945   typedef std::map<std::string, octave_value>::const_iterator global_table_const_iterator;
01946   typedef std::map<std::string, octave_value>::iterator global_table_iterator;
01947 
01948   typedef std::map<std::string, octave_value>::const_iterator persistent_table_const_iterator;
01949   typedef std::map<std::string, octave_value>::iterator persistent_table_iterator;
01950 
01951   typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator;
01952   typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator;
01953 
01954   typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator;
01955   typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator;
01956 
01957   // Name for this table (usually the file name of the function
01958   // corresponding to the scope);
01959   std::string table_name;
01960 
01961   // Map from symbol names to symbol info.
01962   std::map<std::string, symbol_record> table;
01963 
01964   // The associated user code (may be null).
01965   octave_user_function *curr_fcn;
01966 
01967   // Map from names of global variables to values.
01968   static std::map<std::string, octave_value> global_table;
01969 
01970   // Map from names of persistent variables to values.
01971   std::map<std::string, octave_value> persistent_table;
01972 
01973   // Pointer to symbol table for current scope (variables only).
01974   static symbol_table *instance;
01975 
01976   // Map from scope id to symbol table instances.
01977   static std::map<scope_id, symbol_table*> all_instances;
01978 
01979   // Map from function names to function info (subfunctions, private
01980   // functions, class constructors, class methods, etc.)
01981   static std::map<std::string, fcn_info> fcn_table;
01982 
01983   // Mape from class names to set of classes that have lower
01984   // precedence.
01985   static std::map<std::string, std::set<std::string> > class_precedence_table;
01986 
01987   typedef std::map<std::string, std::set<std::string> >::const_iterator class_precedence_table_const_iterator;
01988   typedef std::map<std::string, std::set<std::string> >::iterator class_precedence_table_iterator;
01989 
01990   // Map from class names to parent class names.
01991   static std::map<std::string, std::list<std::string> > parent_map;
01992 
01993   typedef std::map<std::string, std::list<std::string> >::const_iterator const_parent_map_iterator;
01994   typedef std::map<std::string, std::list<std::string> >::iterator parent_map_iterator;
01995 
01996   static const scope_id xglobal_scope;
01997   static const scope_id xtop_scope;
01998 
01999   static scope_id xcurrent_scope;
02000 
02001   static context_id xcurrent_context;
02002 
02003   symbol_table (void)
02004     : table_name (), table (), curr_fcn (0), persistent_table () { }
02005 
02006   ~symbol_table (void) { }
02007 
02008   static symbol_table *get_instance (scope_id scope, bool create = true)
02009   {
02010     symbol_table *retval = 0;
02011 
02012     bool ok = true;
02013 
02014     if (scope != xglobal_scope)
02015       {
02016         if (scope == xcurrent_scope)
02017           {
02018             if (! instance && create)
02019               {
02020                 symbol_table *inst = new symbol_table ();
02021 
02022                 if (inst)
02023                   {
02024                     all_instances[scope] = instance = inst;
02025 
02026                     if (scope == xtop_scope)
02027                       instance->do_cache_name ("top-level");
02028                   }
02029               }
02030 
02031             if (! instance)
02032               ok = false;
02033 
02034             retval = instance;
02035           }
02036         else
02037           {
02038             all_instances_iterator p = all_instances.find (scope);
02039 
02040             if (p == all_instances.end ())
02041               {
02042                 if (create)
02043                   {
02044                     retval = new symbol_table ();
02045 
02046                     if (retval)
02047                       all_instances[scope] = retval;
02048                     else
02049                       ok = false;
02050                   }
02051                 else
02052                   ok = false;
02053               }
02054             else
02055               retval = p->second;
02056           }
02057       }
02058 
02059     if (! ok)
02060       error ("unable to %s symbol_table object for scope %d!",
02061              create ? "create" : "find", scope);
02062 
02063     return retval;
02064   }
02065 
02066   void insert_symbol_record (const symbol_record& sr)
02067   {
02068     table[sr.name ()] = sr;
02069   }
02070 
02071   void
02072   do_dup_scope (symbol_table& new_symbol_table) const
02073   {
02074     for (table_const_iterator p = table.begin (); p != table.end (); p++)
02075       new_symbol_table.insert_symbol_record (p->second.dup ());
02076   }
02077 
02078   symbol_record do_find_symbol (const std::string& name)
02079   {
02080     table_iterator p = table.find (name);
02081 
02082     if (p == table.end ())
02083       return do_insert (name);
02084     else
02085       return p->second;
02086   }
02087 
02088   void do_inherit (symbol_table& donor_table, context_id donor_context)
02089   {
02090     for (table_iterator p = table.begin (); p != table.end (); p++)
02091       {
02092         symbol_record& sr = p->second;
02093 
02094         if (! (sr.is_automatic () || sr.is_formal ()))
02095           {
02096             std::string nm = sr.name ();
02097 
02098             if (nm != "__retval__")
02099               {
02100                 octave_value val = donor_table.do_varval (nm, donor_context);
02101 
02102                 if (val.is_defined ())
02103                   {
02104                     sr.varref (0) = val;
02105 
02106                     sr.mark_inherited ();
02107                   }
02108               }
02109           }
02110       }
02111   }
02112 
02113   static fcn_info *get_fcn_info (const std::string& name)
02114     {
02115       fcn_table_iterator p = fcn_table.find (name);
02116       return p != fcn_table.end () ? &p->second : 0;
02117     }
02118 
02119   octave_value
02120   do_find (const std::string& name, const octave_value_list& args,
02121            bool skip_variables, bool local_funcs);
02122 
02123   octave_value do_builtin_find (const std::string& name);
02124 
02125   symbol_record& do_insert (const std::string& name)
02126   {
02127     table_iterator p = table.find (name);
02128 
02129     return p == table.end ()
02130       ? (table[name] = symbol_record (name)) : p->second;
02131   }
02132 
02133   void do_force_variable (const std::string& name, context_id context)
02134   {
02135     table_iterator p = table.find (name);
02136 
02137     if (p == table.end ())
02138       {
02139         symbol_record& sr = do_insert (name);
02140 
02141         sr.force_variable (context);
02142       }
02143     else
02144       p->second.force_variable (context);
02145   }
02146 
02147   octave_value& do_varref (const std::string& name, context_id context)
02148   {
02149     table_iterator p = table.find (name);
02150 
02151     if (p == table.end ())
02152       {
02153         symbol_record& sr = do_insert (name);
02154 
02155         return sr.varref (context);
02156       }
02157     else
02158       return p->second.varref (context);
02159   }
02160 
02161   octave_value do_varval (const std::string& name, context_id context) const
02162   {
02163     table_const_iterator p = table.find (name);
02164 
02165     return (p != table.end ()) ? p->second.varval (context) : octave_value ();
02166   }
02167 
02168   octave_value& do_persistent_varref (const std::string& name)
02169   {
02170     persistent_table_iterator p = persistent_table.find (name);
02171 
02172     return (p == persistent_table.end ())
02173       ? persistent_table[name] : p->second;
02174   }
02175 
02176   octave_value do_persistent_varval (const std::string& name)
02177   {
02178     persistent_table_const_iterator p = persistent_table.find (name);
02179 
02180     return (p != persistent_table.end ()) ? p->second : octave_value ();
02181   }
02182 
02183   void do_erase_persistent (const std::string& name)
02184   {
02185     persistent_table_iterator p = persistent_table.find (name);
02186 
02187     if (p != persistent_table.end ())
02188       persistent_table.erase (p);
02189   }
02190 
02191   bool do_is_variable (const std::string& name) const
02192   {
02193     bool retval = false;
02194 
02195     table_const_iterator p = table.find (name);
02196 
02197     if (p != table.end ())
02198       {
02199         const symbol_record& sr = p->second;
02200 
02201         retval = sr.is_variable ();
02202       }
02203 
02204     return retval;
02205   }
02206 
02207   void do_push_context (void)
02208   {
02209     for (table_iterator p = table.begin (); p != table.end (); p++)
02210       p->second.push_context ();
02211   }
02212 
02213   void do_pop_context (void)
02214   {
02215     for (table_iterator p = table.begin (); p != table.end (); )
02216       {
02217         if (p->second.pop_context () == 0)
02218           table.erase (p++);
02219         else
02220           p++;
02221       }
02222   }
02223 
02224   void do_clear_variables (void)
02225   {
02226     for (table_iterator p = table.begin (); p != table.end (); p++)
02227       p->second.clear ();
02228   }
02229 
02230   void do_clear_objects (void)
02231   {
02232     for (table_iterator p = table.begin (); p != table.end (); p++)
02233       {
02234         symbol_record& sr = p->second;
02235         octave_value& val = sr.varref ();
02236         if (val.is_object())
02237           p->second.clear ();
02238       }
02239   }
02240 
02241  void do_unmark_forced_variables (void)
02242   {
02243     for (table_iterator p = table.begin (); p != table.end (); p++)
02244       p->second.unmark_forced ();
02245   }
02246 
02247   void do_clear_global (const std::string& name)
02248   {
02249     table_iterator p = table.find (name);
02250 
02251     if (p != table.end ())
02252       {
02253         symbol_record& sr = p->second;
02254 
02255         if (sr.is_global ())
02256           sr.unmark_global ();
02257       }
02258 
02259     global_table_iterator q = global_table.find (name);
02260 
02261     if (q != global_table.end ())
02262       global_table.erase (q);
02263 
02264   }
02265 
02266   void do_clear_variable (const std::string& name)
02267   {
02268     table_iterator p = table.find (name);
02269 
02270     if (p != table.end ())
02271       p->second.clear ();
02272   }
02273 
02274   void do_clear_global_pattern (const std::string& pat)
02275   {
02276     glob_match pattern (pat);
02277 
02278     for (table_iterator p = table.begin (); p != table.end (); p++)
02279       {
02280         symbol_record& sr = p->second;
02281 
02282         if (sr.is_global () && pattern.match (sr.name ()))
02283           sr.unmark_global ();
02284       }
02285 
02286 
02287     for (global_table_iterator q = global_table.begin ();
02288          q != global_table.end ();)
02289       {
02290         if (pattern.match (q->first))
02291           global_table.erase (q++); //Gotta be careful to not
02292                                     //invalidate iterators
02293         else
02294           q++;
02295       }
02296 
02297 
02298   }
02299 
02300   void do_clear_variable_pattern (const std::string& pat)
02301   {
02302     glob_match pattern (pat);
02303 
02304     for (table_iterator p = table.begin (); p != table.end (); p++)
02305       {
02306         symbol_record& sr = p->second;
02307 
02308         if (sr.is_defined () || sr.is_global ())
02309           {
02310             if (pattern.match (sr.name ()))
02311               sr.clear ();
02312           }
02313       }
02314   }
02315 
02316   void do_clear_variable_regexp (const std::string& pat)
02317   {
02318     ::regexp pattern (pat);
02319 
02320     for (table_iterator p = table.begin (); p != table.end (); p++)
02321       {
02322         symbol_record& sr = p->second;
02323 
02324         if (sr.is_defined () || sr.is_global ())
02325           {
02326             if (pattern.is_match (sr.name ()))
02327               sr.clear ();
02328           }
02329       }
02330   }
02331 
02332   void do_mark_automatic (const std::string& name)
02333   {
02334     do_insert (name).mark_automatic ();
02335   }
02336 
02337   void do_mark_hidden (const std::string& name)
02338   {
02339     do_insert (name).mark_hidden ();
02340   }
02341 
02342   void do_mark_global (const std::string& name)
02343   {
02344     do_insert (name).mark_global ();
02345   }
02346 
02347   std::list<symbol_record>
02348   do_all_variables (context_id context, bool defined_only) const
02349   {
02350     std::list<symbol_record> retval;
02351 
02352     for (table_const_iterator p = table.begin (); p != table.end (); p++)
02353       {
02354         const symbol_record& sr = p->second;
02355 
02356         if (defined_only && ! sr.is_defined (context))
02357           continue;
02358 
02359         retval.push_back (sr);
02360       }
02361 
02362     return retval;
02363   }
02364 
02365   std::list<symbol_record> do_glob (const std::string& pattern,
02366                                     bool vars_only = false) const
02367   {
02368     std::list<symbol_record> retval;
02369 
02370     glob_match pat (pattern);
02371 
02372     for (table_const_iterator p = table.begin (); p != table.end (); p++)
02373       {
02374         if (pat.match (p->first))
02375           {
02376             const symbol_record& sr = p->second;
02377 
02378             if (vars_only && ! sr.is_variable ())
02379               continue;
02380 
02381             retval.push_back (sr);
02382           }
02383       }
02384 
02385     return retval;
02386   }
02387 
02388   std::list<symbol_record> do_regexp (const std::string& pattern,
02389                                       bool vars_only = false) const
02390   {
02391     std::list<symbol_record> retval;
02392 
02393     ::regexp pat (pattern);
02394 
02395     for (table_const_iterator p = table.begin (); p != table.end (); p++)
02396       {
02397         if (pat.is_match (p->first))
02398           {
02399             const symbol_record& sr = p->second;
02400 
02401             if (vars_only && ! sr.is_variable ())
02402               continue;
02403 
02404             retval.push_back (sr);
02405           }
02406       }
02407 
02408     return retval;
02409   }
02410 
02411   std::list<std::string> do_variable_names (void)
02412   {
02413     std::list<std::string> retval;
02414 
02415     for (table_const_iterator p = table.begin (); p != table.end (); p++)
02416       {
02417         if (p->second.is_variable ())
02418           retval.push_back (p->first);
02419       }
02420 
02421     retval.sort ();
02422 
02423     return retval;
02424   }
02425 
02426   static std::map<std::string, octave_value>
02427   subfunctions_defined_in_scope (scope_id scope = xcurrent_scope)
02428   {
02429     std::map<std::string, octave_value> retval;
02430 
02431     for (fcn_table_const_iterator p = fcn_table.begin ();
02432          p != fcn_table.end (); p++)
02433       {
02434         std::pair<std::string, octave_value> tmp
02435           = p->second.subfunction_defined_in_scope (scope);
02436 
02437         std::string nm = tmp.first;
02438 
02439         if (! nm.empty ())
02440           retval[nm] = tmp.second;
02441       }
02442 
02443     return retval;
02444   }
02445 
02446   bool do_is_local_variable (const std::string& name) const
02447   {
02448     table_const_iterator p = table.find (name);
02449 
02450     return (p != table.end ()
02451             && ! p->second.is_global ()
02452             && p->second.is_defined ());
02453   }
02454 
02455   bool do_is_global (const std::string& name) const
02456   {
02457     table_const_iterator p = table.find (name);
02458 
02459     return p != table.end () && p->second.is_global ();
02460   }
02461 
02462   void do_dump (std::ostream& os);
02463 
02464   void do_cache_name (const std::string& name) { table_name = name; }
02465 };
02466 
02467 extern bool out_of_date_check (octave_value& function,
02468                                const std::string& dispatch_type = std::string (),
02469                                bool check_relative = true);
02470 
02471 extern OCTINTERP_API std::string
02472 get_dispatch_type (const octave_value_list& args);
02473 extern OCTINTERP_API std::string
02474 get_dispatch_type (const octave_value_list& args, builtin_type_t& builtin_type);
02475 
02476 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines