# HG changeset patch # User Michael Goffioul # Date 1360614000 18000 # Node ID 10142aad4b9fa1c5a3e1a8351e96030708536d84 # Parent 14aa0b5a980c9c4a4731b355d2ec4ce0acbd19de Implement indirect method call: fun(obj, ...). * libinterp/octave-value/ov-classdef.h (class cdef_manager): New class. (cdef_method::cdef_method_rep::meta_subsref, cdef_method::cdef_method_rep::meta_is_postfix_index_handled): New methods. * libinterp/octave-value/ov-classdef.cc (all_packages, all_classes): Move static variables to class cdef_manager. (lookup_class (std::string, bool, bool)): Move implementation to method cdef_manager::do_find_class(). (lookup_package): Move implementation to method cdef_manager::do_find_package(). (make_class): Use cdef_manager::register_class. (make_package): Use cdef_manager::register_package and cdef_manager::find_package. (cdef_class::cdef_class_rep::meta_release): Use cdef_manager::unregister_class. (cdef_method::cdef_method_rep::meta_subsref): New method. (class cdef_manager): New class. * libinterp/interpfcn/symtab.cc (symbol_table::fcn_info::fcn_info_rep::load_class_constructor): Look for classdef constructor in normal m-files. Call find_user_function() and check whether the result is a classdef constructor. If it is, stash it as a constructor and restore the previous value of function_on_path. (symbol_table::fcn_info::fcn_info_rep::load_class_method): Look for method in classdef system, using cdef_manager::find_method_symbol(). diff -r 14aa0b5a980c -r 10142aad4b9f libinterp/interpfcn/symtab.cc --- a/libinterp/interpfcn/symtab.cc Mon Jan 28 21:56:01 2013 -0500 +++ b/libinterp/interpfcn/symtab.cc Mon Feb 11 15:20:00 2013 -0500 @@ -36,6 +36,7 @@ #include "dirfns.h" #include "input.h" #include "load-path.h" +#include "ov-classdef.h" #include "ov-fcn.h" #include "ov-usr-fcn.h" #include "pager.h" @@ -392,6 +393,31 @@ class_constructors[name] = retval; } } + else + { + // Classdef constructors can be defined anywhere in the path, not + // necessarily in @-folders. Look for a normal function and load it. + // If the loaded function is a classdef constructor, store it as such + // and restore function_on_path to its previous value. + + octave_value old_function_on_path = function_on_path; + + octave_value maybe_cdef_ctor = find_user_function (); + + if (maybe_cdef_ctor.is_defined ()) + { + octave_function *fcn = maybe_cdef_ctor.function_value (true); + + if (fcn && fcn->is_classdef_constructor ()) + { + retval = maybe_cdef_ctor; + + class_constructors[name] = retval; + + function_on_path = old_function_on_path; + } + } + } return retval; } @@ -406,43 +432,53 @@ retval = load_class_constructor (); else { - std::string dir_name; + octave_function *cm = cdef_manager::find_method_symbol (name, + dispatch_type); - std::string file_name = load_path::find_method (dispatch_type, name, - dir_name); + if (cm) + retval = octave_value (cm); - if (! file_name.empty ()) + if (! retval.is_defined ()) { - octave_function *fcn = load_fcn_from_file (file_name, dir_name, - dispatch_type); + std::string dir_name; - if (fcn) + std::string file_name = load_path::find_method (dispatch_type, name, + dir_name); + + if (! file_name.empty ()) { - retval = octave_value (fcn); + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type); - class_methods[dispatch_type] = retval; - } - } + if (fcn) + { + retval = octave_value (fcn); - if (retval.is_undefined ()) - { - // Search parent classes + class_methods[dispatch_type] = retval; + } + } - const std::list& plist = parent_classes (dispatch_type); - - std::list::const_iterator it = plist.begin (); - - while (it != plist.end ()) + if (retval.is_undefined ()) { - retval = find_method (*it); + // Search parent classes - if (retval.is_defined ()) + const std::list& plist = + parent_classes (dispatch_type); + + std::list::const_iterator it = plist.begin (); + + while (it != plist.end ()) { - class_methods[dispatch_type] = retval; - break; + retval = find_method (*it); + + if (retval.is_defined ()) + { + class_methods[dispatch_type] = retval; + break; + } + + it++; } - - it++; } } } diff -r 14aa0b5a980c -r 10142aad4b9f libinterp/octave-value/ov-classdef.cc --- a/libinterp/octave-value/ov-classdef.cc Mon Jan 28 21:56:01 2013 -0500 +++ b/libinterp/octave-value/ov-classdef.cc Mon Feb 11 15:20:00 2013 -0500 @@ -25,7 +25,6 @@ #endif #include -#include #include "defun.h" #include "ov-builtin.h" @@ -38,14 +37,12 @@ #include "pt-misc.h" #include "pt-stmt.h" #include "pt-walk.h" +#include "singleton-cleanup.h" #include "symtab.h" #include "toplev.h" #include "Array.cc" -static std::map all_classes; -static std::map all_packages; - static void gripe_method_access (const std::string& from, const cdef_method& meth) { @@ -144,41 +141,11 @@ } static cdef_class -lookup_class (const std::string& name, bool error_if_not_found = true) +lookup_class (const std::string& name, bool error_if_not_found = true, + bool load_if_not_found = true) { - std::map::iterator it = all_classes.find (name); - - if (it == all_classes.end ()) - { - // FIXME: implement this properly - - octave_value ov_cls = symbol_table::find (name); - - if (ov_cls.is_defined ()) - it = all_classes.find (name); - } - - if (it == all_classes.end ()) - { - if (error_if_not_found) - error ("class not found: %s", name.c_str ()); - } - else - { - cdef_class& cls = it->second; - - if (! cls.is_builtin ()) - { - // FIXME: check whether a class reload is needed - } - - if (cls.ok ()) - return cls; - else - all_classes.erase (it); - } - - return cdef_class (); + return cdef_manager::find_class (name, error_if_not_found, + load_if_not_found); } static cdef_class @@ -652,7 +619,7 @@ return cdef_class (); if (! name.empty ()) - all_classes[name] = cls; + cdef_manager::register_class (cls); return cls; } @@ -760,10 +727,13 @@ pack.set_class (cdef_class::meta_package ()); pack.put ("Name", nm); - pack.put ("ContainingPackage", to_ov (all_packages[parent])); + if (parent.empty ()) + pack.put ("ContainingPackage", Matrix ()); + else + pack.put ("ContainingPackage", to_ov (cdef_manager::find_package (parent))); if (! nm.empty ()) - all_packages[nm] = pack; + cdef_manager::register_package (pack); return pack; } @@ -2001,7 +1971,7 @@ void cdef_class::cdef_class_rep::meta_release (void) { - all_classes.erase (get_name ()); + cdef_manager::unregister_class (wrap ()); } void @@ -2646,24 +2616,37 @@ return false; } +octave_value_list +cdef_method::cdef_method_rep::meta_subsref + (const std::string& type, const std::list& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '(': + retval = execute (idx.front (), type.length () > 1 ? 1 : nargout, true); + break; + + default: + error ("invalid meta.method indexing"); + break; + } + + if (! error_state) + { + if (type.length () > 1 && idx.size () > 1 && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx, 1); + } + + return retval; +} + static cdef_package lookup_package (const std::string& name) { - std::map::const_iterator it = all_packages.find (name); - - if (it != all_packages.end ()) - { - cdef_package pack = it->second; - - if (pack.ok ()) - return pack; - else - error ("invalid package: %s", name.c_str ()); - } - else - error ("package not found: %s", name.c_str ()); - - return cdef_package (); + return cdef_manager::find_package (name); } static octave_value_list @@ -2944,6 +2927,102 @@ package_meta.install_class (meta_dynproperty, "dynproperty"); } +//---------------------------------------------------------------------------- + +cdef_manager* cdef_manager::instance = 0; + +void +cdef_manager::create_instance (void) +{ + instance = new cdef_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); +} + +cdef_class +cdef_manager::do_find_class (const std::string& name, + bool error_if_not_found, bool load_if_not_found) +{ + std::map::iterator it = all_classes.find (name); + + 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); + + if (ov_cls.is_defined ()) + it = all_classes.find (name); + } + } + + if (it == all_classes.end ()) + { + if (error_if_not_found) + error ("class not found: %s", name.c_str ()); + } + else + { + cdef_class cls = it->second; + + if (! cls.is_builtin ()) + cls = lookup_class (cls); + + if (cls.ok ()) + return cls; + else + all_classes.erase (it); + } + + return cdef_class (); +} + +octave_function* +cdef_manager::do_find_method_symbol (const std::string& method_name, + const std::string& class_name) +{ + octave_function *retval = 0; + + cdef_class cls = find_class (class_name, false, false); + + if (cls.ok ()) + { + cdef_method meth = cls.find_method (method_name); + + if (meth.ok ()) + retval = new octave_classdef_meta (meth); + } + + return retval; +} + +cdef_package +cdef_manager::do_find_package (const std::string& name, + bool error_if_not_found) +{ + cdef_package retval; + + std::map::const_iterator it + = all_packages.find (name); + + if (it != all_packages.end ()) + { + retval = it->second; + + if (! retval.ok ()) + error ("invalid package `%s'", name.c_str ()); + } + else if (error_if_not_found) + error ("unknown package `%s'", name.c_str ()); + + return retval; +} + +//---------------------------------------------------------------------------- + DEFUN (__meta_get_package__, args, , "") { octave_value retval; diff -r 14aa0b5a980c -r 10142aad4b9f libinterp/octave-value/ov-classdef.h --- a/libinterp/octave-value/ov-classdef.h Mon Jan 28 21:56:01 2013 -0500 +++ b/libinterp/octave-value/ov-classdef.h Mon Feb 11 15:20:00 2013 -0500 @@ -23,6 +23,7 @@ #if !defined (octave_classdef_h) #define octave_classdef_h 1 +#include #include #include @@ -1039,6 +1040,13 @@ bool is_constructor (void) const; + octave_value_list + meta_subsref (const std::string& type, + const std::list& idx, int nargout); + + bool meta_is_postfix_index_handled (char type) const + { return (type == '(' || type == '.'); } + private: cdef_method_rep (const cdef_method_rep& m) : cdef_meta_object_rep (m), function (m.function) { } @@ -1460,6 +1468,133 @@ OCTINTERP_API void install_classdef (void); +class +cdef_manager +{ +public: + + static cdef_class find_class (const std::string& name, + bool error_if_not_found = true, + bool load_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_class (name, error_if_not_found, + load_if_not_found); + + return cdef_class (); + } + + static octave_function* find_method_symbol (const std::string& method_name, + const std::string& class_name) + { + if (instance_ok ()) + return instance->do_find_method_symbol (method_name, class_name); + + return 0; + } + + static cdef_package find_package (const std::string& name, + bool error_if_not_found = true) + { + if (instance_ok ()) + return instance->do_find_package (name, error_if_not_found); + + return cdef_package (); + } + + static void register_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_register_class (cls); + } + + static void unregister_class (const cdef_class& cls) + { + if (instance_ok ()) + instance->do_unregister_class (cls); + } + + static void register_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_register_package (pkg); + } + + static void unregister_package (const cdef_package& pkg) + { + if (instance_ok ()) + instance->do_unregister_package (pkg); + } + +private: + + cdef_manager (void) { } + + cdef_manager (const cdef_manager&); + + cdef_manager& operator = (const cdef_manager&); + + ~cdef_manager (void) { } + + static void create_instance (void); + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + create_instance (); + + if (! instance) + { + ::error ("unable to create cdef_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) + { + delete instance; + + instance = 0; + } + + cdef_class do_find_class (const std::string& name, bool error_if_not_found, + bool load_if_not_found); + + octave_function* do_find_method_symbol (const std::string& method_name, + const std::string& class_name); + + cdef_package do_find_package (const std::string& name, + bool error_if_not_found); + + void do_register_class (const cdef_class& cls) + { all_classes[cls.get_name ()] = cls; } + + void do_unregister_class (const cdef_class& cls) + { all_classes.erase(cls.get_name ()); } + + void do_register_package (const cdef_package& pkg) + { all_packages[pkg.get_name ()] = pkg; } + + void do_unregister_package (const cdef_package& pkg) + { all_packages.erase(pkg.get_name ()); } + +private: + + // The single cdef_manager instance + static cdef_manager *instance; + + // All registered/loaded classes + std::map all_classes; + + // All registered/loaded packages + std::map all_packages; +}; + #endif /* diff -r 14aa0b5a980c -r 10142aad4b9f test/classdef/test_classdef.m --- a/test/classdef/test_classdef.m Mon Jan 28 21:56:01 2013 -0500 +++ b/test/classdef/test_classdef.m Mon Feb 11 15:20:00 2013 -0500 @@ -47,8 +47,7 @@ %!assert (p.rate, 4.0); %!assert (p.principle, 50e3); %!assert (p.amount, amt, eps ()) -%!xtest -%! assert (amount (p), amt, eps ()) +%!assert (amount (p), amt, eps ()) %!xtest %! assert (properties (p), {'rate'; 'term'; 'principle'}) %!xtest