changeset 16676:7368654f302f classdef

Initial support for (classdef) packages. * libinterp/interpfcn/load-path.h (class load_path::loader): New class. (load_path::default_loader, load_path::loader_map): New members. (load_path::load_path): Initialize them. (load_path::fcn_map, load_path::private_fcn_map, load_path::method_map): Move to class load_path::loader. (load_path::add_to_fcn_map, load_path::add_to_private_fcn_map, load_path::add_to_method_map, load_path::move_fcn_map, load_path::move_method_map, load_path::remove_fcn_map, load_path::remove_private_fcn_map, load_path::remove_method_map): Move to class load_path::loader. (load_path::move): Change signature. (load_path::do_move, load_path::remove, load_path::add, load_path::get_loader): New methods. (load_path::find_package, load_path::do_find_package): Likewise. (load_path::dir_info::package_dir_map): New member. (load_path::dir_info::dir_info, load_path::dir_info::operator=): Initialize/assign it. (load_path::dir_info::get_package_dir): New method. (load_path::do_find_fcn, load_path::do_find_private_fcn): Remove methods. (load_path::find_fcn, load_path::find_private_fcn, load_path::find_fcn_file, load_path::find_oct_file, load_path::find_mex_file): Rewrite using class load_path::loader. New argument for package name. *libinterp/interpfcn/load-path.cc (load_path::dir_info::initialize): Clear package_map_dir. (load_path::dir_info::get_package_dir): New method. (load_path::dir_info::get_files_list): Use it. (load_path::add_to_fcn_map, load_path::add_to_private_fcn_map, load_path::add_to_method_map, load_path::move_fcn_map, load_path::move_method_map, load_path::remove_fcn_map, load_path::remove_private_fcn_map, load_path::remove_method_map): Move to class load_path::loader. (load_path::move): Move implementation to do_move, rewrite using class load_path::loader. Signature change. (load_path::do_move, load_path::add, load_path::remove): New methods. (load_path::do_clear): Rewrite using class load_path::loader. (load_path::do_add): Use "do_move" and "add" methods. (load_path::do_remove): Rewrite using "remove" method. (load_path::do_update): Rewitre using class load_path::loader and "add" method. (load_path::do_find_method, load_path::do_methods, load_path::do_overloads, load_path::do_fcn_names, load_path::do_display): Move Implementation to class load_path::loader, without "do_" prefix. Rewrite original to redirect to appropriate loaders. (F__dump_load_path__): New debug function. * libinterp/interpfcn/symtab.h (symbol_table::package_name): New member. (symbol_table::symbol_table): Initialize it. (symbol_table::find): New scope argument. (symbol_table::alloc_package_scope): New method. (symbol_table::fcn_info::find, symbol_table::fcn_info::find_function, symbol_table::fcn_info::find_user_function, symbol_table::fcn_info::fcn_info_rep::xfind, symbol_table::fcn_info::fcn_info_rep::load_class_constructor, symbol_table::fcn_info::fcn_info_rep::find, symbol_table::fcn_info::fcn_info_rep::find_user_function): New argument for package name. (symbol_table::fcn_info::fcn_info_rep::package): New member. (symbol_table::fcn_info::fcn_info_rep::find_package, symbol_table::fcn_info::fcn_info_rep::clear_package): New methods. (symbol_table::fcn_info::fcn_info_rep::clear): Clear package. * libinterp/interpfcn/symtab.cc (symbol_table::fcn_info::fcn_info_rep::load_class_constructor, symbol_table::fcn_info::fcn_info_rep::find, symbol_table::fcn_info::fcn_info_rep::xfind, symbol_table::fcn_info::fcn_info_rep::find_user_function): New argument for package name. (symbol_table::fcn_info::fcn_info_rep::find_package): New method. (symbol_table::find): New scope argument. (symbol_table::do_find): Use package_name member. * libinterp/octave-value/ov-classdef.h (cdef_package::cdef_package_rep::scope): New member. (cdef_package::cdef_package_rep::~cdef_package_rep): New destructor. (cdef_package::cdef_package_rep::meta_subsref, cdef_package::cdef_package_rep::meta_release, cdef_package::cdef_package_rep::meta_is_postfix_index_handled, cdef_package::cdef_package_rep::find, cdef_package::cdef_package_rep::wrap): New methods. (cdef_package::find): New method. (cdef_manager::find_package, cdef_manager::do_find_package): New argument "load_if_not_found". (cdef_manager::find_package_symbol, cdef_manager::do_find_package_symbol): New methods. * libinterp/octave-value/ov-classdef.cc (cdef_manager::do_find_package_symbol): New method. (cdef_manager::do_find_package): New argument. Create package object if it is not loaded yet and the package exists in load_path. (cdef_manager::do_find_class): Handle class names with package. (cdef_package::cdef_package_rep::meta_subsref, cdef_package::cdef_package_rep::meta_release, cdef_package::cdef_package_rep::find): New methods. (cdef_class::make_meta_class): Handle package-scoped classes. (make_package): Assign correct name to the package object. * libinterp/parse-tree/pt-classdef.h (tree_classdef::pack_name): New member. (tree_classdef::tree_classdef): New argument. Initialize it. (tree_classdef::package_name): New accessor. * libinterp/parse-tree/parse.h (octave_base_parser::curr_package_name): New member. (octave_base_parser::octave_base_parser): Initialize it. (load_fcn_from_file): New argument for package name. * libinterp/parse-tree/oct-parse.in.yy (load_fcn_from_file): New argument for package name. Change callers. (parse_fcn_from_file): New argument for package name. Change callers. (octave_base_parser::make_classdef): Use curr_package_name to create the tree_classdef object. * libinterp/octave-value/ov-fcn-handle.cc (octave_fcn_handle::set_fcn): Adapt to new load_fcn_from_file signature. * libinterp/interp-core/ls-mat5.cc (read_mat5_binary_element): Adapt to new load_fcn_from_file signature.
author Michael Goffioul <michael.goffioul@gmail.com>
date Fri, 17 May 2013 23:17:25 -0400
parents 450c03932d6c
children 2c8dc18fa9c6
files libinterp/interp-core/ls-mat5.cc libinterp/interpfcn/load-path.cc libinterp/interpfcn/load-path.h libinterp/interpfcn/symtab.cc libinterp/interpfcn/symtab.h libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h libinterp/octave-value/ov-fcn-handle.cc libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/parse.h libinterp/parse-tree/pt-classdef.h
diffstat 11 files changed, 853 insertions(+), 237 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/interp-core/ls-mat5.cc	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/interp-core/ls-mat5.cc	Fri May 17 23:17:25 2013 -0400
@@ -906,7 +906,7 @@
                         std::string dir_name = str.substr (0, xpos);
 
                         octave_function *fcn
