changeset 7761:5adeea5de26c

symbol table reporting functions
author John W. Eaton <jwe@octave.org>
date Tue, 06 May 2008 05:51:17 -0400
parents f5268d7045d7
children 9c24ca8761f7
files src/ChangeLog src/ls-mat5.cc src/ov-base.cc src/ov-base.h src/ov-builtin.h src/ov-fcn-handle.cc src/ov-fcn-handle.h src/ov-fcn.h src/ov-mex-fcn.h src/ov-usr-fcn.cc src/ov-usr-fcn.h src/ov.cc src/ov.h src/parse.y src/pt-id.cc src/symtab.cc src/symtab.h src/variables.cc
diffstat 18 files changed, 778 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue May 06 03:23:12 2008 -0400
+++ b/src/ChangeLog	Tue May 06 05:51:17 2008 -0400
@@ -1,5 +1,74 @@
 2008-05-06  John W. Eaton  <jwe@octave.org>
 
+	* symtab.h (symbol_table::scope_id_cache): New class.  Use it to
+	replace scope_ids_in_use and scope_ids_free_list.
+	(symbol_table::erase_scope): Call free_scope.
+	(symbol_table::free_scope): Call scope_id_cache::free.
+
+	* ov-fcn.h (octave_function::lock_subfunctions,
+	octave_function::unlock_subfunctions): New virtual functions.
+	(octave_function::lock_subfunctions): Call lock_subfunctions here.
+	(octave_function::unlock_subfunctions): Call unlock_subfunctions here.
+	* ov-usr-fcn.h (octave_user_function::lock_subfunctions,
+	octave_user_function::unlock_subfunctions): New functions.
+
+	* symtab.h (symbol_table::lock_subfunctions,
+	symbol_table::lock_subfunctions,
+	symbol_table::fcn_info::lock_subfunction,
+	symbol_table::fcn_info::unlock_subfunction,
+	symbol_table::fcn_info::fcn_info_rep::lock_subfunction, 
+	symbol_table::fcn_info::fcn_info_rep::unlock_subfunction):	
+	New functions.
+
+	* symtab.h (symbol_table::set_scope, symbol_table::get_instance):
+	Don't set instance unless allocation succeeds.
+	(symbol_table::print_scope, symbol_table::do_print_scope): Delete.
+	(symbol_table::free_scope): Avoid using invalid iterator.
+	(symbol_table::erase_scope): Call free_scope here.
+
+	* ov-fcn-handle.cc (octave_fcn_handle::load_ascii,
+	octave_fcn_handle::load_binary, octave_fcn_handle::load_hdf5):
+	Cache anonymous name here.
+	(octave_fcn_handle::octave_fcn_handle): Move here from
+	ov-fcn-handle.h.  Cache name if function is user-defined.
+
+	* pt-id.cc (tree_identifier::dup): Avoid shadow warning.
+
+	* symtab.h (symbol_table::cache_name, symbol_table::do_cache_name):
+	New functions.
+	(symbol_table::get_instance): Cache top-level name here.
+	* parse.y (finish_function): Call symbol_table::cache_name here.
+
+	* symtab.cc (F__dump_symtab_info__): New function.
+	
+	* symtab.cc (symbol_table::dump, symbol_table::dump_global,
+	symbol_table::dump_functions, symbol_table::do_dump,
+	symbol_table::symbol_record::symbol_record_rep::dump,
+	symobl_table::fcn_info::fcn_info_rep::dump): New functions.
+	* symtab.h: Provide decls.
+	(symtab::scopes, symbol_table::symbol_record::dump,
+	symbol_table::fcn_info::dump): New functions.
+	(symtab::get_instance): New arg, create; if false throw error if
+	instance for given scope is not found.
+
+	* ov-base.cc (octave_base_value::dump): New virtual function.
+	* ov-base.h: Proivde decl.
+	* ov.h (octave_value::dump): New function.
+
+	* ov.h, ov.c (octave_value::function_value): New const version.
+	* ov-base.h, ov-base.cc (octave_base_value::function_value): Likewise.
+	* ov-builtin.h (octave_builtin::function_value): Likewise.
+	* ov-fcn-handle.h (octave_fcn_handle::function_value): Likewise.
+	* ov-mex-fcn.h (octave_mex_function::function_value): Likewise.
+	* ov-usr-fcn.h (octave_user_script::function_value,
+	octave_user_function): Likewise.
+	
+	* symtab.h, symtab.cc: Use consistent naming scheme for iterator
+	typedefs.  Change all uses.
+
+	* variables.cc (F__print_symtab_info__, F__print_symbol_info__):
+	Delete.
+
 	* ov-cell.cc (Fstruct2cell): Handle structure arrays properly.
 
 2008-05-05  David Bateman  <dbateman@free.fr>
