diff libinterp/octave-value/ov-classdef.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 10142aad4b9f
children edbb123cbe3a
line wrap: on
line diff
--- 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;
 }