-                          = load_fcn_from_file (str, dir_name, "", fname);
+                          = load_fcn_from_file (str, dir_name, "", "", fname);
 
                         if (fcn)
                           {
@@ -934,7 +934,7 @@
                         std::string dir_name = str.substr (0, xpos);
 
                         octave_function *fcn
-                          = load_fcn_from_file (str, dir_name, "", fname);
+                          = load_fcn_from_file (str, dir_name, "", "", fname);
 
                         if (fcn)
                           {
@@ -958,7 +958,7 @@
                     std::string dir_name = fpath.substr (0, xpos);
 
                     octave_function *fcn
-                      = load_fcn_from_file (fpath, dir_name, "", fname);
+                      = load_fcn_from_file (fpath, dir_name, "", "", fname);
 
                     if (fcn)
                       {
--- a/libinterp/interpfcn/load-path.cc	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/interpfcn/load-path.cc	Fri May 17 23:17:25 2013 -0400
@@ -119,6 +119,7 @@
   if (fs)
     {
       method_file_map.clear ();
+      package_dir_map.clear ();
 
       dir_mtime = fs.mtime ();
       dir_time_last_checked = octave_time ();
@@ -180,6 +181,8 @@
                     get_private_file_map (full_name);
                   else if (fname[0] == '@')
                     get_method_file_map (full_name, fname.substr (1));
+                  else if (fname[0] == '+')
+                    get_package_dir (full_name, fname.substr (1));
                 }
               else
                 {
@@ -285,6 +288,13 @@
     method_file_map[class_name].private_file_map = get_fcn_files (pd);
 }
 
+void
+load_path::dir_info::get_package_dir (const std::string& d,
+                                      const std::string& package_name)
+{
+  package_dir_map[package_name] = dir_info (d);
+}
+
 bool
 load_path::instance_ok (void)
 {
@@ -373,8 +383,8 @@
 }
 
 void
-load_path::move_fcn_map (const std::string& dir_name,
-                         const string_vector& fcn_files, bool at_end)
+load_path::loader::move_fcn_map (const std::string& dir_name,
+                                 const string_vector& fcn_files, bool at_end)
 {
   octave_idx_type len = fcn_files.length ();
 
@@ -422,7 +432,7 @@
 }
 
 void
-load_path::move_method_map (const std::string& dir_name, bool at_end)
+load_path::loader::move_method_map (const std::string& dir_name, bool at_end)
 {
   for (method_map_iterator i = method_map.begin ();
        i != method_map.end ();
@@ -467,7 +477,7 @@
 }
 
 void
-load_path::move (dir_info_list_iterator i, bool at_end)
+load_path::do_move (dir_info_list_iterator i, bool at_end)
 {
   if (dir_info_list.size () > 1)
     {
@@ -480,16 +490,56 @@
       else
         dir_info_list.push_front (di);
 
-      std::string dir_name = di.dir_name;
-
-      move_fcn_map (dir_name, di.fcn_files, at_end);
-
-      // No need to move elements of private function map.
-
-      move_method_map (dir_name, at_end);
+      move (di, at_end);
+    }
+}
+
+void
+load_path::move (const dir_info& di, bool at_end, const std::string& pname)
+{
+  loader& l = get_loader (pname);
+
+  l.move (di, at_end);
+
+  dir_info::package_dir_map_type package_dir_map = di.package_dir_map;
+
+  for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin ();
+       p != package_dir_map.end (); ++p)
+    {
+      std::string full_name = p->first;
+
+      if (! pname.empty ())
+        full_name = pname + "." + full_name;
+
+      move (p->second, at_end, full_name);
     }
 }
 
+void
+load_path::loader::move (const dir_info& di, bool at_end)
+{
+  std::string dir_name = di.dir_name;
+
+  std::list<std::string>::iterator s = 
+    std::find (dir_list.begin (), dir_list.end (), dir_name);
+
+  if (s != dir_list.end ())
+    {
+      dir_list.erase (s);
+
+      if (at_end)
+        dir_list.push_back (dir_name);
+      else
+        dir_list.push_front (dir_name);
+    }
+
+  move_fcn_map (dir_name, di.fcn_files, at_end);
+
+  // No need to move elements of private function map.
+
+  move_method_map (dir_name, at_end);
+}
+
 static void
 maybe_add_path_elts (std::string& path, const std::string& dir)
 {
@@ -545,9 +595,10 @@
 load_path::do_clear (void)
 {
   dir_info_list.clear ();
-  fcn_map.clear ();
-  private_fcn_map.clear ();
-  method_map.clear ();
+
+  default_loader.clear ();
+
+  loader_map.clear ();
 }
 
 static std::list<std::string>
@@ -684,7 +735,7 @@
   dir_info_list_iterator i = find_dir_info (dir);
 
   if (i != dir_info_list.end ())
-    move (i, at_end);
+    do_move (i, at_end);
   else
     {
       file_stat fs (dir);
@@ -702,11 +753,7 @@
                   else
                     dir_info_list.push_front (di);
 
-                  add_to_fcn_map (di, at_end);
-
-                  add_to_private_fcn_map (di);
-
-                  add_to_method_map (di, at_end);
+                  add (di, at_end);
 
                   if (add_hook)
                     add_hook (dir);
@@ -727,12 +774,12 @@
   i = find_dir_info (".");
 
   if (i != dir_info_list.end ())
-    move (i, false);
+    do_move (i, false);
 }
 
 void
-load_path::remove_fcn_map (const std::string& dir,
-                           const string_vector& fcn_files)
+load_path::loader::remove_fcn_map (const std::string& dir,
+                                   const string_vector& fcn_files)
 {
   octave_idx_type len = fcn_files.length ();
 
@@ -771,7 +818,7 @@
 }
 
 void
-load_path::remove_private_fcn_map (const std::string& dir)
+load_path::loader::remove_private_fcn_map (const std::string& dir)
 {
   private_fcn_map_iterator p = private_fcn_map.find (dir);
 
@@ -780,7 +827,7 @@
 }
 
 void
-load_path::remove_method_map (const std::string& dir)
+load_path::loader::remove_method_map (const std::string& dir)
 {
   for (method_map_iterator i = method_map.begin ();
        i != method_map.end ();
@@ -849,15 +896,11 @@
               if (remove_hook)
                 remove_hook (dir);
 
-              string_vector fcn_files = i->fcn_files;
+              dir_info& di = *i;
 
               dir_info_list.erase (i);
 
-              remove_fcn_map (dir, fcn_files);
-
-              remove_private_fcn_map (dir);
-
-              remove_method_map (dir);
+              remove (di);
             }
         }
     }
@@ -866,17 +909,52 @@
 }
 
 void
+load_path::remove (const dir_info& di, const std::string& pname)
+{
+  loader& l = get_loader (pname);
+
+  l.remove (di);
+
+  dir_info::package_dir_map_type package_dir_map = di.package_dir_map;
+
+  for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin ();
+       p != package_dir_map.end (); ++p)
+    {
+      std::string full_name = p->first;
+
+      if (! pname.empty ())
+        full_name = pname + "." + full_name;
+
+      remove (p->second, full_name);
+    }
+}
+
+void
+load_path::loader::remove (const dir_info& di)
+{
+  std::string dir = di.dir_name;
+
+  string_vector fcn_files = di.fcn_files;
+
+  dir_list.remove (dir);
+
+  remove_fcn_map (dir, fcn_files);
+
+  remove_private_fcn_map (dir);
+
+  remove_method_map (dir);
+}
+
+void
 load_path::do_update (void) const
 {
   // I don't see a better way to do this because we need to
   // preserve the correct directory ordering for new files that
   // have appeared.
 
-  fcn_map.clear ();
-
-  private_fcn_map.clear ();
-
-  method_map.clear ();
+  default_loader.clear ();
+
+  loader_map.clear ();
 
   for (dir_info_list_iterator p = dir_info_list.begin ();
        p != dir_info_list.end ();
@@ -886,11 +964,7 @@
 
       di.update ();
 
-      add_to_fcn_map (di, true);
-
-      add_to_private_fcn_map (di);
-
-      add_to_method_map (di, true);
+      add (di, true);
     }
 }
 
@@ -989,8 +1063,8 @@
 }
 
 std::string
-load_path::do_find_fcn (const std::string& fcn, std::string& dir_name,
-                        int type) const
+load_path::loader::find_fcn (const std::string& fcn, std::string& dir_name,
+                             int type) const
 {
   std::string retval;
 
@@ -1005,7 +1079,7 @@
           std::string class_name = fcn.substr (1, pos-1);
           std::string meth = fcn.substr (pos+1);
 
-          retval = do_find_method (class_name, meth, dir_name);
+          retval = find_method (class_name, meth, dir_name);
         }
       else
         retval = std::string ();
@@ -1044,8 +1118,8 @@
 }
 
 std::string
