Mercurial > hg > octave-nkf
changeset 18288:b5be1a2aa5ab
Initial implementation for classdef methods in separate files.
* libinterp/octave-value/ov-classdef.h (cdef_class::make_meta_class):
New argument to tell whether the class is loaded from a @-folder.
(cdef_method::cdef_method_rep::dispatch_type): New member used for
external methods.
(cdef_method::cdef_method_rep::cdef_method_rep): Initialize it.
(cdef_method::cdef_method_rep::is_external,
cdef_method::cdef_method_rep::mark_as_external): New methods, use it.
(cdef_method::is_external, cdef_method::mark_as_external): Likewise.
* libinterp/octave-value/ov-classdef.cc (is_dummy_method): New static
method.
(make_method): Use it to initialize "external" state of created method.
(cdef_class::make_meta_class): New argument to know whether we're
loading from a @-folder. Scan existing methods from load-path and
create corresponding method entries in the class definition.
(cdef_method::cdef_method_rep::check_method): Load external method if
required.
(cdef_method::cdef_method_rep::execute): Check error_state after calling
check_method.
* libinterp/parse-tree/pt-classdef.h (tree_classdef::make_meta_class):
New argument to tell whether the class is loaded from a @-folder.
* libinterp/parse-tree/pt-classdef.cc (tree_classdef::make_meta_class):
Likewise. Pass new argument to cdef_class::make_meta_class.
* libinterp/parse-tree/oct-parse.in.yy (parse_fcn_file): Pass new
is_at_folder argument.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Sun, 12 Jan 2014 15:54:44 -0500 |
parents | 69990d5edcc2 |
children | 75d7cde2dda4 |
files | libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/pt-classdef.cc libinterp/parse-tree/pt-classdef.h |
diffstat | 5 files changed, 139 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc +++ b/libinterp/octave-value/ov-classdef.cc @@ -32,6 +32,7 @@ #include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-typeinfo.h" +#include "ov-usr-fcn.h" #include "pt-assign.h" #include "pt-classdef.h" #include "pt-funcall.h" @@ -360,6 +361,27 @@ return false; } +static bool +is_dummy_method (const octave_value& fcn) +{ + bool retval = false; + + if (fcn.is_defined ()) + { + if (fcn.is_user_function ()) + { + octave_user_function *uf = fcn.user_function_value (true); + + if (! uf || ! uf->body ()) + retval = true; + } + } + else + retval = true; + + return retval; +} + bool is_method_executing (const octave_value& ov, const cdef_object& obj) { @@ -763,6 +785,9 @@ meth.set_function (fcn); + if (is_dummy_method (fcn)) + meth.mark_as_external (cls.get_name ()); + return meth; } @@ -2455,7 +2480,7 @@ } cdef_class -cdef_class::make_meta_class (tree_classdef* t) +cdef_class::make_meta_class (tree_classdef* t, bool is_at_folder) { cdef_class retval; std::string class_name, full_class_name; @@ -2598,6 +2623,43 @@ } } + if (is_at_folder) + { + // Look for all external methods visible on octave path at the + // time of loading of the class. + // + // TODO: This is an "extension" to Matlab behavior, which only + // looks in the @-folder containing the original classdef + // file. However, this is easier to implement it that way at + // the moment. + + std::list<std::string> external_methods = + load_path::methods (full_class_name); + + for (std::list<std::string>::const_iterator it = external_methods.begin (); + it != external_methods.end (); ++it) + { + // TODO: should we issue a warning if the method is already + // defined in the classdef file? + + if (*it != class_name + && ! retval.find_method (*it, true).ok ()) + { + // Create a dummy method that is used until the actual + // method is loaded. + + octave_user_function *fcn = new octave_user_function (); + + fcn->stash_function_name (*it); + + cdef_method meth = make_method (retval, *it, + octave_value (fcn)); + + retval.install_method (meth); + } + } + } + // Property blocks // FIXME: default property expression should be able to call static @@ -2847,7 +2909,49 @@ void cdef_method::cdef_method_rep::check_method (void) { - // FIXME: check whether re-load is needed + if (is_external ()) + { + if (is_dummy_method (function)) + { + std::string name = get_name (); + std::string cls_name = dispatch_type; + std::string pack_name; + + size_t pos = cls_name.rfind ('.'); + + if (pos != std::string::npos) + { + pack_name = cls_name.substr (0, pos); + cls_name = cls_name.substr (pos + 1); + } + + std::string dir_name; + std::string file_name = load_path::find_method (cls_name, name, + dir_name, pack_name); + + if (! file_name.empty ()) + { + octave_function *fcn = load_fcn_from_file (file_name, dir_name, + dispatch_type, + pack_name); + + if (fcn) + { + function = octave_value (fcn); + + make_function_of_class (dispatch_type, function); + } + } + } + else + { + // FIXME: check out-of-date status + } + + if (is_dummy_method (function)) + ::error ("no definition found for method `%s' of class `%s'", + get_name ().c_str (), dispatch_type.c_str ()); + } } octave_value_list @@ -2868,7 +2972,7 @@ { check_method (); - if (function.is_defined ()) + if (! error_state && function.is_defined ()) { retval = execute_ov (function, args, nargout); } @@ -2899,10 +3003,10 @@ { check_method (); - octave_value_list new_args; - - if (function.is_defined ()) + if (! error_state && function.is_defined ()) { + octave_value_list new_args; + new_args.resize (args.length () + 1); new_args(0) = to_ov (obj);
--- a/libinterp/octave-value/ov-classdef.h +++ b/libinterp/octave-value/ov-classdef.h @@ -827,7 +827,8 @@ void delete_object (cdef_object obj) { get_rep ()->delete_object (obj); } - static cdef_class make_meta_class (tree_classdef* t); + static cdef_class make_meta_class (tree_classdef* t, + bool is_at_folder = false); octave_function* get_method_function (const std::string& nm); @@ -1019,7 +1020,9 @@ cdef_method_rep : public cdef_meta_object_rep { public: - cdef_method_rep (void) : cdef_meta_object_rep () { } + cdef_method_rep (void) + : cdef_meta_object_rep (), function (), dispatch_type () + { } cdef_object_rep* copy (void) const { return new cdef_method_rep(*this); } @@ -1037,6 +1040,11 @@ bool check_access (void) const; + bool is_external (void) const { return ! dispatch_type.empty (); } + + void mark_as_external (const std::string& dtype) + { dispatch_type = dtype; } + octave_value_list execute (const octave_value_list& args, int nargout, bool do_check_access = true, const std::string& who = std::string ()); @@ -1057,7 +1065,9 @@ private: cdef_method_rep (const cdef_method_rep& m) - : cdef_meta_object_rep (m), function (m.function) { } + : cdef_meta_object_rep (m), function (m.function), + dispatch_type (m.dispatch_type) + { } void check_method (void); @@ -1069,6 +1079,10 @@ private: octave_value function; + + // When non-empty, the method is externally defined and this member + // is used to cache the dispatch type to look for the method. + std::string dispatch_type; }; public: @@ -1125,6 +1139,11 @@ bool is_constructor (void) const { return get_rep ()->is_constructor (); } + bool is_external (void) const { return get_rep ()->is_external (); } + + void mark_as_external (const std::string& dtype) + { get_rep ()->mark_as_external (dtype); } + private: cdef_method_rep* get_rep (void) { return dynamic_cast<cdef_method_rep *> (cdef_object::get_rep ()); }
--- a/libinterp/parse-tree/oct-parse.in.yy +++ b/libinterp/parse-tree/oct-parse.in.yy @@ -3841,7 +3841,10 @@ if (fcn_ptr) panic_impossible (); - fcn_ptr = parser.classdef_object->make_meta_class (); + bool is_at_folder = ! dispatch_type.empty (); + + fcn_ptr = + parser.classdef_object->make_meta_class (is_at_folder); } else if (fcn_ptr) {
--- a/libinterp/parse-tree/pt-classdef.cc +++ b/libinterp/parse-tree/pt-classdef.cc @@ -233,10 +233,10 @@ // Classdef octave_function* -tree_classdef::make_meta_class (void) +tree_classdef::make_meta_class (bool is_at_folder) { octave_value retval; - cdef_class cls = cdef_class::make_meta_class (this); + cdef_class cls = cdef_class::make_meta_class (this, is_at_folder); if (cls.ok ()) return cls.get_constructor_function ();
--- a/libinterp/parse-tree/pt-classdef.h +++ b/libinterp/parse-tree/pt-classdef.h @@ -628,7 +628,7 @@ const std::string& package_name (void) const { return pack_name; } - octave_function* make_meta_class (void); + octave_function* make_meta_class (bool is_at_folder = false); tree_classdef *dup (symbol_table::scope_id scope, symbol_table::context_id context) const;