Mercurial > hg > octave-lyh
changeset 16048:10142aad4b9f classdef
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().
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Mon, 11 Feb 2013 15:20:00 -0500 |
parents | 14aa0b5a980c |
children | ebd2259c5df1 |
files | libinterp/interpfcn/symtab.cc libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h test/classdef/test_classdef.m |
diffstat | 4 files changed, 333 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/interpfcn/symtab.cc +++ b/libinterp/interpfcn/symtab.cc @@ -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<std::string>& plist = parent_classes (dispatch_type); - - std::list<std::string>::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<std::string>& plist = + parent_classes (dispatch_type); + + std::list<std::string>::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++; } } }
--- a/libinterp/octave-value/ov-classdef.cc +++ b/libinterp/octave-value/ov-classdef.cc @@ -25,7 +25,6 @@ #endif #include <algorithm> -#include <map> #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<std::string, cdef_class> all_classes; -static std::map<std::string, cdef_package> 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<std::string, cdef_class>::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<octave_value_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<std::string, cdef_package>::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<std::string, cdef_class>::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<std::string, cdef_package>::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;
--- a/libinterp/octave-value/ov-classdef.h +++ b/libinterp/octave-value/ov-classdef.h @@ -23,6 +23,7 @@ #if !defined (octave_classdef_h) #define octave_classdef_h 1 +#include <map> #include <set> #include <string> @@ -1039,6 +1040,13 @@ bool is_constructor (void) const; + octave_value_list + meta_subsref (const std::string& type, + const std::list<octave_value_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<std::string, cdef_class> all_classes; + + // All registered/loaded packages + std::map<std::string, cdef_package> all_packages; +}; + #endif /*
--- a/test/classdef/test_classdef.m +++ b/test/classdef/test_classdef.m @@ -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