-load_path::do_find_private_fcn (const std::string& dir,
-                                const std::string& fcn, int type) const
+load_path::loader::find_private_fcn (const std::string& dir,
+                                     const std::string& fcn, int type) const
 {
   std::string retval;
 
@@ -1076,7 +1150,26 @@
 std::string
 load_path::do_find_method (const std::string& class_name,
                            const std::string& meth,
-                           std::string& dir_name, int type) const
+                           std::string& dir_name) const
+{
+  size_t pos = class_name.rfind ('.');
+
+  if (pos == std::string::npos)
+    return default_loader.find_method (class_name, meth, dir_name);
+  else
+    {
+      std::string pname = class_name.substr (0, pos);
+
+      std::string cname = class_name.substr (pos+1);
+
+      return get_loader(pname).find_method (cname, meth, dir_name);
+    }
+}
+
+std::string
+load_path::loader::find_method (const std::string& class_name,
+                                const std::string& meth,
+                                std::string& dir_name, int type) const
 {
   std::string retval;
 
@@ -1124,6 +1217,23 @@
 std::list<std::string>
 load_path::do_methods (const std::string& class_name) const
 {
+  size_t pos = class_name.rfind ('.');
+
+  if (pos == std::string::npos)
+    return default_loader.methods (class_name);
+  else
+    {
+      std::string pname = class_name.substr (0, pos);
+
+      std::string cname = class_name.substr (pos+1);
+
+      return get_loader (pname).methods (cname);
+    }
+}
+
+std::list<std::string>
+load_path::loader::methods (const std::string& class_name) const
+{
   std::list<std::string> retval;
 
   //  update ();
@@ -1151,16 +1261,34 @@
 
   //  update ();
 
+  default_loader.overloads (meth, retval);
+
+  for (const_loader_map_iterator l = loader_map.begin ();
+       l != loader_map.end (); ++l)
+    l->second.overloads (meth, retval);
+
+  return retval;
+}
+
+void
+load_path::loader::overloads (const std::string& meth,
+                              std::list<std::string>& l) const
+{
   for (const_method_map_iterator q = method_map.begin ();
        q != method_map.end (); q++)
     {
       const fcn_map_type& m = q->second;
 
       if (m.find (meth) != m.end ())
-        retval.push_back (q->first);
+        {
+          std::string class_name = q->first;
+
+          if (! prefix.empty ())
+            class_name = prefix + "." + class_name;
+
+          l.push_back (class_name);
+        }
     }
-
-  return retval;
 }
 
 std::string
@@ -1518,6 +1646,12 @@
 string_vector
 load_path::do_fcn_names (void) const
 {
+  return default_loader.fcn_names ();
+}
+
+string_vector
+load_path::loader::fcn_names (void) const
+{
   size_t len = fcn_map.size ();
 
   string_vector retval (len);
@@ -1661,69 +1795,11 @@
         }
     }
 
-  for (const_private_fcn_map_iterator i = private_fcn_map.begin ();
-       i != private_fcn_map.end (); i++)
-    {
-      os << "\n*** private functions in "
-         << file_ops::concat (i->first, "private") << ":\n\n";
-
-      print_fcn_list (os, i->second);
-    }
-
-#if defined (DEBUG_LOAD_PATH)
-
-  for (const_fcn_map_iterator i = fcn_map.begin ();
-       i != fcn_map.end ();
-       i++)
-    {
-      os << i->first << ":\n";
-
-      const file_info_list_type& file_info_list = i->second;
-
-      for (const_file_info_list_iterator p = file_info_list.begin ();
-           p != file_info_list.end ();
-           p++)
-        {
-          os << "  " << p->dir_name << " (";
-
-          print_types (os, p->types);
-
-          os << ")\n";
-        }
-    }
-
-  for (const_method_map_iterator i = method_map.begin ();
-       i != method_map.end ();
-       i++)
-    {
-      os << "CLASS " << i->first << ":\n";
-
-      const fcn_map_type& fm = i->second;
-
-      for (const_fcn_map_iterator q = fm.begin ();
-           q != fm.end ();
-           q++)
-        {
-          os << "  " << q->first << ":\n";
-
-          const file_info_list_type& file_info_list = q->second;
-
-          for (const_file_info_list_iterator p = file_info_list.begin ();
-               p != file_info_list.end ();
-               p++)
-            {
-              os << "  " << p->dir_name << " (";
-
-              print_types (os, p->types);
-
-              os << ")\n";
-            }
-        }
-    }
-
-  os << "\n";
-
-#endif
+  default_loader.display (os);
+
+  for (const_loader_map_iterator l = loader_map.begin ();
+       l != loader_map.end (); ++l)
+    l->second.display (os);
 }
 
 // True if a path is contained in a path list separated by path_sep_char
@@ -1745,7 +1821,29 @@
 }
 
 void
-load_path::add_to_fcn_map (const dir_info& di, bool at_end) const
+load_path::add (const dir_info& di, bool at_end,
+                const std::string& pname) const
+{
+  loader& l = get_loader (pname);
+
+  l.add (di, at_end);
+
+  dir_info::package_dir_map_type package_dir_map = di.package_dir_map;
+
+  for (dir_info::const_package_dir_map_iterator p = package_dir_map.begin ();
+       p != package_dir_map.end (); ++p)
+    {
+      std::string full_name = p->first;
+
+      if (! pname.empty ())
+        full_name = pname + "." + full_name;
+
+      add (p->second, at_end, full_name);
+    }
+}
+
+void
+load_path::loader::add_to_fcn_map (const dir_info& di, bool at_end)
 {
   std::string dir_name = di.dir_name;
 
@@ -1841,7 +1939,7 @@
 }
 
 void
-load_path::add_to_private_fcn_map (const dir_info& di) const
+load_path::loader::add_to_private_fcn_map (const dir_info& di)
 {
   dir_info::fcn_file_map_type private_file_map = di.private_file_map;
 
@@ -1850,7 +1948,7 @@
 }
 
 void
-load_path::add_to_method_map (const dir_info& di, bool at_end) const
+load_path::loader::add_to_method_map (const dir_info& di, bool at_end)
 {
   std::string dir_name = di.dir_name;
 
@@ -1920,6 +2018,81 @@
     }
 }
 
+void
+load_path::loader::display (std::ostream& os) const
+{
+  os << "*** loader: " << (prefix.empty () ? "<top-level>" : prefix) << "\n\n";
+
+  for (std::list<std::string>::const_iterator s = dir_list.begin ();
+       s != dir_list.end (); ++s)
+    os << *s << "\n";
+  os << "\n";
+
+  for (const_private_fcn_map_iterator i = private_fcn_map.begin ();
+       i != private_fcn_map.end (); i++)
+    {
+      os << "\n*** private functions in "
+         << file_ops::concat (i->first, "private") << ":\n\n";
+
+      print_fcn_list (os, i->second);
+    }
+
+#if defined (DEBUG_LOAD_PATH)
+
+  for (const_fcn_map_iterator i = fcn_map.begin ();
+       i != fcn_map.end ();
+       i++)
+    {
+      os << i->first << ":\n";
+
+      const file_info_list_type& file_info_list = i->second;
+
+      for (const_file_info_list_iterator p = file_info_list.begin ();
+           p != file_info_list.end ();
+           p++)
+        {
+          os << "  " << p->dir_name << " (";
+
+          print_types (os, p->types);
+
+          os << ")\n";
+        }
+    }
+
+  for (const_method_map_iterator i = method_map.begin ();
+       i != method_map.end ();
+       i++)
+    {
+      os << "CLASS " << i->first << ":\n";
+
+      const fcn_map_type& fm = i->second;
+
+      for (const_fcn_map_iterator q = fm.begin ();
+           q != fm.end ();
+           q++)
+        {
+          os << "  " << q->first << ":\n";
+
+          const file_info_list_type& file_info_list = q->second;
+
+          for (const_file_info_list_iterator p = file_info_list.begin ();
+               p != file_info_list.end ();
+               p++)
+            {
+              os << "  " << p->dir_name << " (";
+
+              print_types (os, p->types);
+
+              os << ")\n";
+            }
+        }
+    }
+
+  os << "\n";
+
+#endif
+}
+
 std::string
 genpath (const std::string& dirname, const string_vector& skip)
 {
@@ -2340,3 +2513,10 @@
 
   return retval;
 }
+
+DEFUN (__dump_load_path__, , , "")
+{
+  load_path::display (octave_stdout);
+
+  return octave_value_list ();
+}
--- a/libinterp/interpfcn/load-path.h	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/interpfcn/load-path.h	Fri May 17 23:17:25 2013 -0400
@@ -39,8 +39,7 @@
 protected:
 
   load_path (void)
-    : dir_info_list (), fcn_map (), private_fcn_map (), method_map (),
-      init_dirs () { }
+    : loader_map (), default_loader (), dir_info_list (), init_dirs () { }
 
 public:
 
@@ -99,7 +98,8 @@
                                   std::string& dir_name)
   {
     return instance_ok ()
-      ? instance->do_find_method (class_name, meth, dir_name) : std::string ();
+      ? instance->do_find_method (class_name, meth, dir_name)
+      : std::string ();
   }
 
   static std::string find_method (const std::string& class_name,
@@ -121,47 +121,64 @@
       ? instance->do_overloads (meth) : std::list<std::string> ();
   }
 
