diff libinterp/interpfcn/load-path.cc @ 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 68176102fe07
children edbb123cbe3a
line wrap: on
line diff
--- 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 ();
+}