Mercurial > octave-nkf
diff libinterp/octave-value/ov-classdef.cc @ 18263: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 | 81c1edd70bfd |
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc Sun Jan 12 15:54:43 2014 -0500 +++ b/libinterp/octave-value/ov-classdef.cc Sun Jan 12 15:54:44 2014 -0500 @@ -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);