-  static std::string find_fcn (const std::string& fcn, std::string& dir_name)
+  static bool find_package (const std::string& package_name)
+  {
+    return instance_ok ()
+      ? instance->do_find_package (package_name) : false;
+  }
+
+  static std::string find_fcn (const std::string& fcn, std::string& dir_name,
+                               const std::string& pack_name = std::string ())
   {
     return instance_ok ()
-      ? instance->do_find_fcn (fcn, dir_name) : std::string ();
+      ? instance->get_loader (pack_name).find_fcn (fcn, dir_name)
+      : std::string ();
   }
 
-  static std::string find_fcn (const std::string& fcn)
+  static std::string find_fcn (const std::string& fcn,
+                               const std::string& pack_name = std::string ())
   {
     std::string dir_name;
-    return find_fcn (fcn, dir_name);
+    return find_fcn (fcn, dir_name, pack_name);
   }
 
   static std::string find_private_fcn (const std::string& dir,
-                                       const std::string& fcn)
+                                       const std::string& fcn,
+                                       const std::string& pack_name = std::string ())
   {
     return instance_ok ()
-      ? instance->do_find_private_fcn (dir, fcn) : std::string ();
+      ? instance->get_loader (pack_name).find_private_fcn (dir, fcn)
+      : std::string ();
   }
 
-  static std::string find_fcn_file (const std::string& fcn)
+  static std::string find_fcn_file (const std::string& fcn,
+                                    const std::string& pack_name = std::string ())
   {
     std::string dir_name;
 
-    return instance_ok () ?
-      instance->do_find_fcn (fcn, dir_name, M_FILE) : std::string ();
+    return instance_ok ()
+      ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE)
+      : std::string ();
   }
 
-  static std::string find_oct_file (const std::string& fcn)
+  static std::string find_oct_file (const std::string& fcn,
+                                    const std::string& pack_name = std::string ())
   {
     std::string dir_name;
 
-    return instance_ok () ?
-      instance->do_find_fcn (fcn, dir_name, OCT_FILE) : std::string ();
+    return instance_ok ()
+      ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE)
+      : std::string ();
   }
 
-  static std::string find_mex_file (const std::string& fcn)
+  static std::string find_mex_file (const std::string& fcn,
+                                    const std::string& pack_name = std::string ())
   {
     std::string dir_name;
 
-    return instance_ok () ?
-      instance->do_find_fcn (fcn, dir_name, MEX_FILE) : std::string ();
+    return instance_ok ()
+      ? instance->get_loader (pack_name).find_fcn (fcn, dir_name, M_FILE)
+      : std::string ();
   }
 
   static std::string find_file (const std::string& file)
@@ -295,19 +312,27 @@
     typedef method_file_map_type::const_iterator const_method_file_map_iterator;
     typedef method_file_map_type::iterator method_file_map_iterator;
 
+    // <PACKAGE_NAME, DIR_INFO>
+    typedef std::map<std::string, dir_info> package_dir_map_type;
+
+    typedef package_dir_map_type::const_iterator const_package_dir_map_iterator;
+    typedef package_dir_map_type::iterator package_dir_map_iterator;
+
     // This default constructor is only provided so we can create a
     // std::map of dir_info objects.  You should not use this
     // constructor for any other purpose.
     dir_info (void)
       : dir_name (), abs_dir_name (), is_relative (false),
         dir_mtime (), dir_time_last_checked (),
-        all_files (), fcn_files (), private_file_map (), method_file_map ()
+        all_files (), fcn_files (), private_file_map (), method_file_map (),
+        package_dir_map ()
       { }
 
     dir_info (const std::string& d)
       : dir_name (d), abs_dir_name (), is_relative (false),
         dir_mtime (), dir_time_last_checked (),
-        all_files (), fcn_files (), private_file_map (), method_file_map ()
+        all_files (), fcn_files (), private_file_map (), method_file_map (),
+        package_dir_map ()
     {
       initialize ();
     }
@@ -319,7 +344,8 @@
         dir_time_last_checked (di.dir_time_last_checked),
         all_files (di.all_files), fcn_files (di.fcn_files),
         private_file_map (di.private_file_map),
-        method_file_map (di.method_file_map) { }
+        method_file_map (di.method_file_map),
+        package_dir_map (di.package_dir_map) { }
 
     ~dir_info (void) { }
 
@@ -336,6 +362,7 @@
           fcn_files = di.fcn_files;
           private_file_map = di.private_file_map;
           method_file_map = di.method_file_map;
+          package_dir_map = di.package_dir_map;
         }
 
       return *this;
@@ -352,6 +379,7 @@
     string_vector fcn_files;
     fcn_file_map_type private_file_map;
     method_file_map_type method_file_map;
+    package_dir_map_type package_dir_map;
 
   private:
 
@@ -364,6 +392,9 @@
     void get_method_file_map (const std::string& d,
                               const std::string& class_name);
 
+    void get_package_dir (const std::string& d,
+                          const std::string& package_name);
+
     friend fcn_file_map_type get_fcn_files (const std::string& d);
   };
 
@@ -439,13 +470,125 @@
   typedef method_map_type::const_iterator const_method_map_iterator;
   typedef method_map_type::iterator method_map_iterator;
 
-  mutable dir_info_list_type dir_info_list;
+  class loader
+  {
+  public:
+    loader (const std::string& pfx = std::string ())
+      : prefix (pfx), dir_list (), fcn_map (), private_fcn_map (),
+        method_map () { }
+
+    loader (const loader& l)
+      : prefix (l.prefix), dir_list (l.dir_list),
+        private_fcn_map (l.private_fcn_map), method_map (l.method_map) { }
+
+    ~loader (void) { }
+
+    loader& operator = (const loader& l)
+    {
+      if (&l != this)
+        {
+          prefix = l.prefix;
+          dir_list = l.dir_list;
+          fcn_map = l.fcn_map;
+          private_fcn_map = l.private_fcn_map;
+          method_map = l.method_map;
+        }
+
+      return *this;
+    }
 
-  mutable fcn_map_type fcn_map;
+    void add (const dir_info& di, bool at_end)
+    {
+      if (at_end)
+        dir_list.push_back (di.dir_name);
+      else
+        dir_list.push_front (di.dir_name);
+
+      add_to_fcn_map (di, at_end);
+
+      add_to_private_fcn_map (di);
+
+      add_to_method_map (di, at_end);
+    }
+
+    void move (const dir_info& di, bool at_end);
+
+    void remove (const dir_info& di);
+
+    void clear (void)
+      {
+        dir_list.clear ();
+
+        fcn_map.clear ();
+
+        private_fcn_map.clear ();
+
+        method_map.clear ();
+      }
+
+    void display (std::ostream& out) const;
 
-  mutable private_fcn_map_type private_fcn_map;
+    std::string find_fcn (const std::string& fcn,
+                          std::string& dir_name,
+                          int type = M_FILE | OCT_FILE | MEX_FILE) const;
+
+    std::string find_private_fcn (const std::string& dir,
+                                  const std::string& fcn,
+                                  int type = M_FILE | OCT_FILE | MEX_FILE) const;
+
+    std::string find_method (const std::string& class_name,
+                             const std::string& meth,
+                             std::string& dir_name,
+                             int type = M_FILE | OCT_FILE | MEX_FILE) const;
+
+    std::list<std::string> methods (const std::string& class_name) const;
+
+    void overloads (const std::string& meth, std::list<std::string>& l) const;
+
+    string_vector fcn_names (void) const;
+
+  private:
+    void add_to_fcn_map (const dir_info& di, bool at_end);
+
+    void add_to_private_fcn_map (const dir_info& di);
+
+    void add_to_method_map (const dir_info& di, bool at_end);
+
+    void move_fcn_map (const std::string& dir,
+                       const string_vector& fcn_files, bool at_end);
+
+    void move_method_map (const std::string& dir, bool at_end);
 
-  mutable method_map_type method_map;
+    void remove_fcn_map (const std::string& dir,
+                         const string_vector& fcn_files);
+
+    void remove_private_fcn_map (const std::string& dir);
+
+    void remove_method_map (const std::string& dir);
+
+  private:
+    std::string prefix;
+
+    std::list<std::string> dir_list;
+
+    fcn_map_type fcn_map;
+
+    private_fcn_map_type private_fcn_map;
+
+    method_map_type method_map;
+  };
+
+  // <PACKAGE_NAME, LOADER>
+  typedef std::map<std::string, loader> loader_map_type;
+
+  typedef loader_map_type::const_iterator const_loader_map_iterator;
+  typedef loader_map_type::iterator loader_map_iterator;
+
+  mutable loader_map_type loader_map;
+
+  mutable loader default_loader;
+
+  mutable dir_info_list_type dir_info_list;
 
   mutable std::set<std::string> init_dirs;
 