--- a/src/ls-mat5.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/ls-mat5.cc	Tue May 06 05:51:17 2008 -0400
@@ -892,8 +892,9 @@
 	      {
 		octave_fcn_handle *fh = 
 		  anon_fcn_handle.fcn_handle_value ();
+
 		if (fh)
-		  tc = new octave_fcn_handle (fh->fcn_val(), "@<anonymous>");
+		  tc = new octave_fcn_handle (fh->fcn_val (), "@<anonymous>");
 		else
 		  {
 		    error ("load: failed to load anonymous function handle");
--- a/src/ov-base.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-base.cc	Tue May 06 05:51:17 2008 -0400
@@ -771,6 +771,17 @@
   return retval;
 }
 
+const octave_function *
+octave_base_value::function_value (bool silent) const
+{
+  const octave_function *retval = 0;
+
+  if (! silent)
+    gripe_wrong_type_arg ("octave_base_value::function_value()",
+			  type_name ());
+  return retval;
+}
+
 octave_user_function *
 octave_base_value::user_function_value (bool silent)
 {
@@ -1011,6 +1022,16 @@
   gripe_wrong_type_arg ("octave_base_value::unlock ()", type_name ());
 }
 
+void
+octave_base_value::dump (std::ostream& os) const
+{
+  dim_vector dv = this->dims ();
+
+  os << "class: " << this->class_name ()
+     << " type: " << this->type_name ()
+     << " dims: " << dv.str ();
+}
+
 static void
 gripe_indexed_assignment (const std::string& tn1, const std::string& tn2)
 {
--- a/src/ov-base.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-base.h	Tue May 06 05:51:17 2008 -0400
@@ -401,6 +401,8 @@
 
   virtual octave_function *function_value (bool silent = false);
 
+  virtual const octave_function *function_value (bool silent = false) const;
+
   virtual octave_user_function *user_function_value (bool silent = false);
 
   virtual octave_user_script *user_script_value (bool silent = false);
@@ -480,6 +482,8 @@
 
   virtual bool islocked (void) const { return false; }
 
+  virtual void dump (std::ostream& os) const;
+
   virtual octave_value abs (void) const;
   virtual octave_value acos (void) const;
   virtual octave_value acosh (void) const;
--- a/src/ov-builtin.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-builtin.h	Tue May 06 05:51:17 2008 -0400
@@ -63,6 +63,8 @@
 
   octave_function *function_value (bool = false) { return this; }
 
+  const octave_function *function_value (bool = false) const { return this; }
+
   bool is_builtin_function (void) const { return true; }
 
   octave_value_list
--- a/src/ov-fcn-handle.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-fcn-handle.cc	Tue May 06 05:51:17 2008 -0400
@@ -65,6 +65,16 @@
 				     "function handle",
 				     "function_handle");
 
+octave_fcn_handle::octave_fcn_handle (const octave_value& f,
+				      const std::string& n)
+  : warn_reload (true), fcn (f), nm (n)
+{
+  octave_user_function *uf = fcn.user_function_value (true);
+
+  if (uf)
+    symbol_table::cache_name (uf->scope (), nm);
+}
+
 octave_value_list
 octave_fcn_handle::subsref (const std::string& type,
 			    const std::list<octave_value_list>& idx,
@@ -358,8 +368,16 @@
 	    {
 	      octave_fcn_handle *fh = 
 		anon_fcn_handle.fcn_handle_value ();
+
 	      if (fh)
-		fcn = fh->fcn;
+		{
+		  fcn = fh->fcn;
+
+		  octave_user_function *uf = fcn.user_function_value (true);
+
+		  if (uf)
+		    symbol_table::cache_name (uf->scope (), nm);
+		}
 	      else
 		success = false;
 	    }
@@ -519,8 +537,16 @@
 	  if (parse_status == 0)
 	    {
 	      octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
+
 	      if (fh)
-		fcn = fh->fcn;
+		{
+		  fcn = fh->fcn;
+
+		  octave_user_function *uf = fcn.user_function_value (true);
+
+		  if (uf)
+		    symbol_table::cache_name (uf->scope (), nm);
+		}
 	      else
 		success = false;
 	    }
@@ -968,8 +994,16 @@
 	  if (parse_status == 0)
 	    {
 	      octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
+
 	      if (fh)
-		fcn = fh->fcn;
+		{
+		  fcn = fh->fcn;
+
+		  octave_user_function *uf = fcn.user_function_value (true);
+
+		  if (uf)
+		    symbol_table::cache_name (uf->scope (), nm);
+		}
 	      else
 		success = false;
 	    }
--- a/src/ov-fcn-handle.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-fcn-handle.h	Tue May 06 05:51:17 2008 -0400
@@ -45,8 +45,7 @@
   octave_fcn_handle (const std::string& n)
     : warn_reload (true), fcn (), nm (n) { }
 
-  octave_fcn_handle (const octave_value& f,  const std::string& n)
-    : warn_reload (true), fcn (f), nm (n) { }
+  octave_fcn_handle (const octave_value& f,  const std::string& n);
 
   octave_fcn_handle (const octave_fcn_handle& fh)
     : octave_base_value (fh), warn_reload (fh.warn_reload),
@@ -77,6 +76,9 @@
   octave_function *function_value (bool = false)
     { return fcn.function_value (); }
 
+  const octave_function *function_value (bool = false) const
+    { return fcn.function_value (); }
+
   octave_user_function *user_function_value (bool = false)
     { return fcn.user_function_value (); }
 
--- a/src/ov-fcn.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-fcn.h	Tue May 06 05:51:17 2008 -0400
@@ -88,12 +88,24 @@
 
   void stash_dir_name (const std::string& dir) { my_dir_name = dir; }
 
-  void lock (void) { locked = true; }
+  void lock (void)
+  {
+    this->lock_subfunctions ();
+    locked = true;
+  }
 
-  void unlock (void) { locked = false; }
+  void unlock (void)
+  {
+    this->unlock_subfunctions ();
+    locked = false;
+  }
 
   bool islocked (void) const { return locked; }
 
+  virtual void lock_subfunctions (void) { }
+
+  virtual void unlock_subfunctions (void) { }
+
   void mark_relative (void) { relative = true; }
 
   bool is_relative (void) const { return relative; }
--- a/src/ov-mex-fcn.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-mex-fcn.h	Tue May 06 05:51:17 2008 -0400
@@ -63,6 +63,8 @@
 
   octave_function *function_value (bool = false) { return this; }
 
+  const octave_function *function_value (bool = false) const { return this; }
+
   void mark_fcn_file_up_to_date (const octave_time& t) { t_checked = t; }
 
   std::string fcn_file_name (void) const;
--- a/src/ov-usr-fcn.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-usr-fcn.cc	Tue May 06 05:51:17 2008 -0400
@@ -272,6 +272,18 @@
   return (ret_list && ret_list->takes_varargs ());
 }
 
+void
+octave_user_function::lock_subfunctions (void)
+{
+  symbol_table::lock_subfunctions (local_scope);
+}
+
+void
+octave_user_function::unlock_subfunctions (void)
+{
+  symbol_table::unlock_subfunctions (local_scope);
+}
+
 octave_value_list
 octave_user_function::octave_all_va_args (void)
 {
--- a/src/ov-usr-fcn.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov-usr-fcn.h	Tue May 06 05:51:17 2008 -0400
@@ -91,6 +91,8 @@
 
   octave_function *function_value (bool = false) { return this; }
 
+  const octave_function *function_value (bool = false) const { return this; }
+
   octave_user_script *user_script_value (bool = false) { return this; }
 
   octave_user_code *user_code_value (bool = false) { return this; }
@@ -181,6 +183,8 @@
 
   octave_function *function_value (bool = false) { return this; }
 
+  const octave_function *function_value (bool = false) const { return this; }
+
   octave_user_function *user_function_value (bool = false) { return this; }
 
   octave_user_code *user_code_value (bool = false) { return this; }
@@ -225,6 +229,10 @@
 
   bool takes_var_return (void) const;
 
+  void lock_subfunctions (void);
+
+  void unlock_subfunctions (void);
+
   octave_value_list octave_all_va_args (void);
 
   void stash_function_name (const std::string& s) { my_name = s; }
--- a/src/ov.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov.cc	Tue May 06 05:51:17 2008 -0400
@@ -1145,6 +1145,12 @@
   return rep->function_value (silent);
 }
 
+const octave_function *
+octave_value::function_value (bool silent) const
+{
+  return rep->function_value (silent);
+}
+
 octave_user_function *
 octave_value::user_function_value (bool silent)
 {
--- a/src/ov.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/ov.h	Tue May 06 05:51:17 2008 -0400
@@ -740,6 +740,8 @@
 
   octave_function *function_value (bool silent = false);
 
+  const octave_function *function_value (bool silent = false) const;
+
   octave_user_function *user_function_value (bool silent = false);
 
   octave_user_script *user_script_value (bool silent = false);
@@ -890,6 +892,8 @@
 
   bool islocked (void) const { return rep->islocked (); }
 
+  void dump (std::ostream& os) const { rep->dump (os); }
+
 #define MAPPER_FORWARD(F) \
   octave_value F (void) const { return rep->F (); }
 
--- a/src/parse.y	Tue May 06 03:23:12 2008 -0400
+++ b/src/parse.y	Tue May 06 05:51:17 2008 -0400
@@ -2548,6 +2548,15 @@
 
   if (fcn)
     {
+      std::string nm = fcn->name ();
+      std::string file = fcn->fcn_file_name ();
+
+      std::string tmp = nm;
+      if (! file.empty ())
+	tmp += ": " + file;
+
+      symbol_table::cache_name (fcn->scope (), tmp);
+
       if (lc)
 	fcn->stash_leading_comment (lc);
 
@@ -2555,8 +2564,6 @@
 
       if (lexer_flags.parsing_nested_function)
 	{
-	  std::string nm = fcn->name ();
-
 	  fcn->mark_as_nested_function ();
 
 	  symbol_table::install_subfunction (nm, octave_value (fcn));
--- a/src/pt-id.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/pt-id.cc	Tue May 06 05:51:17 2008 -0400
@@ -123,14 +123,14 @@
 }
 
 tree_identifier *
-tree_identifier::dup (symbol_table::scope_id scope)
+tree_identifier::dup (symbol_table::scope_id sc)
 {
   // The new tree_identifier object contains a symbol_record
   // entry from the duplicated scope.
 
   // FIXME -- is this the best way?
   symbol_table::symbol_record new_sym
-    = symbol_table::find_symbol (xsym().name (), scope);
+    = symbol_table::find_symbol (xsym().name (), sc);
 
   tree_identifier *new_id
     = new tree_identifier (new_sym, line (), column ());
--- a/src/symtab.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/symtab.cc	Tue May 06 05:51:17 2008 -0400
@@ -45,6 +45,8 @@
 
 symbol_table *symbol_table::instance = 0;
 
+symbol_table::scope_id_cache *symbol_table::scope_id_cache::instance = 0;
+
 std::map<symbol_table::scope_id, symbol_table*> symbol_table::all_instances;
 
 std::map<std::string, octave_value> symbol_table::global_table;
@@ -61,16 +63,37 @@
 
 std::deque<symbol_table::scope_id> symbol_table::scope_stack;
 
-symbol_table::scope_id symbol_table::next_available_scope = 2;
-std::set<symbol_table::scope_id> symbol_table::scope_ids_in_use;
-std::set<symbol_table::scope_id> symbol_table::scope_ids_free_list;
-
 symbol_table::context_id symbol_table::xcurrent_context = 0;
 
 // Should Octave always check to see if function files have changed
 // since they were last compiled?
 static int Vignore_function_time_stamp = 1;
 
+void
+symbol_table::symbol_record::symbol_record_rep::dump
+  (std::ostream& os, const std::string& prefix) const
+{
+  octave_value val = varval ();
+
+  os << prefix << name;
+
+  if (val.is_defined ())
+    {
+      os << " ["
+	 << (is_local () ? "l" : "")
+	 << (is_automatic () ? "a" : "")
+	 << (is_formal () ? "f" : "")
+	 << (is_hidden () ? "h" : "")
+	 << (is_inherited () ? "i" : "")
+	 << (is_global () ? "g" : "")
+	 << (is_persistent () ? "p" : "")
+	 << "] ";
+      val.dump (os);
+    }
+
+  os << "\n";
+}
+
 octave_value
 symbol_table::symbol_record::find (tree_argument_list *args,
 				   const string_vector& arg_names,
@@ -309,7 +332,7 @@
     {
       os << "Overloaded function " << name << ":\n\n";
 
-      for (const_dispatch_map_iterator p = dispatch_map.begin ();
+      for (dispatch_map_const_iterator p = dispatch_map.begin ();
 	   p != dispatch_map.end (); p++)
 	os << "  " << name << " (" << p->first << ", ...) -> " 
 	   << p->second << " (" << p->first << ", ...)\n";
@@ -327,7 +350,7 @@
     {
       retval = "Overloaded function:\n\n";
 
-      for (const_dispatch_map_iterator p = dispatch_map.begin ();
+      for (dispatch_map_const_iterator p = dispatch_map.begin ();
 	   p != dispatch_map.end (); p++)
 	retval += "  " + p->second + " (" + p->first + ", ...)\n\n";
     }
@@ -671,6 +694,75 @@
   return function_on_path;
 }
 
+static std::string
+fcn_file_name (const octave_value& fcn)
+{
+  const octave_function *f = fcn.function_value ();
+
+  return f ? f->fcn_file_name () : std::string ();
+}
+
+void
+symbol_table::fcn_info::fcn_info_rep::dump
+  (std::ostream& os, const std::string& prefix) const
+{
+  os << prefix << name
+     << " ["
+     << (cmdline_function.is_defined () ? "c" : "")
+     << (built_in_function.is_defined () ? "b" : "")
+     << "]\n";
+
+  std::string tprefix = prefix + "  ";
+
+  if (autoload_function.is_defined ())
+    os << tprefix << "autoload: "
+       << fcn_file_name (autoload_function) << "\n";
+
+  if (function_on_path.is_defined ())
+    os << tprefix << "function from path: "
+       << fcn_file_name (function_on_path) << "\n";
+
+  if (! subfunctions.empty ())
+    {
+      for (scope_val_const_iterator p = subfunctions.begin ();
+	   p != subfunctions.end (); p++)
+	os << tprefix << "subfunction: " << fcn_file_name (p->second)
+	   << " [" << p->first << "]\n";
+    }
+
+  if (! private_functions.empty ())
+    {
+      for (str_val_const_iterator p = private_functions.begin ();
+	   p != private_functions.end (); p++)
+	os << tprefix << "private: " << fcn_file_name (p->second)
+	   << " [" << p->first << "]\n";
+    }
+
+  if (! class_constructors.empty ())
+    {
+      for (str_val_const_iterator p = class_constructors.begin ();
+	   p != class_constructors.end (); p++)
+	os << tprefix << "constructor: " << fcn_file_name (p->second)
+	   << " [" << p->first << "]\n";
+    }
+
+  if (! class_methods.empty ())
+    {
+      for (str_val_const_iterator p = class_methods.begin ();
+	   p != class_methods.end (); p++)
+	os << tprefix << "method: " << fcn_file_name (p->second)
+	   << " [" << p->first << "]\n";
+    }
+
+  if (! dispatch_map.empty ())
+    {
+      for (dispatch_map_const_iterator p = dispatch_map.begin ();
+	   p != dispatch_map.end (); p++)
+	os << tprefix << "dispatch: " << fcn_file_name (p->second)
+	   << " [" << p->first << "]\n";
+    }
+}
+
 octave_value
 symbol_table::fcn_info::find (tree_argument_list *args,
 			      const string_vector& arg_names,
@@ -703,6 +795,76 @@
   return find (name, args, arg_names, evaluated_args, args_evaluated, true);
 }
 
+void
+symbol_table::dump (std::ostream& os, scope_id scope)
+{
+  if (scope == xglobal_scope)
+    dump_global (os);
+  else
+    {
+      symbol_table *inst = get_instance (scope, false);
+
+      if (inst)
+	{
+	  os << "*** dumping symbol table scope " << scope
+	     << " (" << inst->table_name << ")\n\n";
+
+	  std::map<std::string, octave_value> sfuns
+	    = symbol_table::subfunctions_defined_in_scope (scope);
+
+	  if (! sfuns.empty ())
+	    {
+	      os << "  subfunctions defined in this scope:\n";
+
+	      for (std::map<std::string, octave_value>::const_iterator p = sfuns.begin ();
+		   p != sfuns.end (); p++)
+		os << "    " << p->first << "\n";
+
+	      os << "\n";
+	    }
+
+
+	  inst->do_dump (os);
+	}
+    }
+}
+
+void
+symbol_table::dump_global (std::ostream& os)
+{
+  if (! global_table.empty ())
+    {
+      os << "*** dumping global symbol table\n\n";
+
+      for (global_table_const_iterator p = global_table.begin ();
+	   p != global_table.end (); p++)
+	{
+	  std::string nm = p->first;
+	  octave_value val = p->second;
+
+	  os << "  " << nm << " ";
+	  val.dump (os);
+	  os << "\n";
+	}
+    }
+}
+
+void
+symbol_table::dump_functions (std::ostream& os)
+{
+  if (! fcn_table.empty ())
+    {
+      os << "*** dumping globally visible functions from symbol table\n"
+	 << "    (c=commandline, b=built-in)\n\n";
+
+      for (fcn_table_const_iterator p = fcn_table.begin ();
+	   p != fcn_table.end (); p++)
+	p->second.dump (os, "  ");
+
+      os << "\n";
+    }
+}
+
 octave_value
 symbol_table::do_find (const std::string& name, tree_argument_list *args,
 		       const string_vector& arg_names,
@@ -719,7 +881,7 @@
 
       if (p != table.end ())
 	{
-	  symbol_record& sr = p->second;
+	  symbol_record sr = p->second;
 
 	  // FIXME -- should we be using something other than varref here?
 
@@ -760,6 +922,39 @@
   return retval;
 }
 
+void
+symbol_table::do_dump (std::ostream& os)
+{
+  if (! persistent_table.empty ())
+    {
+      os << "  persistent variables in this scope:\n\n";
+
+      for (persistent_table_const_iterator p = persistent_table.begin ();
+	   p != persistent_table.end (); p++)
+	{
+	  std::string nm = p->first;
+	  octave_value val = p->second;
+
+	  os << "    " << nm << " ";
+	  val.dump (os);
+	  os << "\n";
+	}
+
+      os << "\n";
+    }
+
+  if (! table.empty ())
+    {
+      os << "  other symbols in this scope (l=local; a=auto; f=formal\n"
+	 << "    h=hidden; i=inherited; g=global; p=persistent)\n\n";
+
+      for (table_const_iterator p = table.begin (); p != table.end (); p++)
+	p->second.dump (os, "    ");
+
+      os << "\n";
+    }
+}
+
 DEFUN (ignore_function_time_stamp, args, nargout,
     "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} ignore_function_time_stamp ()\n\
@@ -823,6 +1018,90 @@
   return retval;
 }
 
+DEFUN (__current_scope__, , ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {[@var{scope}, @var{context}]} __dump_symtab_info__ ()\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  retval(1) = symbol_table::current_context ();
+  retval(0) = symbol_table::current_scope ();
+
+  return retval;
+}
+
+DEFUN (__dump_symtab_info__, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} __dump_symtab_info__ ()\n\
+@deftypefnx {Built-in Function} {} __dump_symtab_info__ (@var{scope})\n\
+@deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"scopes\")\n\
+@deftypefnx {Built-in Function} {} __dump_symtab_info__ (\"functions\")\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 0)
+    {
+      symbol_table::dump_functions (octave_stdout);
+
+      symbol_table::dump_global (octave_stdout);
+
+      std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
+
+      for (std::list<symbol_table::scope_id>::const_iterator p = lst.begin ();
+	   p != lst.end (); p++)
+	symbol_table::dump (octave_stdout, *p);
+    }
+  else if (nargin == 1)
+    {
+      octave_value arg = args(0);
+
+      if (arg.is_string ())
+	{
+	  std::string s_arg = arg.string_value ();
+
+	  if (s_arg == "scopes")
+	    {
+	      std::list<symbol_table::scope_id> lst = symbol_table::scopes ();
+
+	      RowVector v (lst.size ());
+
+	      octave_idx_type k = 0;
+
+	      for (std::list<symbol_table::scope_id>::const_iterator p = lst.begin ();
+		   p != lst.end (); p++)
+		v.xelem (k++) = *p;
+
+	      retval = v;
+	    }
+	  else if (s_arg == "functions")
+	    {
+	      symbol_table::dump_functions (octave_stdout);
+	    }
+	  else
+	    error ("__dump_symtab_info__: expecting \"functions\" or \"scopes\"");
+	}
+      else
+	{
+	  int s = arg.int_value ();
+
+	  if (! error_state)
+	    symbol_table::dump (octave_stdout, s);
+	  else
+	    error ("__dump_symtab_info__: expecting string or scope id");
+	}
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
 #if 0
 
 // FIXME -- should we have functions like this in Octave?
--- a/src/symtab.h	Tue May 06 03:23:12 2008 -0400
+++ b/src/symtab.h	Tue May 06 05:51:17 2008 -0400
@@ -47,6 +47,114 @@
   typedef size_t context_id;
 
   class
+  scope_id_cache
+  {
+  protected:
+
+    typedef std::set<scope_id>::iterator set_iterator;
+    typedef std::set<scope_id>::const_iterator set_const_iterator;
+
+    // We start with 2 because we allocate 0 for the global symbols
+    // and 1 for the top-level workspace.
+
+    scope_id_cache (void) : next_available (2), in_use (), free_list () { }
+
+  public:
+
+    ~scope_id_cache (void) { }
+
+    static scope_id alloc (void)
+    {
+      return instance_ok () ? instance->do_alloc () : -1;
+    }
+
+    static void free (scope_id scope)
+    {
+      if (instance_ok ())
+	return instance->do_free (scope);
+    }
+
+    static std::list<scope_id> scopes (void)
+    {
+      return instance_ok () ? instance->do_scopes () : std::list<scope_id> ();
+    }
+
+    static bool instance_ok (void)
+    {
+      bool retval = true;
+
+      if (! instance)
+	instance = new scope_id_cache ();
+
+      if (! instance)
+	{
+	  ::error ("unable to create scope_id_cache object!");
+
+	  retval = false;
+	}
+
+      return retval;
+    }
+
+  private:
+
+    static scope_id_cache *instance;
+
+    // The next available scope not in the free list.
+    scope_id next_available;
+
+    // The set of scope IDs that are currently allocated.
+    std::set<scope_id> in_use;
+
+    // The set of scope IDs that are currently available.
+    std::set<scope_id> free_list;
+
+    scope_id do_alloc (void)
+    {
+      scope_id retval;
+
+      set_iterator p = free_list.begin ();
+
+      if (p != free_list.end ())
+	{
+	  retval = *p;
+	  free_list.erase (p);
+	}
+      else
+	retval = next_available++;
+
+      in_use.insert (retval);
+
+      return retval;
+    }
+
+    void do_free (scope_id scope)
+    {
+      set_iterator p = in_use.find (scope);
+
+      if (p != in_use.end ())
+	{
+	  in_use.erase (p);
+	  free_list.insert (scope);
+	}
+      else
+	error ("free_scope: scope %d not found!", scope);
+    }
+
+    std::list<scope_id> do_scopes (void) const
+    {
+      std::list<scope_id> retval;
+
+      for (set_const_iterator p = in_use.begin (); p != in_use.end (); p++)
+	retval.push_back (*p);
+
+      retval.sort ();
+
+      return retval;
+    }
+  };
+
+  class
   symbol_record
   {
   public:
@@ -235,6 +343,8 @@
 	return new symbol_record_rep (name, varval (), storage_class);
       }
 
+      void dump (std::ostream& os, const std::string& prefix) const;
+
       std::string name;
 
       std::deque<octave_value> value_stack;
@@ -333,6 +443,12 @@
 
     unsigned int xstorage_class (void) const { return rep->storage_class; }
 
+    void
+    dump (std::ostream& os, const std::string& prefix = std::string ()) const
+    {
+      rep->dump (os, prefix);
+    }
+
   private:
 
     symbol_record_rep *rep;
@@ -347,13 +463,13 @@
 
     typedef std::map<std::string, std::string> dispatch_map_type;
 
-    typedef std::map<scope_id, octave_value>::const_iterator const_scope_val_iterator;
+    typedef std::map<scope_id, octave_value>::const_iterator scope_val_const_iterator;
     typedef std::map<scope_id, octave_value>::iterator scope_val_iterator;
 
-    typedef std::map<std::string, octave_value>::const_iterator const_str_val_iterator;
+    typedef std::map<std::string, octave_value>::const_iterator str_val_const_iterator;
     typedef std::map<std::string, octave_value>::iterator str_val_iterator;
 
-    typedef dispatch_map_type::const_iterator const_dispatch_map_iterator;
+    typedef dispatch_map_type::const_iterator dispatch_map_const_iterator;
     typedef dispatch_map_type::iterator dispatch_map_iterator;
 
   private:
@@ -406,6 +522,32 @@
 	return find (0, arg_names, evaluated_args, args_evaluated);
       }
 
+      void lock_subfunction (scope_id scope)
+      {
+	scope_val_iterator p = subfunctions.find (scope);
+
+	if (p != subfunctions.end ())
+	  p->second.lock ();
+      }
+
+      void unlock_subfunction (scope_id scope)
+      {
+	scope_val_iterator p = subfunctions.find (scope);
+
+	if (p != subfunctions.end ())
+	  p->second.unlock ();
+      }
+
+      std::pair<std::string, octave_value>
+      subfunction_defined_in_scope (scope_id scope) const
+      {
+	scope_val_const_iterator p = subfunctions.find (scope);
+
+	return p == subfunctions.end ()
+	  ? std::pair<std::string, octave_value> ()
+	  : std::pair<std::string, octave_value> (name, p->second);
+      }	     
+
       void install_cmdline_function (const octave_value& f)
       {
 	cmdline_function = f;
@@ -497,6 +639,8 @@
 
       dispatch_map_type get_dispatch (void) const { return dispatch_map; }
 
+      void dump (std::ostream& os, const std::string& prefix) const;
+
       std::string name;
 
       // Scope id to function object.
@@ -599,6 +743,22 @@
       return rep->find_function (args);
     }
 
+    void lock_subfunction (scope_id scope)
+    {
+      rep->lock_subfunction (scope);
+    }
+
+    void unlock_subfunction (scope_id scope)
+    {
+      rep->unlock_subfunction (scope);
+    }
+
+    std::pair<std::string, octave_value>
+    subfunction_defined_in_scope (scope_id scope = xcurrent_scope) const
+    {
+      return rep->subfunction_defined_in_scope (scope);
+    }	     
+
     void install_cmdline_function (const octave_value& f)
     {
       rep->install_cmdline_function (f);
@@ -647,6 +807,12 @@
       return rep->get_dispatch ();
     }
 
+    void
+    dump (std::ostream& os, const std::string& prefix = std::string ()) const
+    {
+      rep->dump (os, prefix);
+    }
+
   private:
 
     fcn_info_rep *rep;
@@ -663,24 +829,7 @@
   // We use parent_scope to handle parsing subfunctions.
   static scope_id parent_scope (void) { return xparent_scope; }
 
-  static scope_id alloc_scope (void)
-  {
-    scope_id retval;
-
-    scope_ids_free_list_iterator p = scope_ids_free_list.begin ();
-
-    if (p != scope_ids_free_list.end ())
-      {
-	retval = *p;
-	scope_ids_free_list.erase (p);
-      }
-    else
-      retval = next_available_scope++;
-
-    scope_ids_in_use.insert (retval);
-
-    return retval;
-  }
+  static scope_id alloc_scope (void) { return scope_id_cache::alloc (); }
 
   static void set_scope (scope_id scope)
   {
@@ -692,9 +841,10 @@
 
 	if (p == all_instances.end ())
 	  {
-	    instance = new symbol_table ();
-
-	    all_instances[scope] = instance;
+	    symbol_table *inst = new symbol_table ();
+
+	    if (inst)
+	      all_instances[scope] = instance = inst;
 	  }
 	else
 	  instance = p->second;
@@ -780,9 +930,13 @@
     all_instances_iterator p = all_instances.find (scope);
 
     if (p != all_instances.end ())
-      all_instances.erase (p);
-
-    // free_scope (scope);
+      {
+	delete p->second;
+
+	all_instances.erase (p);
+
+	free_scope (scope);
+      }
   }
 
   static scope_id dup_scope (scope_id scope)
@@ -810,30 +964,10 @@
     return retval;
   }
 
-#if 0
-  static void print_scope (const std::string& tag)
-  {
-    symbol_table *inst = get_instance (xcurrent_scope);
-
-    if (inst)
-      inst->do_print_scope (std::cerr);
-  }
-
-  void do_print_scope (std::ostream& os) const
+  static std::list<scope_id> scopes (void)
   {
-    for (const_table_iterator p = table.begin (); p != table.end (); p++)
-      {
-	symbol_record sr = p->second;
-
-	octave_value val = sr.varval ();
-
-	if (val.is_defined ())
-	  sr.varval ().print_with_name (os, sr.name ());
-	else
-	  os << sr.name () << " is not defined" << std::endl;
-      }
+    return scope_id_cache::scopes ();
   }
-#endif
 
   static symbol_record
   find_symbol (const std::string& name, scope_id scope = xcurrent_scope)
@@ -899,7 +1033,7 @@
   static octave_value
   global_varval (const std::string& name)
   {
-    const_global_table_iterator p = global_table.find (name);
+    global_table_const_iterator p = global_table.find (name);
 
     return (p != global_table.end ()) ? p->second : octave_value ();
   }
@@ -946,7 +1080,7 @@
   static octave_value
   find_method (const std::string& name, const std::string& dispatch_type)
   {
-    const_fcn_table_iterator p = fcn_table.find (name);
+    fcn_table_const_iterator p = fcn_table.find (name);
 
     if (p != fcn_table.end ())
       return p->second.find_method (dispatch_type);
@@ -966,7 +1100,7 @@
   static octave_value
   find_built_in_function (const std::string& name)
   {
-    const_fcn_table_iterator p = fcn_table.find (name);
+    fcn_table_const_iterator p = fcn_table.find (name);
 
     return (p != fcn_table.end ())
       ? p->second.find_built_in_function () : octave_value ();
@@ -1383,7 +1517,7 @@
 
     glob_match pat (pattern);
 
-    for (const_global_table_iterator p = global_table.begin ();
+    for (global_table_const_iterator p = global_table.begin ();
 	 p != global_table.end (); p++)
       {
 	// We generate a list of symbol_record objects so that
@@ -1435,7 +1569,7 @@
   {
     std::list<std::string> retval;
 
-    for (const_global_table_iterator p = global_table.begin ();
+    for (global_table_const_iterator p = global_table.begin ();
 	 p != global_table.end (); p++)
       retval.push_back (p->first);
 
@@ -1462,7 +1596,7 @@
   {
     std::list<std::string> retval;
 
-    for (const_fcn_table_iterator p = fcn_table.begin ();
+    for (fcn_table_const_iterator p = fcn_table.begin ();
 	 p != fcn_table.end (); p++)
       {
 	octave_value fcn = p->second.find_built_in_function ();
@@ -1501,28 +1635,62 @@
       }
   }
 
+  static void dump (std::ostream& os, scope_id scope = xcurrent_scope);
+
+  static void dump_global (std::ostream& os);
+
+  static void dump_functions (std::ostream& os);
+
+  static void cache_name (scope_id scope, const std::string& name)
+  {
+    symbol_table *inst = get_instance (scope, false);
+
+    if (inst)
+      inst->do_cache_name (name);
+  }
+
+  static void lock_subfunctions (scope_id scope = xcurrent_scope)
+  {
+    for (fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      p->second.lock_subfunction (scope);
+  }    
+
+  static void unlock_subfunctions (scope_id scope = xcurrent_scope)
+  {
+    for (fcn_table_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      p->second.unlock_subfunction (scope);
+  }    
+
+  static void free_scope (scope_id scope)
+  {
+    if (scope == xglobal_scope || scope == xtop_scope)
+      error ("can't free global or top-level scopes!");
+    else
+      symbol_table::scope_id_cache::free (scope);
+  }
+
 private:
 
-  typedef std::map<std::string, symbol_record>::const_iterator const_table_iterator;
+  typedef std::map<std::string, symbol_record>::const_iterator table_const_iterator;
   typedef std::map<std::string, symbol_record>::iterator table_iterator;
 
-  typedef std::map<std::string, octave_value>::const_iterator const_global_table_iterator;
+  typedef std::map<std::string, octave_value>::const_iterator global_table_const_iterator;
   typedef std::map<std::string, octave_value>::iterator global_table_iterator;
 
-  typedef std::map<std::string, octave_value>::const_iterator const_persistent_table_iterator;
+  typedef std::map<std::string, octave_value>::const_iterator persistent_table_const_iterator;
   typedef std::map<std::string, octave_value>::iterator persistent_table_iterator;
 
   typedef std::map<scope_id, symbol_table*>::const_iterator all_instances_const_iterator;
   typedef std::map<scope_id, symbol_table*>::iterator all_instances_iterator;
 
-  typedef std::map<std::string, fcn_info>::const_iterator const_fcn_table_iterator;
+  typedef std::map<std::string, fcn_info>::const_iterator fcn_table_const_iterator;
   typedef std::map<std::string, fcn_info>::iterator fcn_table_iterator;
 
-  typedef std::set<scope_id>::const_iterator scope_ids_free_list_const_iterator;
-  typedef std::set<scope_id>::iterator scope_ids_free_list_iterator;
-
-  typedef std::set<scope_id>::const_iterator scope_ids_in_use_const_iterator;
-  typedef std::set<scope_id>::iterator scope_ids_in_use_iterator;
+  // Name for this table (usually the file name of the function
+  // corresponding to the scope);
+  std::string table_name;
 
   // Map from symbol names to symbol info.
   std::map<std::string, symbol_record> table;
@@ -1558,54 +1726,36 @@
 
   static std::deque<scope_id> scope_stack;
 
-  // The next available scope ID.
-  static scope_id next_available_scope;
-
-  // The set of scope IDs that are currently allocated.
-  static std::set<scope_id> scope_ids_in_use;
-
-  // The set of scope IDs that are currently available.
-  static std::set<scope_id> scope_ids_free_list;
-
-  symbol_table (void) : table (), xcurrent_context_this_table () { }
+  symbol_table (void)
+    : table_name (), table (), xcurrent_context_this_table () { }
 
   ~symbol_table (void) { }
 
-  static void free_scope (scope_id scope)
-  {
-    if (scope == xglobal_scope || scope == xtop_scope)
-      error ("can't free global or top-level scopes!");
-    else
-      {
-	scope_ids_in_use_iterator p = scope_ids_in_use.find (scope);
-
-	if (p != scope_ids_in_use.end ())
-	  {
-	    scope_ids_in_use.erase (p);
-	    scope_ids_free_list.insert (*p);
-	  }
-	else
-	  error ("scope id = %ld not found!", scope);
-      }
-  }
-
-  static symbol_table *get_instance (scope_id scope)
+  static symbol_table *get_instance (scope_id scope, bool create = true)
   {
     symbol_table *retval = 0;
 
+    bool ok = true;
+
     if (scope != xglobal_scope)
       {
 	if (scope == xcurrent_scope)
 	  {
-	    if (! instance)
+	    if (! instance && create)
 	      {
-		instance = new symbol_table ();
-
-		all_instances[scope] = instance;
+		symbol_table *inst = new symbol_table ();
+
+		if (inst)
+		  {
+		    all_instances[scope] = instance = inst;
+
+		    if (scope == xtop_scope)
+		      instance->do_cache_name ("top-level");
+		  }
 	      }
 
 	    if (! instance)
-	      error ("unable to create symbol_table object!");
+	      ok = false;
 
 	    retval = instance;
 	  }
@@ -1615,15 +1765,27 @@
 
 	    if (p == all_instances.end ())
 	      {
-		retval = new symbol_table ();
-
-		all_instances[scope] = retval;
+		if (create)
+		  {
+		    retval = new symbol_table ();
+
+		    if (retval)
+		      all_instances[scope] = retval;
+		    else
+		      ok = false;
+		  }
+		else
+		  ok = false;
 	      }
 	    else
 	      retval = p->second;
 	  }
       }
 
+    if (! ok)
+      error ("unable to %s symbol_table object for scope %d!",
+	     create ? "create" : "find", scope);
+
     return retval;
   }
 
@@ -1635,7 +1797,7 @@
   void
   do_dup_scope (symbol_table& new_symbol_table) const
   {
-    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+    for (table_const_iterator p = table.begin (); p != table.end (); p++)
       new_symbol_table.insert_symbol_record (p->second.dup ());
   }
 
@@ -1701,7 +1863,7 @@
 
   octave_value do_varval (const std::string& name) const
   {
-    const_table_iterator p = table.find (name);
+    table_const_iterator p = table.find (name);
 
     return (p != table.end ()) ? p->second.varval () : octave_value ();
   }
@@ -1716,7 +1878,7 @@
 
   octave_value do_persistent_varval (const std::string& name)
   {
-    const_persistent_table_iterator p = persistent_table.find (name);
+    persistent_table_const_iterator p = persistent_table.find (name);
 
     return (p != persistent_table.end ()) ? p->second : octave_value ();
   }
@@ -1733,7 +1895,7 @@
   {
     bool retval = false;
 
-    const_table_iterator p = table.find (name);
+    table_const_iterator p = table.find (name);
 
     if (p != table.end ())
       {
@@ -1859,7 +2021,7 @@
   {
     std::list<symbol_record> retval;
 
-    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+    for (table_const_iterator p = table.begin (); p != table.end (); p++)
       {
 	const symbol_record& sr = p->second;
 
@@ -1879,7 +2041,7 @@
 
     glob_match pat (pattern);
 
-    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+    for (table_const_iterator p = table.begin (); p != table.end (); p++)
       {
 	if (pat.match (p->first))
 	  {
@@ -1899,7 +2061,7 @@
   {
     std::list<std::string> retval;
 
-    for (const_table_iterator p = table.begin (); p != table.end (); p++)
+    for (table_const_iterator p = table.begin (); p != table.end (); p++)
       retval.push_back (p->first);
 
     retval.sort ();
@@ -1907,9 +2069,29 @@
     return retval;
   }
 
+  static std::map<std::string, octave_value>
+  subfunctions_defined_in_scope (scope_id scope = xcurrent_scope)
+  {
+    std::map<std::string, octave_value> retval;
+
+    for (fcn_table_const_iterator p = fcn_table.begin ();
+	 p != fcn_table.end (); p++)
+      {
+	std::pair<std::string, octave_value> tmp
+	  = p->second.subfunction_defined_in_scope (scope);
+
+	std::string nm = tmp.first;
+
+	if (! nm.empty ())
+	  retval[nm] = tmp.second;
+      }
+
+    return retval;
+  }
+
   bool do_is_local_variable (const std::string& name) const
   {
-    const_table_iterator p = table.find (name);
+    table_const_iterator p = table.find (name);
 
     return (p != table.end ()
 	    && ! p->second.is_global ()
@@ -1918,10 +2100,14 @@
 
   bool do_is_global (const std::string& name) const
   {
-    const_table_iterator p = table.find (name);
+    table_const_iterator p = table.find (name);
 
     return p != table.end () && p->second.is_global ();
   }
+
+  void do_dump (std::ostream& os);
+
+  void do_cache_name (const std::string& name) { table_name = name; }
 };
 
 extern bool out_of_date_check (octave_value& function);
--- a/src/variables.cc	Tue May 06 03:23:12 2008 -0400
+++ b/src/variables.cc	Tue May 06 05:51:17 2008 -0400
@@ -2375,34 +2375,6 @@
   return retval;
 }
 
-DEFUN (__print_symtab_info__, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} __print_symtab_info__ ()\n\
-Undocumented internal function.\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  // FIXME -- what should this function do now?  Print a summary for
-  // each scope?  Print the entire symbol table?  Accept a scope
-  // argument?
-
-  return retval;
-}
-
-DEFUN (__print_symbol_info__, args, ,
-  "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {} __dump_symbol_info__ (@var{name})\n\
-Undocumented internal function.\n\
-@end deftypefn")
-{
-  octave_value_list retval;
-
-  // FIXME -- what should this function do now?
-
-  return retval;
-}
-
 DEFUN (whos_line_format, args, nargout,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\