@@ -472,12 +615,13 @@
 
   bool do_contains_canonical (const std::string& dir) const;
 
-  void move_fcn_map (const std::string& dir,
-                     const string_vector& fcn_files, bool at_end);
+  void do_move (dir_info_list_iterator i, bool at_end);
 
-  void move_method_map (const std::string& dir, bool at_end);
+  void move (const dir_info& di, bool at_end,
+             const std::string& pname = std::string ());
 
-  void move (std::list<dir_info>::iterator i, bool at_end);
+  void remove (const dir_info& di,
+               const std::string& pname = std::string ());
 
   void do_initialize (bool set_initial_path);
 
@@ -491,12 +635,6 @@
 
   void do_add (const std::string& dir, bool at_end, bool warn);
 
-  void remove_fcn_map (const std::string& dir, const string_vector& fcn_files);
-
-  void remove_private_fcn_map (const std::string& dir);
-
-  void remove_method_map (const std::string& dir);
-
   bool do_remove (const std::string& dir);
 
   void do_update (void) const;
@@ -505,23 +643,35 @@
   check_file_type (std::string& fname, int type, int possible_types,
                    const std::string& fcn, const char *who);
 
-  std::string do_find_fcn (const std::string& fcn,
-                           std::string& dir_name,
-                           int type = M_FILE | OCT_FILE | MEX_FILE) const;
+  loader& get_loader (const std::string& name) const
+  {
+    if (! name.empty ())
+      {
+        loader_map_iterator l = loader_map.find (name);
 
-  std::string do_find_private_fcn (const std::string& dir,
-                                   const std::string& fcn,
-                                   int type = M_FILE | OCT_FILE | MEX_FILE) const;
+        if (l == loader_map.end ())
+          l = loader_map.insert (loader_map.end (),
+                                 loader_map_type::value_type (name, loader (name)));
+
+        return l->second;
+      }
+
+    return default_loader;
+  }
 
   std::string do_find_method (const std::string& class_name,
                               const std::string& meth,
-                              std::string& dir_name,
-                              int type = M_FILE | OCT_FILE | MEX_FILE) const;
+                              std::string& dir_name) const;
 
   std::list<std::string> do_methods (const std::string& class_name) const;
 
   std::list<std::string> do_overloads (const std::string& meth) const;
 
+  bool do_find_package (const std::string& package_name) const
+  {
+    return (loader_map.find (package_name) != loader_map.end ());
+  }
+
   std::string do_find_file (const std::string& file) const;
 
   std::string do_find_dir (const std::string& dir) const;
@@ -555,11 +705,8 @@
 
   std::string do_get_command_line_path (void) const { return command_line_path; }
 
-  void add_to_fcn_map (const dir_info& di, bool at_end) const;
-
-  void add_to_private_fcn_map (const dir_info& di) const;
-
-  void add_to_method_map (const dir_info& di, bool at_end) const;
+  void add (const dir_info& di, bool at_end,
+            const std::string& pname = std::string ()) const;
 
   friend dir_info::fcn_file_map_type get_fcn_files (const std::string& d);
 };
--- a/libinterp/interpfcn/symtab.cc	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/interpfcn/symtab.cc	Fri May 17 23:17:25 2013 -0400
@@ -374,17 +374,24 @@
 }
 
 octave_value
-symbol_table::fcn_info::fcn_info_rep::load_class_constructor (void)
+symbol_table::fcn_info::fcn_info_rep::load_class_constructor
+  (const std::string& pname)
 {
   octave_value retval;
 
   std::string dir_name;
 
-  std::string file_name = load_path::find_method (name, name, dir_name);
+  std::string full_name = name;
+
+  if (! pname.empty ())
+    full_name = pname + "." + full_name;
+
+  std::string file_name = load_path::find_method (full_name, name, dir_name);
 
   if (! file_name.empty ())
     {
-      octave_function *fcn = load_fcn_from_file (file_name, dir_name, name);
+      octave_function *fcn = load_fcn_from_file (file_name, dir_name, name,
+                                                 pname);
 
       if (fcn)
         {
@@ -402,7 +409,7 @@
 
       octave_value old_function_on_path = function_on_path;
 
-      octave_value maybe_cdef_ctor = find_user_function ();
+      octave_value maybe_cdef_ctor = find_user_function (pname);
 
       if (maybe_cdef_ctor.is_defined ())
         {
@@ -429,7 +436,17 @@
   octave_value retval;
 
   if (name == dispatch_type)
-    retval = load_class_constructor ();
+    retval = load_class_constructor (std::string ());
+  else if (dispatch_type.length () > name.length ()
+           && dispatch_type.substr (dispatch_type.length () - name.length ()
+                                    - 1) == ("." + name))
+    {
+      std::string pname =
+        dispatch_type.substr (0,
+                              dispatch_type.length () - name.length () - 1);
+
+      retval = load_class_constructor (pname);
+    }
   else
     {
       octave_function *cm = cdef_manager::find_method_symbol (name,
@@ -647,9 +664,10 @@
 
 octave_value
 symbol_table::fcn_info::fcn_info_rep::find (const octave_value_list& args,
-                                            bool local_funcs)
+                                            bool local_funcs,
+                                            const std::string& pname)
 {
-  octave_value retval = xfind (args, local_funcs);
+  octave_value retval = xfind (args, local_funcs, pname);
 
   if (! (error_state || retval.is_defined ()))
     {
@@ -659,7 +677,7 @@
 
       load_path::update ();
 
-      retval = xfind (args, local_funcs);
+      retval = xfind (args, local_funcs, pname);
     }
 
   return retval;
@@ -667,7 +685,8 @@
 
 octave_value
 symbol_table::fcn_info::fcn_info_rep::xfind (const octave_value_list& args,
-                                             bool local_funcs)
+                                             bool local_funcs,
+                                             const std::string& pname)
 {
   if (local_funcs)
     {
@@ -750,7 +769,7 @@
 
   if (q == class_constructors.end ())
     {
-      octave_value val = load_class_constructor ();
+      octave_value val = load_class_constructor (pname);
 
       if (val.is_defined ())
         return val;
@@ -766,7 +785,7 @@
         return fval;
       else
         {
-          octave_value val = load_class_constructor ();
+          octave_value val = load_class_constructor (pname);
 
           if (val.is_defined ())
             return val;
@@ -812,7 +831,14 @@
 
   // Function on the path.
 
-  fcn = find_user_function ();
+  fcn = find_user_function (pname);
+
+  if (fcn.is_defined ())
+    return fcn;
+
+  // Package
+
+  fcn = find_package (pname);
 
   if (fcn.is_defined ())
     return fcn;
@@ -869,7 +895,7 @@
 
   // Function on the path.
 
-  octave_value fcn = find_user_function ();
+  octave_value fcn = find_user_function (std::string ());
 
   if (fcn.is_defined ())
     return fcn;
@@ -1004,7 +1030,7 @@
 
           std::string dir_name = file_name.substr (0, pos);
 
-          octave_function *fcn = load_fcn_from_file (file_name, dir_name,
+          octave_function *fcn = load_fcn_from_file (file_name, dir_name, "",
                                                      "", name, true);
 
           if (fcn)
@@ -1016,7 +1042,7 @@
 }
 
 octave_value
-symbol_table::fcn_info::fcn_info_rep::find_user_function (void)
+symbol_table::fcn_info::fcn_info_rep::find_user_function (const std::string& pname)
 {
   // Function on the path.
 
@@ -1027,11 +1053,12 @@
     {
       std::string dir_name;
 
-      std::string file_name = load_path::find_fcn (name, dir_name);
+      std::string file_name = load_path::find_fcn (name, dir_name, pname);
 
       if (! file_name.empty ())
         {
-          octave_function *fcn = load_fcn_from_file (file_name, dir_name);
+          octave_function *fcn = load_fcn_from_file (file_name, dir_name, "",
+                                                     pname);
 
           if (fcn)
             function_on_path = octave_value (fcn);
@@ -1041,6 +1068,29 @@
   return function_on_path;
 }
 
+octave_value
+symbol_table::fcn_info::fcn_info_rep::find_package (const std::string& pname)
+{
+  // FIXME: implement correct way to check out of date package
+  //if (package.is_defined ())
+  //  out_of_date_check (package);
+
+  if (! (error_state || package.is_defined ()))
+    {
+      std::string full_name = name;
+
+      if (! pname.empty ())
+        full_name = pname + "." + full_name;
+
+      octave_function * fcn = cdef_manager::find_package_symbol (full_name);
+
+      if (fcn)
+        package = octave_value (fcn);
+    }
+
+  return package;
+}
+
 // Insert INF_CLASS in the set of class names that are considered
 // inferior to SUP_CLASS.  Return FALSE if INF_CLASS is currently
 // marked as superior to  SUP_CLASS.
@@ -1176,9 +1226,10 @@
 symbol_table::find (const std::string& name,
                     const octave_value_list& args,
                     bool skip_variables,
-                    bool local_funcs)
+                    bool local_funcs,
+                    scope_id scope)
 {
-  symbol_table *inst = get_instance (xcurrent_scope);
+  symbol_table *inst = get_instance (scope);
 
   return inst
     ? inst->do_find (name, args, skip_variables, local_funcs)
@@ -1376,12 +1427,12 @@
   fcn_table_iterator p = fcn_table.find (name);
 
   if (p != fcn_table.end ())
-    return p->second.find (args, local_funcs);
+    return p->second.find (args, local_funcs, package_name);
   else
     {
       fcn_info finfo (name);
 
-      octave_value fcn = finfo.find (args, local_funcs);
+      octave_value fcn = finfo.find (args, local_funcs, package_name);
 
       if (fcn.is_defined ())
         fcn_table[name] = finfo;
--- a/libinterp/interpfcn/symtab.h	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/interpfcn/symtab.h	Fri May 17 23:17:25 2013 -0400
@@ -761,11 +761,12 @@
 
       octave_value load_private_function (const std::string& dir_name);
 
-      octave_value load_class_constructor (void);
+      octave_value load_class_constructor (const std::string& pname);
 
       octave_value load_class_method (const std::string& dispatch_type);
 
-      octave_value find (const octave_value_list& args, bool local_funcs);
+      octave_value find (const octave_value_list& args, bool local_funcs,
+                         const std::string& package_name);
 
       octave_value builtin_find (void);
 
@@ -773,16 +774,19 @@
 
       octave_value find_autoload (void);
 
-      octave_value find_user_function (void);
+      octave_value find_package (const std::string& package_name);
+
+      octave_value find_user_function (const std::string& package_name);
 
       bool is_user_function_defined (void) const
       {
         return function_on_path.is_defined ();
       }
 
-      octave_value find_function (const octave_value_list& args, bool local_funcs)
+      octave_value find_function (const octave_value_list& args, bool local_funcs,
+                                  const std::string& package_name)
       {
-        return find (args, local_funcs);
+        return find (args, local_funcs, package_name);
       }
 
       void lock_subfunction (scope_id scope)
@@ -880,6 +884,11 @@
           clear_user_function ();
       }
 
+      void clear_package (void)
+      {
+        package = octave_value ();
+      }
+
       void clear (bool force = false)
       {
         clear_map (subfunctions, force);
@@ -889,6 +898,7 @@
 
         clear_autoload_function (force);
         clear_user_function (force);
+        clear_package ();
       }
 
       void add_dispatch (const std::string& type, const std::string& fname)
@@ -935,13 +945,16 @@
 
       octave_value function_on_path;
 
+      octave_value package;
+
       octave_value built_in_function;
 
       octave_refcount<size_t> count;
 
     private:
 
-      octave_value xfind (const octave_value_list& args, bool local_funcs);
+      octave_value xfind (const octave_value_list& args, bool local_funcs,
+                          const std::string& package_name);
 
       octave_value x_builtin_find (void);
 
@@ -983,9 +996,10 @@
     }
 
     octave_value find (const octave_value_list& args = octave_value_list (),
-                       bool local_funcs = true)
+                       bool local_funcs = true,
+                       const std::string& package_name = std::string ())
     {
-      return rep->find (args, local_funcs);
+      return rep->find (args, local_funcs, package_name);
     }
 
     octave_value builtin_find (void)
@@ -1013,9 +1027,9 @@
       return rep->find_autoload ();
     }
 
-    octave_value find_user_function (void)
+    octave_value find_user_function (const std::string& pname = std::string ())
     {
-      return rep->find_user_function ();
+      return rep->find_user_function (pname);
     }
 
     bool is_user_function_defined (void) const
@@ -1024,9 +1038,10 @@
     }
 
     octave_value find_function (const octave_value_list& args = octave_value_list (),
-                                bool local_funcs = true)
+                                bool local_funcs = true,
+                                const std::string& package_name = std::string ())
     {
-      return rep->find_function (args, local_funcs);
+      return rep->find_function (args, local_funcs, package_name);
     }
 
     void lock_subfunction (scope_id scope)
@@ -1132,6 +1147,21 @@
 
   static scope_id alloc_scope (void) { return scope_id_cache::alloc (); }
 
+  static scope_id alloc_package_scope (const std::string& name)
+  {
+    scope_id retval = alloc_scope ();
+
+    if (retval != -1)
+      {
+        symbol_table* inst = get_instance (retval, true);
+
+        inst->do_cache_name (name);
+        inst->package_name = name;
+      }
+
+    return retval;
+  }
+
   static void set_scope (scope_id scope)
   {
     if (scope == xglobal_scope)
@@ -1275,7 +1305,8 @@
   find (const std::string& name,
         const octave_value_list& args = octave_value_list (),
         bool skip_variables = false,
-        bool local_funcs = true);
+        bool local_funcs = true,
+        scope_id scope = xcurrent_scope);
 
   static octave_value builtin_find (const std::string& name);
 
@@ -2312,6 +2343,10 @@
   // If true then no variables can be added.
   bool static_workspace;
 
+  // The name of the package context associated with this table. This is
+  // only used by classdef packages.
+  std::string package_name;
+
   // Map from names of global variables to values.
   static std::map<std::string, octave_value> global_table;
 
@@ -2352,7 +2387,7 @@
 
   symbol_table (scope_id scope)
     : my_scope (scope), table_name (), table (), nest_children (), nest_parent (0),
-    curr_fcn (0), static_workspace (false), persistent_table () { }
+    curr_fcn (0), static_workspace (false), package_name (), persistent_table () { }
 
   ~symbol_table (void) { }
 
--- a/libinterp/octave-value/ov-classdef.cc	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/octave-value/ov-classdef.cc	Fri May 17 23:17:25 2013 -0400
@@ -27,6 +27,7 @@
 #include <algorithm>
 
 #include "defun.h"
+#include "load-path.h"
 #include "ov-builtin.h"
 #include "ov-classdef.h"
 #include "ov-fcn-handle.h"
@@ -723,10 +724,9 @@
 make_package (const std::string& nm,
               const std::string& parent = std::string ())
 {
-  cdef_package pack ("meta.package");
+  cdef_package pack (nm);
 
   pack.set_class (cdef_class::meta_package ());
-  pack.put ("Name", nm);
   if (parent.empty ())
     pack.put ("ContainingPackage", Matrix ());
   else
@@ -779,6 +779,8 @@
                            const std::list<octave_value_list>& idx,
                            const octave_value& rhs)
 {
+  // FIXME: should check "subsasgn" method first
+
   return object.subsasgn (type, idx, rhs);
 }
 
@@ -950,7 +952,7 @@
                         {
                           // I see 2 possible implementations here:
                           // 1) use cdef_object::subsref with a different class
-                          //    context; this avoids duplicating codem but
+                          //    context; this avoids duplicating code, but
                           //    assumes the object is always the first argument
                           // 2) lookup the method manually and call
                           //    cdef_method::execute; this duplicates part of
@@ -2190,12 +2192,14 @@
 cdef_class::make_meta_class (tree_classdef* t)
 {
   cdef_class retval;
-  std::string class_name;
+  std::string class_name, full_class_name;
 
   // Class creation
 
-  class_name = t->ident ()->name ();
-  gnulib::printf ("class: %s\n", class_name.c_str ());
+  class_name = full_class_name = t->ident ()->name ();
+  if (! t->package_name ().empty ())
+    full_class_name = t->package_name () + "." + full_class_name;
+  gnulib::printf ("class: %s\n", full_class_name.c_str ());
 
   std::list<cdef_class> slist;
 
@@ -2219,7 +2223,7 @@
               else
                 {
                   ::error ("`%s' cannot inherit from `%s', because it is sealed",
-                           class_name.c_str (), sclass_name.c_str ());
+                           full_class_name.c_str (), sclass_name.c_str ());
                   return retval;
                 }
             }
@@ -2229,11 +2233,21 @@
         }
     }
 
-  retval = ::make_class (class_name, slist);
+  retval = ::make_class (full_class_name, slist);
 
   if (error_state)
     return cdef_class ();
 
+  // Package owning this class
+
+  if (! t->package_name ().empty ())
+    {
+      cdef_package pack = cdef_manager::find_package (t->package_name ());
+
+      if (! error_state && pack.ok ())
+        retval.put ("ContainingPackage", to_ov (pack));
+    }
+
   // Class attributes
 
   if (t->attribute_list ())
@@ -2770,6 +2784,89 @@
 cdef_package::cdef_package_rep::get_packages (void) const
 { return map2Cell (package_map); }
 
+octave_value
+cdef_package::cdef_package_rep::find (const std::string& nm)
+{
+  if (scope == -1)
+    scope = symbol_table::alloc_package_scope (get_name ());
+
+  return symbol_table::find (nm, octave_value_list (), true, false, scope);
+}
+
+octave_value_list
+cdef_package::cdef_package_rep::meta_subsref
+  (const std::string& type, const std::list<octave_value_list>& idx,
+   int nargout)
+{
+  octave_value_list retval;
+
+  switch (type[0])
+    {
+    case '.':
+      if (idx.front ().length () == 1)
+        {
+          std::string nm = idx.front ()(0).string_value ();
+
+          if (! error_state)
+            {
+              gnulib::printf ("meta.package query: %s\n", nm.c_str ());
+
+              octave_value o = find (nm);
+
+              if (o.is_defined ())
+                {
+                  if (o.is_function ())
+                    {
+                      octave_function* fcn = o.function_value ();
+
+                      if (! error_state)
+                        {
+                          if (type.size () == 1 ||
+                              ! fcn->is_postfix_index_handled (type[1]))
+                            {
+                              octave_value_list tmp_args;
+
+                              retval = o.do_multi_index_op (nargout,
+                                                            tmp_args);
+                            }
+                          else
+                            retval(0) = o;
+
+                          if (type.size () > 1 && idx.size () > 1)
+                            retval = retval(0).next_subsref (nargout, type,
+                                                             idx, 1);
+                        }
+                    }
+                  else if (type.size () > 1 && idx.size () > 1)
+                    retval = o.next_subsref (nargout, type, idx, 1);
+                  else
+                    retval(0) = o;
+                }
+              else
+                error ("member `%s' in package `%s' does not exist",
+                       nm.c_str (), get_name ().c_str ());
+            }
+          else
+            error ("invalid meta.package indexing, expected a symbol name");
+        }
+      else
+        error ("invalid meta.package indexing");
+      break;
+
+    default:
+      error ("invalid meta.package indexing");
+      break;
+    }
+
+  return retval;
+}
+
+void
+cdef_package::cdef_package_rep::meta_release (void)
+{
+  cdef_manager::unregister_package (wrap ());
+}
+
 cdef_class cdef_class::_meta_class = cdef_class ();
 cdef_class cdef_class::_meta_property = cdef_class ();
 cdef_class cdef_class::_meta_method = cdef_class ();
@@ -2948,11 +3045,23 @@
 
   if (it == all_classes.end ())
     {
-      // FIXME: implement this properly, take package prefix into account
-
       if (load_if_not_found)
         {
-          octave_value ov_cls = symbol_table::find (name);
+          octave_value ov_cls;
+
+          size_t pos = name.rfind ('.');
+
+          if (pos == std::string::npos)
+            ov_cls = symbol_table::find (name);
+          else
+            {
+              std::string pack_name = name.substr (0, pos);
+
+              cdef_package pack = do_find_package (pack_name, false, true);
+
+              if (pack.ok ())
+                ov_cls = pack.find (name.substr (pos+1));
+            }
 
           if (ov_cls.is_defined ())
             it = all_classes.find (name);
@@ -3001,7 +3110,8 @@
 
 cdef_package
 cdef_manager::do_find_package (const std::string& name,
-                               bool error_if_not_found)
+                               bool error_if_not_found,
+                               bool load_if_not_found)
 {
   cdef_package retval;
 
@@ -3015,8 +3125,37 @@
       if (! retval.ok ())
         error ("invalid package `%s'", name.c_str ());
     }
-  else if (error_if_not_found)
-    error ("unknown package `%s'", name.c_str ());
+  else
+    {
+      if (load_if_not_found && load_path::find_package (name))
+        {
+          size_t pos = name.find ('.');
+
+          if (pos == std::string::npos)
+            retval = make_package (name, std::string ());
+          else
+            {
+              std::string parent_name = name.substr (0, pos);
+
+              retval = make_package (name, parent_name);
+            }
+        }
+      else if (error_if_not_found)
+        error ("unknown package `%s'", name.c_str ());
+    }
+
+  return retval;
+}
+
+octave_function*
+cdef_manager::do_find_package_symbol (const std::string& pack_name)
+{
+  octave_function* retval = 0;
+
+  cdef_package pack = find_package (pack_name, false);
+
+  if (pack.ok ())
+    retval = new octave_classdef_meta (pack);
 
   return retval;
 }
--- a/libinterp/octave-value/ov-classdef.h	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/octave-value/ov-classdef.h	Fri May 17 23:17:25 2013 -0400
@@ -30,6 +30,7 @@
 #include "oct-map.h"
 #include "oct-refcount.h"
 #include "ov-base.h"
+#include "symtab.h"
 
 class cdef_object;
 class cdef_class;
@@ -1210,7 +1211,14 @@
   cdef_package_rep : public cdef_meta_object_rep
   {
   public:
-    cdef_package_rep (void) : cdef_meta_object_rep (), member_count (0) { }
+    cdef_package_rep (void)
+      : cdef_meta_object_rep (), member_count (0), scope (-1) { }
+
+    ~cdef_package_rep (void)
+      {
+        if (scope != -1)
+          symbol_table::erase_scope (scope);
+      }
 
     cdef_object_rep* copy (void) const { return new cdef_package_rep (*this); }
 
@@ -1249,7 +1257,19 @@
           delete this;
       }
 
+    octave_value_list
+    meta_subsref (const std::string& type,
+                  const std::list<octave_value_list>& idx, int nargout);
+
+    void meta_release (void);
+
+    bool meta_is_postfix_index_handled (char type) const
+      { return (type == '.'); }
+
+    octave_value find (const std::string& nm);
+
   private:
+    std::string full_name;
     std::map<std::string, cdef_class> class_map;
     std::map<std::string, octave_value> function_map;
     std::map<std::string, cdef_package> package_map;
@@ -1265,11 +1285,21 @@
     typedef std::map<std::string, cdef_package>::iterator package_iterator;
     typedef std::map<std::string, cdef_package>::const_iterator package_const_iterator;
 
+    // The symbol_table scope corresponding to this package.
+    symbol_table::scope_id scope;
+
   private:
     cdef_package_rep (const cdef_package_rep& p)
-      : cdef_meta_object_rep (p), class_map (p.class_map),
-        function_map (p.function_map), package_map (p.package_map),
-        member_count (p.member_count) { }
+      : cdef_meta_object_rep (p), full_name (p.full_name),
+        class_map (p.class_map), function_map (p.function_map),
+        package_map (p.package_map), member_count (p.member_count)
+      { }
+
+    cdef_package wrap (void)
+      {
+        refcount++;
+        return cdef_package (this);
+      }
   };
 
 public:
@@ -1318,6 +1348,8 @@
 
   std::string get_name (void) const { return get_rep ()->get_name (); }
 
+  octave_value find (const std::string& nm) { return get_rep ()->find (nm); }
+
   static const cdef_package& meta (void) { return _meta; }
 
 private:
@@ -1494,14 +1526,24 @@
     }
 
   static cdef_package find_package (const std::string& name,
-                                    bool error_if_not_found = true)
+                                    bool error_if_not_found = true,
+                                    bool load_if_not_found = true)
     {
       if (instance_ok ())
-        return instance->do_find_package (name, error_if_not_found);
+        return instance->do_find_package (name, error_if_not_found,
+                                          load_if_not_found);
 
       return cdef_package ();
     }
 
+  static octave_function* find_package_symbol (const std::string& pack_name)
+    {
+      if (instance_ok ())
+        return instance->do_find_package_symbol (pack_name);
+
+      return 0;
+    }
+
   static void register_class (const cdef_class& cls)
     {
       if (instance_ok ())
@@ -1569,7 +1611,10 @@
                                           const std::string& class_name);
 
   cdef_package do_find_package (const std::string& name,
-                                bool error_if_not_found);
+                                bool error_if_not_found,
+                                bool load_if_not_found);
+
+  octave_function* do_find_package_symbol (const std::string& pack_name);
 
   void do_register_class (const cdef_class& cls)
     { all_classes[cls.get_name ()] = cls; }
--- a/libinterp/octave-value/ov-fcn-handle.cc	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Fri May 17 23:17:25 2013 -0400
@@ -266,7 +266,7 @@
           std::string dir_name = str.substr (0, xpos);
 
           octave_function *xfcn
-            = load_fcn_from_file (str, dir_name, "", nm);
+            = load_fcn_from_file (str, dir_name, "", "", nm);
 
           if (xfcn)
             {
@@ -296,7 +296,7 @@
 
           std::string dir_name = str.substr (0, xpos);
 
-          octave_function *xfcn = load_fcn_from_file (str, dir_name, "", nm);
+          octave_function *xfcn = load_fcn_from_file (str, dir_name, "", "", nm);
 
           if (xfcn)
             {
@@ -319,7 +319,7 @@
 
           std::string dir_name = fpath.substr (0, xpos);
 
-          octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", nm);
+          octave_function *xfcn = load_fcn_from_file (fpath, dir_name, "", "", nm);
 
           if (xfcn)
             {
--- a/libinterp/parse-tree/oct-parse.in.yy	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/parse-tree/oct-parse.in.yy	Fri May 17 23:17:25 2013 -0400
@@ -1588,6 +1588,7 @@
   curr_fcn_depth = 0;
   primary_fcn_scope = -1;
   curr_class_name = "";
+  curr_package_name = "";
   function_scopes.clear ();
   primary_fcn_ptr  = 0;
   subfunction_names.clear ();
@@ -2972,7 +2973,8 @@
       int l = tok_val->line ();
       int c = tok_val->column ();
 
-      retval = new tree_classdef (a, id, sc, body, lc, tc, l, c);
+      retval = new tree_classdef (a, id, sc, body, lc, tc, curr_package_name,
+                                  l, c);
     }
 
   return retval;
@@ -3529,6 +3531,7 @@
 static octave_function *
 parse_fcn_file (const std::string& full_file, const std::string& file,
                 const std::string& dispatch_type,
+                const std::string& package_name,
                 bool require_file, bool force_script, bool autoload,    
                 bool relative_lookup, const std::string& warn_for)
 {
@@ -3562,6 +3565,7 @@
       octave_parser parser (ffile);
 
       parser.curr_class_name = dispatch_type;
+      parser.curr_package_name = package_name;
       parser.autoloading = autoload;
       parser.fcn_file_from_relative_lookup = relative_lookup;
 
@@ -3644,7 +3648,8 @@
       symbol_found = true;
 
       octave_function *fcn
-        = parse_fcn_file (full_file, file, "", true, false, false, false, "");
+        = parse_fcn_file (full_file, file, "", "", true, false, false, false,
+                          "");
 
       if (fcn)
         {
@@ -3708,6 +3713,7 @@
 octave_function *
 load_fcn_from_file (const std::string& file_name, const std::string& dir_name,
                     const std::string& dispatch_type,
+                    const std::string& package_name,
                     const std::string& fcn_name, bool autoload)
 {
   octave_function *retval = 0;
@@ -3755,7 +3761,8 @@
       // to get the help-string to use.
 
       octave_function *tmpfcn = parse_fcn_file (file.substr (0, len - 2),
-                                                nm, dispatch_type, false,
+                                                nm, dispatch_type,
+                                                package_name, false,
                                                 autoload, autoload,
                                                 relative_lookup, "");
 
@@ -3767,8 +3774,8 @@
     }
   else if (len > 2)
     {
-      retval = parse_fcn_file (file, nm, dispatch_type, true, autoload,
-                               autoload, relative_lookup, "");
+      retval = parse_fcn_file (file, nm, dispatch_type, package_name, true,
+                               autoload, autoload, relative_lookup, "");
     }
 
   if (retval)
@@ -3966,7 +3973,7 @@
   if (! error_state)
     {
       octave_function *fcn = parse_fcn_file (file_full_name, file_name,
-                                             "", require_file, true,
+                                             "", "", require_file, true,
                                              false, false, warn_for);
 
       if (! error_state)
--- a/libinterp/parse-tree/parse.h	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/parse-tree/parse.h	Fri May 17 23:17:25 2013 -0400
@@ -104,6 +104,7 @@
 load_fcn_from_file (const std::string& file_name,
                     const std::string& dir_name = std::string (),
                     const std::string& dispatch_type = std::string (),
+                    const std::string& package_name = std::string (),
                     const std::string& fcn_name = std::string (),
                     bool autoload = false);
 
@@ -148,9 +149,9 @@
       autoloading (false), fcn_file_from_relative_lookup (false),
       parsing_subfunctions (false), max_fcn_depth (0),
       curr_fcn_depth (0), primary_fcn_scope (-1),
-      curr_class_name (), function_scopes (), primary_fcn_ptr (0),
-      subfunction_names (), classdef_object (0), stmt_list (0),
-      lexer (lxr)
+      curr_class_name (), curr_package_name (), function_scopes (),
+      primary_fcn_ptr (0), subfunction_names (), classdef_object (0),
+      stmt_list (0), lexer (lxr)
   {
     init ();
   }
@@ -424,6 +425,10 @@
   // constructors.
   std::string curr_class_name;
 
+  // Name of the current package when we are parsing an element contained
+  // in a package directory (+-directory).
+  std::string curr_package_name;
+
   // A stack holding the nested function scopes being parsed.
   // We don't use std::stack, because we want the clear method. Also, we
   // must access one from the top
--- a/libinterp/parse-tree/pt-classdef.h	Sun May 12 21:47:57 2013 -0400
+++ b/libinterp/parse-tree/pt-classdef.h	Fri May 17 23:17:25 2013 -0400
@@ -598,9 +598,12 @@
   tree_classdef (tree_classdef_attribute_list *a, tree_identifier *i,
                  tree_classdef_superclass_list *sc,
                  tree_classdef_body *b, octave_comment_list *lc,
-                 octave_comment_list *tc, int l = -1, int c = -1)
+                 octave_comment_list *tc,
+                 const std::string& pn = std::string (), int l = -1,
+                 int c = -1)
     : tree_command (l, c), attr_list (a), id (i),
-      supclass_list (sc), element_list (b), lead_comm (lc), trail_comm (tc) { }
+      supclass_list (sc), element_list (b), lead_comm (lc), trail_comm (tc),
+      pack_name (pn) { }
 
   ~tree_classdef (void)
   {
@@ -623,6 +626,8 @@
   octave_comment_list *leading_comment (void) { return lead_comm; }
   octave_comment_list *trailing_comment (void) { return trail_comm; }
 
+  const std::string& package_name (void) const { return pack_name; }
+
   octave_function* make_meta_class (void);
 
   tree_classdef *dup (symbol_table::scope_id scope,
@@ -643,6 +648,8 @@
   octave_comment_list *lead_comm;
   octave_comment_list *trail_comm;
 
+  std::string pack_name;
+
   // No copying!
 
   tree_classdef (const tree_classdef&);