Mercurial > hg > octave-lojdl
changeset 15869:5e5705b3e505 classdef
Implement some embryonic handle-classdef semantic.
* libinterp/octave-value/ov-classdef.h (cdef_object_rep::subsasgn,
handle_cdef_object::subsasgn, octave_classdef::subsasgn): New method
declarations.
(handle_cdef_object::~handle_cdef_object): New destructor declaration.
(cdef_class::cdef_class_rep::handle_class): New boolean field.
(cdef_class::cdef_class_rep::cdef_class_rep): Initialize it.
(cdef_class::cdef_class_rep::mark_as_handle_class,
cdef_class::cdef_class_rep::is_handle_class, cdef_class::mark_as_handle_class,
cdef_class::is_handle_class): Manipulate it.
(cdef_class::cdef_class_rep::get_name): New method.
(cdef_class::get_name): Use it.
(cdef_class::cdef_class_rep::initialize_object,
cdef_class::cdef_class_rep::subsref_meta,
cdef_class::cdef_class_rep::run_constructor,
cdef_class::cdef_class_rep::construct, cdef_class:initialize_object,
cdef_class::subsref_meta, cdef_class::run_constructor, cdef_class::construct):
New methods.
(cdef_class::cdef_class_rep::find_method, cdef_class::find_method):
Add "local" argument.
(cdef_class::cdef_class_rep::find_names, cdef_class::find_names): Change
signature to use std::set and a boolean flag.
(cdef_class::cdef_class_rep::find_methods, cdef_class::find_methods): Change
signature to use a boolean flag as second argument.
(cdef_class::make_meta_class): New static method.
(cdef_class::get_method_function, cdef_class::get_constructor_function): New
methods.
(cdef_property::cdef_property_rep::set_value, cdef_property::set_value):
Make cdef_object argument non const.
(cdef_property::cder_property_rep::is_relative_set): New method.
(cdef_property::get_get_access, cdef_property::get_set_access): Delete methods.
(cdef_property::check_get_access, cdef_property::check_set_access):
Remove string argument.
(cdef_method::get_access): Delete method.
(cdef_method::check_access): Remove string argument.
* libinterp/octave-value/ov-classdef.cc (gripe_method_access,
gripe_property_access): Support access specified as cell array of classes.
(make_function_of_class): New static function(s).
(check_access (std::string, std::string), superclass_access): Remove static
functions.
(lookup_class): Use symbol_table when class hasn't been loaded yet.
(lookup_classes): Returns std::list<cdef_class> instead of Cell.
(class_get_superclasses, class_get_inferiorclasses): Use it.
(to_ov (const std::list<cdef_class>&)): New static function.
(get_class_context, check_access (const cdef_class&, const octave_value&)):
Likewise.
(handle_cdef_object::subsref): Use new signature of access check methods.
(property_get_defaultvalue): New built-in property accessor.
(make_class): Change signature to support multiple inheritance. Set "Sealed" to
false by default. Determine value for HandleCompatible property and handle-class
representation.
(make_property): Take cdef_class as first argument. Add DefaultValue and
HasDefault properties. Call make_function_of_class for property accessors.
(make_attribute): Take cdef_class as first argument.
(make_method): Likewise. Call make_function_of_class.
(make_method (octave_builtin::fcn)): Do no construct a function handle object.
(octave_classdef::subsasgn, handle_cdef_object::subsasgn): New method.
(class octave_classdef_proxy): New class.
(cdef_class::get_method_function): Use it, new method.
(handle_cdef_object::~handle_cdef_object): New destructor.
(cdef_class_rep::find_method): New boolean "local" argument. When true, only
look into the current class, not in superclasses.
(cdef_class_rep::find_methods): New signature.
(cdef_class_rep::get_methods): Use it.
(cdef_class_rep::find_properties): New signature.
(cdef_class_rep::get_properties): Use it.
(cdef_class_rep::find_names): New signature.
(cdef_class_rep::get_names): Use it.
(cdef_class_rep::subsref_meta, cdef_class_rep::initialize_object,
cdef_class_rep::run_constructor, cdef_class_rep::construct): New methods.
(compute_attribute_value, attribute_to_string): New static functions.
(cdef_class::make_meta_class): Change signature, non const argument.
Implement it.
(cdef_property_rep::get_value): Do not check access here.
(cdef_property_rep::set_value, cdef_property_rep::is_recursive_set): New method.
(cdef_property_rep::check_get_access, cdef_property_rep::check_set_access,
cdef_method_rep::check_access): Use static check_access utility function.
(install_classdef): Adapt to change of signature of make_class. Mark meta
classes as sealed. Add HandleCompatible property to meta.class. Add
DefaultValue and HasDefault properties to meta.property.
* libinterp/parse-tree/pt-classdef.h (tree_classdef::make_meta_class):
Change return type to (octave_function *).
* libinterp/parse-tree/pt-classdef.cc (tree_classdef::make_meta_class):
Likewise. Call cdef_class::get_constructor_function.
* libinterp/parse-tree/oct-parse.yy (parse_fcn_file): Adapt to new
signature of tree_classdef::make_meta_class.
* libinterp/octave-value/ov-fcn.h (octave_function::is_classdef_constructor):
New virtual method.
* libinterp/octave-value/ov-usr-fcn.h
(octave_user_function::class_ctor_type): New private enum.
(octave_user_function::mark_as_class_constructor,
octave_user_function::is_class_constructor): Use it.
(octave_user_function::mark_as_classdef_constructor,
octave_user_function::is_classdef_constructor): New methods.
(octave_user_function::class_constructor): Turn into class_ctor_type.
* libinterp/octave-value/of-usr-fcn.cc
(octave_user_function::octave_user_function): Initialize class_constructor.
(octave_user_function::do_multi_index_op): When function is a classdef
constructor, extract the first argument and use it to populate the first
output argument.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Tue, 01 Jan 2013 19:42:17 -0500 |
parents | 622f3f794162 |
children | 2b6fe094e615 |
files | libinterp/octave-value/ov-classdef.cc libinterp/octave-value/ov-classdef.h libinterp/octave-value/ov-fcn.h libinterp/octave-value/ov-usr-fcn.cc libinterp/octave-value/ov-usr-fcn.h libinterp/parse-tree/oct-parse.yy libinterp/parse-tree/pt-classdef.cc libinterp/parse-tree/pt-classdef.h |
diffstat | 8 files changed, 1075 insertions(+), 232 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc +++ b/libinterp/octave-value/ov-classdef.cc @@ -32,6 +32,9 @@ #include "ov-fcn-handle.h" #include "ov-typeinfo.h" #include "pt-classdef.h" +#include "pt-walk.h" +#include "symtab.h" +#include "toplev.h" static std::map<std::string, cdef_class> all_classes; static std::map<std::string, cdef_package> all_packages; @@ -39,23 +42,78 @@ static void gripe_method_access (const std::string& from, const cdef_method& meth) { + octave_value acc = meth.get ("Access"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + error ("%s: method `%s' has %s access and cannot be run in this context", - from.c_str (), meth.get_name ().c_str (), - meth.get_access ().c_str ()); + from.c_str (), meth.get_name ().c_str (), acc_s.c_str ()); } static void gripe_property_access (const std::string& from, const cdef_property& prop, bool is_set = false) { + octave_value acc = prop.get (is_set ? "SetAccess" : "GetAccess"); + std::string acc_s; + + if (acc.is_string ()) + acc_s = acc.string_value (); + else + acc_s = "class-restricted"; + if (is_set) error ("%s: property `%s' has %s access and cannot be set in this context", - from.c_str (), prop.get_name ().c_str (), - prop.get_set_access ().c_str ()); + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); else error ("%s: property `%s' has %s access and cannot be obtained in this context", - from.c_str (), prop.get_name ().c_str (), - prop.get_get_access ().c_str ()); + from.c_str (), prop.get_name ().c_str (), acc_s.c_str ()); +} + +static std::string +get_base_name (const std::string& nm) +{ + std::string::size_type pos = nm.find_last_of ('.'); + + if (pos != std::string::npos) + return nm.substr (pos + 1); + + return nm; +} + +static void +make_function_of_class (const std::string& class_name, + const octave_value& fcn) +{ + octave_function *of = fcn.function_value (); + + if (! error_state) + { + of->stash_dispatch_class (class_name); + + octave_user_function *uf = of->user_function_value (true); + + if (! error_state && uf) + { + if (get_base_name (class_name) == uf->name ()) + { + uf->mark_as_class_constructor (); + uf->mark_as_classdef_constructor (); + } + else + uf->mark_as_class_method (); + } + } +} + +static void +make_function_of_class (const cdef_class& cls, const octave_value& fcn) +{ + make_function_of_class (cls.get_name (), fcn); } static octave_value @@ -78,37 +136,6 @@ return val.subsref (type, idx, nargout); } -static bool -check_access (const std::string& req, const std::string& acc) -{ - if (req == "private") - return true; - else if (req == "protected") - return (acc != "private"); - else - return (acc == "public"); -} - -static std::string -get_base_name (const std::string& nm) -{ - std::string::size_type pos = nm.find_last_of ('.'); - - if (pos != std::string::npos) - return nm.substr (pos + 1); - - return nm; -} - -static std::string -superclass_access (const std::string& acc) -{ - if (acc == "public") - return acc; - else - return "protected"; -} - static cdef_class lookup_class (const std::string& name, bool error_if_not_found = true) { @@ -116,7 +143,16 @@ if (it == all_classes.end ()) { - // FIXME: should look into load-path + // 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 ()); } @@ -138,22 +174,38 @@ return cdef_class (); } -static Cell +static std::list<cdef_class> lookup_classes (const Cell& cls_names) { - Cell cls (cls_names.numel (), 1); + std::list<cdef_class> retval; for (int i = 0; i < cls_names.numel (); i++) { cdef_class c = lookup_class (cls_names(i).string_value ()); if (! error_state) - cls(i) = to_ov (c); + retval.push_back (c); else - return Cell (); + { + retval.clear (); + break; + } } - return cls; + return retval; +} + +static octave_value +to_ov (const std::list<cdef_class>& class_list) +{ + Cell cls (class_list.size (), 1); + int i = 0; + + for (std::list<cdef_class>::const_iterator it = class_list.begin (); + it != class_list.end (); ++it, ++i) + cls(i) = to_ov (*it); + + return octave_value (cls); } static bool @@ -199,6 +251,72 @@ return retval; } +static cdef_class +get_class_context (void) +{ + cdef_class cls; + + octave_function* fcn = octave_call_stack::current (); + + if (fcn && + (fcn->is_class_method () + || fcn->is_class_constructor () + || fcn->is_anonymous_function_of_class () + || (fcn->is_private_function () + && ! fcn->dispatch_class ().empty ()))) + cls = lookup_class (fcn->dispatch_class ()); + + return cls; +} + +static bool +check_access (const cdef_class& cls, const octave_value& acc) +{ + if (acc.is_string ()) + { + std::string acc_s = acc.string_value (); + + if (acc_s == "public") + return true; + + cdef_class ctx = get_class_context (); + + if (acc_s == "private") + return (ctx == cls); + else if (acc_s == "protected") + return is_superclass (cls, ctx); + else + panic_impossible (); + } + else if (acc.is_cell ()) + { + Cell acc_c = acc.cell_value (); + + cdef_class ctx = get_class_context (); + + if (ctx == cls) + return true; + + for (int i = 0; ! error_state && i < acc.numel (); i++) + { + cdef_class acc_cls (to_cdef (acc_c(i))); + + if (! error_state) + { + if (is_superclass (acc_cls, ctx)) + return true; + } + } + + return false; + } + else + error ("invalid property/method access in class `%s'", + cls.get_name ().c_str ()); + + return false; +} + static octave_value_list class_get_methods (const octave_value_list& args, int /* nargout */) { @@ -226,7 +344,7 @@ Cell classes = cls.get ("SuperClasses").cell_value (); - retval(0) = lookup_classes (classes); + retval(0) = to_ov (lookup_classes (classes)); } return retval; @@ -244,7 +362,7 @@ Cell classes = cls.get ("InferiorClasses").cell_value (); - retval(0) = lookup_classes (classes); + retval(0) = to_ov (lookup_classes (classes)); } return retval; @@ -289,8 +407,7 @@ if (meth.ok ()) { - // FIXME: can the context be something else? - if (meth.check_access ("public")) + if (meth.check_access ()) { if (meth.is_static ()) retval = meth.execute (args.splice (0, 2), nargout); @@ -336,8 +453,7 @@ if (prop.ok ()) { - // FIXME: can the context be something else? - if (prop.check_get_access ("public")) + if (prop.check_get_access ()) { if (prop.is_constant ()) retval(0) = prop.get_value (); @@ -396,6 +512,26 @@ META_CLASS_CMP (eq, clsa, clsb, operator==) META_CLASS_CMP (ne, clsa, clsb, operator!=) +octave_value_list +property_get_defaultvalue (const octave_value_list& args, int /* nargout */) +{ + octave_value_list retval; + + if (args.length () == 1 && args(0).type_name () == "object") + { + cdef_property prop (to_cdef (args(0))); + + retval(0) = prop.get ("DefaultValue"); + + if (! retval(0).is_defined ()) + error_with_id ("Octave:class:NotDefaultDefined", + "no default value for property `%s'", + prop.get_name ().c_str ()); + } + + return retval; +} + static octave_value_list handle_delete (const octave_value_list& /* args */, int /* nargout */) { @@ -407,11 +543,12 @@ } static cdef_class -make_class (const std::string& name, const std::string& super = std::string()) +make_class (const std::string& name, + const std::list<cdef_class>& super_list = std::list<cdef_class> (), + const std::list<std::string>& super_name_list = std::list<std::string> ()) { cdef_class cls ("meta.class"); - all_classes[name] = cls; cls.put ("ConstructOnLoad", false); cls.put ("ContainingPackage", Matrix ()); cls.put ("Description", std::string ()); @@ -422,17 +559,68 @@ cls.put ("Methods", Cell ()); cls.put ("Name", name); cls.put ("Properties", Cell ()); - cls.put ("Sealed", true); - if (super.empty ()) - cls.put ("SuperClasses", Cell ()); + cls.put ("Sealed", false); + if (super_name_list.size () == super_list.size ()) + cls.put ("SuperClasses", Cell (super_name_list)); + else + { + std::list<std::string> snamelist; + + for (std::list<cdef_class>::const_iterator it = super_list.begin (); + it != super_list.end (); ++it) + snamelist.push_back (it->get_name ()); + + cls.put ("SuperClasses", Cell (snamelist)); + } + + if (name == "handle") + { + cls.put ("HandleCompatible", true); + cls.mark_as_handle_class (); + } + else if (super_list.empty ()) + { + cls.put ("HandleCompatible", false); + } else - cls.put ("SuperClasses", Cell (octave_value (super))); + { + bool all_handle_compatible = true; + bool has_handle_class = false; + + for (std::list<cdef_class>::const_iterator it = super_list.begin (); + it != super_list.end (); ++it) + { + all_handle_compatible = all_handle_compatible && it->get ("HandleCompatible").bool_value (); + has_handle_class = has_handle_class || it->is_handle_class (); + } + + if (has_handle_class && ! all_handle_compatible) + ::error ("%s: cannot mix handle and non-HandleCompatible classes", + name.c_str ()); + else + { + cls.put ("HandleCompatible", all_handle_compatible); + if (has_handle_class) + cls.mark_as_handle_class (); + } + } + + if (error_state) + return cdef_class (); + + all_classes[name] = cls; return cls; } +static cdef_class +make_class (const std::string& name, const cdef_class& super) +{ + return make_class (name, std::list<cdef_class> (1, super)); +} + static cdef_property -make_property (const cdef_object& cls, const std::string& name, +make_property (const cdef_class& cls, const std::string& name, const octave_value& get_method = Matrix (), const std::string& get_access = "public", const octave_value& set_method = Matrix (), @@ -457,19 +645,29 @@ prop.put ("GetMethod", get_method); prop.put ("SetMethod", set_method); prop.put ("DefiningClass", to_ov (cls)); + prop.put ("DefaultValue", octave_value ()); + prop.put ("HasDefault", false); + + std::string class_name = cls.get_name (); + + if (! get_method.is_empty ()) + make_function_of_class (class_name, get_method); + if (! set_method.is_empty ()) + make_function_of_class (class_name, set_method); return prop; } inline cdef_property -make_attribute (const cdef_object& cls, const std::string& name) +make_attribute (const cdef_class& cls, const std::string& name) { return make_property (cls, name, Matrix (), "public", Matrix (), "private"); } static cdef_method -make_method (const cdef_object& cls, const std::string& name, const octave_value& fcn, - const std::string& m_access = "public", bool is_static = false) +make_method (const cdef_class& cls, const std::string& name, + const octave_value& fcn,const std::string& m_access = "public", + bool is_static = false) { cdef_method meth ("meta.method"); @@ -483,20 +681,21 @@ meth.put ("Sealed", true); meth.put ("Static", is_static); + make_function_of_class (cls, fcn); + meth.set_function (fcn); return meth; } inline cdef_method -make_method (const cdef_object& cls, const std::string& name, octave_builtin::fcn ff, - const std::string& m_access = "public", bool is_static = false) +make_method (const cdef_class& cls, const std::string& name, + octave_builtin::fcn ff, const std::string& m_access = "public", + bool is_static = false) { octave_value fcn (new octave_builtin (ff, name)); - octave_value fcn_handle (new octave_fcn_handle (fcn, name)); - - return make_method (cls, name, fcn_handle, m_access, is_static); + return make_method (cls, name, fcn, m_access, is_static); } static cdef_package @@ -512,6 +711,8 @@ return pack; } +//---------------------------------------------------------------------------- + DEFINE_OCTAVE_ALLOCATOR (octave_classdef); int octave_classdef::t_id (-1); @@ -525,6 +726,72 @@ (octave_classdef::t_name, "<unknown>", octave_value (new octave_classdef ())); } +octave_value_list +octave_classdef::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) +{ + int skip = 0; + octave_value_list retval; + + // FIXME: should check "subsref" method first + + retval = object.subsref (type, idx, nargout, skip); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +octave_value +octave_classdef::subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs) +{ + return object.subsasgn (type, idx, rhs); +} + +//---------------------------------------------------------------------------- + +class octave_classdef_proxy : public octave_function +{ +public: + octave_classdef_proxy (const cdef_class& _klass) + : klass (_klass) { } + + ~octave_classdef_proxy (void) { } + + octave_value_list + subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) + { return klass.subsref_meta (type, idx, nargout); } + + octave_value + subsref (const std::string& type, + const std::list<octave_value_list>& idx) + { + octave_value_list retval; + + retval = subsref (type, idx, 1); + + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + octave_value_list + do_multi_index_op (int /* nargout */, const octave_value_list& /* idx */) + { return to_ov (klass); } + +private: + cdef_class klass; +}; + +//---------------------------------------------------------------------------- + cdef_class cdef_object_rep::get_class (void) const { @@ -544,6 +811,11 @@ return string_vector (); } +handle_cdef_object::~handle_cdef_object (void) +{ + printf ("deleting %s object (handle)\n", cname.c_str ()); +} + octave_value_list handle_cdef_object::subsref (const std::string& type, const std::list<octave_value_list>& idx, @@ -564,17 +836,11 @@ { std::string name = (idx.front ())(0).string_value (); - // FIXME: get the right context; context should also - // be linked to the current executing class (if any) - // such that protected/private methods found in inherited - // classes are correctly resolved. - std::string context = "public"; - cdef_method meth = cls.find_method (name); if (meth.ok ()) { - if (meth.check_access (context)) + if (meth.check_access ()) { int _nargout = (type.length () > 2 ? 1 : nargout); @@ -609,7 +875,7 @@ if (prop.ok ()) { - if (prop.check_get_access (context)) + if (prop.check_get_access ()) { refcount++; retval(0) = prop.get_value (cdef_object (this)); @@ -632,8 +898,67 @@ return retval; } +octave_value +handle_cdef_object::subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs) +{ + octave_value retval; + + cdef_class cls = get_class (); + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + if (! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (type.length () == 1) + { + if (prop.check_set_access ()) + { + refcount++; + + cdef_object obj (this); + + prop.set_value (obj, rhs); + + if (! error_state) + retval = to_ov (obj); + } + else + gripe_property_access ("subsasgn", prop, true); + } + else + { + } + + if (! error_state) + { + } + } + else + error ("subsasgn: unknown property: %s", name.c_str ()); + } + } + break; + + default: + panic_impossible (); + break; + } + + return retval; +} + cdef_method -cdef_class::cdef_class_rep::find_method (const std::string& nm) +cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local) { method_iterator it = method_map.find (nm); @@ -651,21 +976,24 @@ return meth; } - // Look into superclasses - - Cell super_classes = get ("SuperClasses").cell_value (); + if (! local) + { + // Look into superclasses - for (int i = 0; i < super_classes.numel (); i++) - { - cdef_class cls = lookup_class (super_classes(i).string_value ()); + Cell super_classes = get ("SuperClasses").cell_value (); - if (! error_state) - { - cdef_method meth = cls.find_method (nm); + for (int i = 0; i < super_classes.numel (); i++) + { + cdef_class cls = lookup_class (super_classes(i).string_value ()); - if (meth.ok ()) - return meth; - } + if (! error_state) + { + cdef_method meth = cls.find_method (nm); + + if (meth.ok ()) + return meth; + } + } } return cdef_method (); @@ -688,22 +1016,17 @@ { std::map<std::string,cdef_method> meths; - std::map<std::string,int> count; - - count["public"] = count["protected"] = count["private"] = 0; - - find_methods (meths, count); + find_methods (meths, false); if (! error_state) { - Cell c (count["public"] + count["protected"], 1); + Cell c (meths.size (), 1); int idx = 0; for (std::map<std::string,cdef_method>::const_iterator it = meths.begin (); - it != meths.end (); ++it) - if (::check_access ("protected", it->second.get_access ())) - c (idx++, 0) = to_ov (it->second); + it != meths.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); return c; } @@ -712,24 +1035,35 @@ } void -cdef_class::cdef_class_rep::find_methods (std::map<std::string,cdef_method>& meths, - std::map<std::string,int>& count) +cdef_class::cdef_class_rep::find_methods (std::map<std::string, cdef_method>& meths, + bool only_inherited) { load_all_methods (); method_const_iterator it; + std::string cls_name = get_base_name (get_name ()); + for (it = method_map.begin (); it != method_map.end (); ++it) { std::string nm = it->second.get_name (); - if (meths.find (nm) == meths.end ()) - { - std::string acc = it->second.get_access (); + if (nm != cls_name) + { + if (meths.find (nm) == meths.end ()) + { + if (only_inherited) + { + octave_value acc = it->second.get ("Access"); - meths[nm] = it->second; - count[acc]++; - } + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } + + meths[nm] = it->second; + } + } } // Look into superclasses @@ -741,7 +1075,7 @@ cdef_class cls = lookup_class (super_classes(i).string_value ()); if (! error_state) - cls.get_rep ()->find_methods (meths, count); + cls.get_rep ()->find_methods (meths, true); else break; } @@ -791,22 +1125,17 @@ { std::map<std::string,cdef_property> props; - std::map<std::string,int> count; - - count["public"] = count["protected"] = count["private"] = 0; - - find_properties (props, count); + find_properties (props, false); if (! error_state) { - Cell c (count["public"] + count["protected"], 1); + Cell c (props.size (), 1); int idx = 0; for (std::map<std::string,cdef_property>::const_iterator it = props.begin (); - it != props.end (); ++it) - if (::check_access ("protected", it->second.get_get_access ())) - c (idx++, 0) = to_ov (it->second); + it != props.end (); ++it, ++idx) + c (idx, 0) = to_ov (it->second); return c; } @@ -816,20 +1145,27 @@ void cdef_class::cdef_class_rep::find_properties (std::map<std::string,cdef_property>& props, - std::map<std::string,int>& count) + bool only_inherited) { property_const_iterator it; - for (it = property_map.begin (); it != property_map.end (); ++it) + for (it = property_map.begin (); ! error_state && it != property_map.end (); + ++it) { std::string nm = it->second.get_name (); if (props.find (nm) == props.end ()) { - std::string acc = it->second.get_get_access (); + if (only_inherited) + { + octave_value acc = it->second.get ("GetAccess"); + + if (! acc.is_string () + || acc.string_value () == "private") + continue; + } props[nm] = it->second; - count[acc]++; } } @@ -837,61 +1173,72 @@ Cell super_classes = get ("SuperClasses").cell_value (); - for (int i = 0; i < super_classes.numel (); i++) + for (int i = 0; ! error_state && i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i).string_value ()); if (! error_state) - cls.get_rep ()->find_properties (props, count); + cls.get_rep ()->find_properties (props, true); else break; } } void -cdef_class::cdef_class_rep::find_names (std::map<std::string,std::string>& names, - std::map<std::string,int>& count) +cdef_class::cdef_class_rep::find_names (std::set<std::string>& names, + bool all) { load_all_methods (); + std::string cls_name = get_base_name (get_name ()); + for (method_const_iterator it = method_map.begin (); - it != method_map.end(); ++it) + ! error_state && it != method_map.end(); ++it) { std::string nm = it->second.get_name (); - if (names.find (nm) == names.end ()) - { - std::string acc = it->second.get_access (); + if (nm != cls_name) + { + if (! all) + { + octave_value acc = it->second.get ("Access"); - names[nm] = acc; - count[acc]++; - } + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); + } } for (property_const_iterator it = property_map.begin (); - it != property_map.end (); ++it) + ! error_state && it != property_map.end (); ++it) { std::string nm = it->second.get_name (); - if (names.find (nm) == names.end ()) - { - std::string acc = it->second.get_get_access (); + if (! all) + { + octave_value acc = it->second.get ("GetAccess"); - names[nm] = acc; - count[acc]++; - } + if (! acc.is_string() + || acc.string_value () != "public") + continue; + } + + names.insert (nm); } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); - for (int i = 0; i < super_classes.numel (); i++) + for (int i = 0; ! error_state && i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i).string_value ()); if (! error_state) - cls.get_rep ()->find_names (names, count); + cls.get_rep ()->find_names (names, all); else break; } @@ -900,25 +1247,18 @@ string_vector cdef_class::cdef_class_rep::get_names (void) { - std::map<std::string,std::string> names; - - std::map<std::string,int> count; + std::set<std::string> names; - count["public"] = count["protected"] = count["private"] = 0; - - find_names (names, count); + find_names (names, false); if (! error_state) { - string_vector v (count["public"]); + string_vector v (names.size ()); int idx = 0; - for (std::map<std::string,std::string>::const_iterator it = names.begin (); - it != names.end (); ++it) - { - if (it->second == "public") - v[idx++] = it->first; - } + for (std::set<std::string>::const_iterator it = names.begin (); + it != names.end (); ++it, ++idx) + v[idx] = *it; return v.sort (true); } @@ -957,14 +1297,352 @@ } } +octave_value_list +cdef_class::cdef_class_rep::subsref_meta (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) +{ + octave_value_list retval; + + switch (type[0]) + { + case '(': + // Constructor call + printf ("constructor\n"); + retval(0) = construct (idx.front ()); + break; + case '.': + // Static method, constant (or property?) + printf ("static method\n"); + break; + } + + if (! error_state) + { + if (type.length () > 1 && idx.size () > 1 && ! retval.empty ()) + retval = retval(0).next_subsref (nargout, type, idx); + } + + return retval; +} + +void +cdef_class::cdef_class_rep::initialize_object (cdef_object& obj) +{ + // Populate the object with default property values + + std::list<cdef_class> super_classes = lookup_classes (get ("SuperClasses").cell_value ()); + + if (! error_state) + { + for (std::list<cdef_class>::iterator it = super_classes.begin (); + ! error_state && it != super_classes.end (); ++it) + it->initialize_object (obj); + + if (! error_state) + { + for (property_const_iterator it = property_map.begin (); + ! error_state && it != property_map.end (); ++it) + { + if (! it->second.get ("Dependent").bool_value ()) + { + octave_value pvalue = it->second.get ("DefaultValue"); + + if (pvalue.is_defined ()) + obj.put (it->first, pvalue); + else + obj.put (it->first, octave_value (Matrix ())); + } + } + } + } +} + +void +cdef_class::cdef_class_rep::run_constructor (cdef_object& obj, + const octave_value_list& args) +{ + // FIXME: Run constructors from superclasses if needed. + // One must analyze the class constructor to detect + // whether it explicitly calls them or not. + + std::string ctor_name = get_base_name (get_name ()); + cdef_method ctor = find_method (ctor_name); + + if (ctor.ok ()) + { + octave_value_list ctor_args (args); + octave_value_list ctor_retval; + + ctor_args.prepend (to_ov (obj)); + ctor_retval = ctor.execute (ctor_args, 1); + + if (ctor_retval.length () == 1) + obj = to_cdef (ctor_retval(0)); + else + ::error ("%s: invalid number of output arguments for classdef constructor", + ctor_name.c_str ()); + } +} + +octave_value +cdef_class::cdef_class_rep::construct (const octave_value_list& args) +{ + // FIXME: determine whether to use value or handle rep object + cdef_object obj (new handle_cdef_object (get ("Name").string_value ())); + + initialize_object (obj); + + if (! error_state) + { + run_constructor (obj, args); + + if (! error_state) + return to_ov (obj); + } + + return octave_value(); +} + +static octave_value +compute_attribute_value (tree_classdef_attribute* t) +{ + if (t->expression ()) + { + if (t->expression ()->is_identifier ()) + { + std::string s = t->expression ()->name (); + + if (s == "public") + return std::string ("public"); + else if (s == "protected") + return std::string ("protected"); + else if (s == "private") + return std::string ("private"); + } + + return t->expression ()->rvalue1 (); + } + else + return octave_value (true); +} + +template<class T> +static std::string +attribute_value_to_string (T* t, octave_value v) +{ + if (v.is_string ()) + return v.string_value (); + else if (t->expression ()) + return t->expression ()->original_text (); + else + return std::string ("true"); +} + cdef_class -cdef_class::make_meta_class (const tree_classdef* t) +cdef_class::make_meta_class (tree_classdef* t) { cdef_class retval; + std::string class_name; + + // Class creation + + class_name = t->ident ()->name (); + printf ("class: %s\n", class_name.c_str ()); + + std::list<std::string> snamelist; + std::list<cdef_class> slist; + + if (t->superclass_list ()) + { + for (tree_classdef_superclass_list::iterator it = t->superclass_list ()->begin (); + ! error_state && it != t->superclass_list ()->end (); ++it) + { + std::string sclass_name = + ((*it)->package () ? (*it)->package ()->name () + "." : std::string ()) + + (*it)->ident ()->name (); + + printf ("superclass: %s\n", sclass_name.c_str ()); + + cdef_class sclass = lookup_class (sclass_name); + + if (! error_state) + { + if (! sclass.get ("Sealed").bool_value ()) + { + slist.push_back (sclass); + snamelist.push_back (sclass_name); + } + else + { + ::error ("`%s' cannot inherit from `%s', because it is sealed", + class_name.c_str (), sclass_name.c_str ()); + return retval; + } + } + else + return retval; + + } + } + + retval = ::make_class (class_name, slist); + + if (error_state) + return cdef_class (); + + // FIXME: remove this... + if (! retval.is_handle_class ()) + { + ::error ("%s: value classes not supported yet", + class_name.c_str ()); + return cdef_class (); + } + + // Class attributes + + if (t->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator it = t->attribute_list ()->begin (); + it != t->attribute_list ()->end (); ++it) + { + std::string aname = (*it)->ident ()->name (); + octave_value avalue = compute_attribute_value (*it); + + printf ("class attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*it, avalue).c_str ()); + retval.put (aname, avalue); + } + } + + tree_classdef_body* b = t->body (); + + if (b) + { + // Method blocks + + std::list<tree_classdef_methods_block *> mb_list = b->methods_list (); + + for (tree_classdef_body::methods_list_iterator it = mb_list.begin (); + it != mb_list.end (); ++it) + { + std::map<std::string, octave_value> amap; + printf ("method block\n"); + + // Method attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + printf ("method attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + amap[aname] = avalue; + } + } + + // Methods + + if ((*it)->element_list ()) + { + for (tree_classdef_methods_list::iterator mit = (*it)->element_list ()->begin (); + mit != (*it)->element_list ()->end (); ++mit) + { + std::string mname = mit->function_value ()->name (); + cdef_method meth = make_method (retval, mname, *mit); + + printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), + mname.c_str ()); + for (std::map<std::string, octave_value>::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + meth.put (ait->first, ait->second); + + retval.install_method (meth); + } + } + } + + // Property blocks + + // FIXME: default property expression should be able to call static + // methods of the class being constructed. A restricted CLASSNAME + // symbol should be added to the scope before evaluating default + // value expressions. + + std::list<tree_classdef_properties_block *> pb_list = b->properties_list (); + + for (tree_classdef_body::properties_list_iterator it = pb_list.begin (); + it != pb_list.end (); ++it) + { + std::map<std::string, octave_value> amap; + printf ("property block\n"); + + // Property attributes + + if ((*it)->attribute_list ()) + { + for (tree_classdef_attribute_list::iterator ait = (*it)->attribute_list ()->begin (); + ait != (*it)->attribute_list ()->end (); ++ait) + { + std::string aname = (*ait)->ident ()->name (); + octave_value avalue = compute_attribute_value (*ait); + + printf ("property attribute: %s = %s\n", aname.c_str (), + attribute_value_to_string (*ait, avalue).c_str ()); + if (aname == "Access") + { + amap["GetAccess"] = avalue; + amap["SetAccess"] = avalue; + } + else + amap[aname] = avalue; + } + } + + // Properties + + if ((*it)->element_list ()) + { + for (tree_classdef_property_list::iterator pit = (*it)->element_list ()->begin (); + pit != (*it)->element_list ()->end (); ++pit) + { + cdef_property prop = ::make_property (retval, (*pit)->ident ()->name ()); + + printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); + if ((*pit)->expression ()) + { + octave_value pvalue = (*pit)->expression ()->rvalue1 (); + + printf ("property default: %s\n", + attribute_value_to_string (*pit, pvalue).c_str ()); + prop.put ("DefaultValue", pvalue); + } + + for (std::map<std::string, octave_value>::iterator ait = amap.begin (); + ait != amap.end (); ++ait) + prop.put (ait->first, ait->second); + + retval.install_property (prop); + } + } + } + } return retval; } +octave_function* +cdef_class::get_method_function (const std::string& /* nm */) +{ + octave_classdef_proxy* p = new octave_classdef_proxy (*this); + + return p; +} + octave_value cdef_property::cdef_property_rep::get_value (const cdef_object& obj) { @@ -974,13 +1652,6 @@ octave_value get_fcn = get ("GetMethod"); - std::string get_access = get ("GetAccess").string_value (); - - if (get_access != "public") - { - // FIXME: should check the current call stack - } - if (get_fcn.is_empty ()) retval = obj.get (get ("Name").string_value ()); else @@ -999,15 +1670,64 @@ } bool -cdef_property::check_get_access (const std::string& req) const +cdef_property::cdef_property_rep::is_recursive_set (const cdef_object& /* obj */) const +{ + // FIXME: implement + return false; +} + +void +cdef_property::cdef_property_rep::set_value (cdef_object& obj, + const octave_value& val) { - return ::check_access (req, get_get_access ()); + octave_value set_fcn = get ("SetMethod"); + + if (set_fcn.is_empty () || is_recursive_set (obj)) + { + obj.put (get ("Name").string_value (), val); + } + else + { + octave_value_list args; + + args(0) = to_ov (obj); + args(1) = val; + + args = execute_ov (set_fcn, args, 1); + + if (! error_state) + { + if (args.length() > 0) + { + cdef_object new_obj = to_cdef (args(0)); + + if (! error_state) + obj = new_obj; + } + } + } } bool -cdef_property::check_set_access (const std::string& req) const +cdef_property::check_get_access (void) const { - return ::check_access (req, get_set_access ()); + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("GetAccess")); + + return false; +} + +bool +cdef_property::check_set_access (void) const +{ + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("SetAccess")); + + return false; } void @@ -1070,9 +1790,14 @@ } bool -cdef_method::check_access (const std::string& req) const +cdef_method::check_access (void) const { - return ::check_access (req, get_access ()); + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! error_state) + return ::check_access (cls, get ("Access")); + + return false; } static cdef_package @@ -1220,27 +1945,6 @@ cdef_package::cdef_package_rep::get_packages (void) const { return map2Cell (package_map); } -octave_value_list -octave_classdef::subsref (const std::string& type, - const std::list<octave_value_list>& idx, - int nargout) -{ - int skip = 0; - octave_value_list retval; - - // FIXME: should check "subsref" method first - - retval = object.subsref (type, idx, nargout, skip); - - if (! error_state) - { - if (type.length () > skip && idx.size () > skip) - retval = retval(0).next_subsref (nargout, type, idx, skip); - } - - return retval; -} - void install_classdef (void) { @@ -1248,12 +1952,20 @@ /* meta classes */ cdef_class handle = make_class ("handle"); - cdef_class meta_class = make_class ("meta.class", "handle"); - cdef_class meta_property = make_class ("meta.property", "handle"); - cdef_class meta_method = make_class ("meta.method", "handle"); - cdef_class meta_event = make_class ("meta.event", "handle"); - cdef_class meta_package = make_class ("meta.package", "handle"); - cdef_class meta_dynproperty = make_class ("meta.dynamicproperty", "handle"); + cdef_class meta_class = make_class ("meta.class", handle); + cdef_class meta_property = make_class ("meta.property", handle); + cdef_class meta_method = make_class ("meta.method", handle); + cdef_class meta_event = make_class ("meta.event", handle); + cdef_class meta_package = make_class ("meta.package", handle); + cdef_class meta_dynproperty = make_class ("meta.dynamicproperty", handle); + + /* meta classes are all sealed */ + meta_class.put ("Sealed", true); + meta_property.put ("Sealed", true); + meta_method.put ("Sealed", true); + meta_event.put ("Sealed", true); + meta_package.put ("Sealed", true); + meta_dynproperty.put ("Sealed", true); /* meta.class properties */ meta_class.install_property (make_attribute (meta_class, "ConstructOnLoad")); @@ -1261,6 +1973,7 @@ meta_class.install_property (make_property (meta_class, "Description")); meta_class.install_property (make_property (meta_class, "DetailedDescription")); meta_class.install_property (make_property (meta_class, "Events")); + meta_class.install_property (make_attribute (meta_class, "HandleCompatible")); meta_class.install_property (make_attribute (meta_class, "Hidden")); meta_class.install_property (make_property (meta_class, "InferiorClasses", @@ -1333,6 +2046,11 @@ meta_property.install_property (make_attribute (meta_property, "GetMethod")); meta_property.install_property (make_attribute (meta_property, "SetMethod")); meta_property.install_property (make_attribute (meta_property, "DefiningClass")); + meta_property.install_property + (make_property (meta_property, "DefaultValue", + make_fcn_handle (property_get_defaultvalue, "meta.property>get.DefaultValue"), + "public", Matrix (), "private")); + meta_property.install_property (make_attribute (meta_property, "HasDefault")); /* meta.property events */ // FIXME: add events
--- 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 <set> #include <string> #include "oct-map.h" @@ -80,6 +81,14 @@ return octave_value_list (); } + virtual octave_value subsasgn (const std::string&, + const std::list<octave_value_list>&, + const octave_value&) + { + error ("subsasgn: invalid object"); + return octave_value (); + } + virtual string_vector map_keys(void) const; virtual bool is_valid (void) const { return false; } @@ -156,6 +165,11 @@ int nargout, int& skip) { return rep->subsref (type, idx, nargout, skip); } + octave_value subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs) + { return rep->subsasgn (type, idx, rhs); } + string_vector map_keys (void) const { return rep->map_keys (); } const cdef_object_rep* get_rep (void) const { return rep; } @@ -179,6 +193,8 @@ handle_cdef_object (const std::string& nm) : cdef_object_rep (nm) { } + ~handle_cdef_object (void); + cdef_object_rep* clone (void) const { handle_cdef_object *obj = const_cast<handle_cdef_object *> (this); @@ -206,6 +222,10 @@ const std::list<octave_value_list>& idx, int nargout, int& skip); + octave_value subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs); + bool is_valid (void) const { return true; } protected: @@ -222,9 +242,12 @@ { public: cdef_class_rep (const std::string& nm) - : handle_cdef_object (nm) { } + : handle_cdef_object (nm), handle_class (false) { } - cdef_method find_method (const std::string& nm); + std::string get_name (void) const + { return get ("Name").string_value (); } + + cdef_method find_method (const std::string& nm, bool local = false); void install_method (const cdef_method& meth); @@ -244,25 +267,47 @@ void delete_object (cdef_object obj); + octave_value_list subsref_meta (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout); + + octave_value construct (const octave_value_list& args); + + void initialize_object (cdef_object& obj); + + void run_constructor (cdef_object& obj, const octave_value_list& args); + + void mark_as_handle_class (void) { handle_class = true; } + + bool is_handle_class (void) const { return handle_class; } + private: void load_all_methods (void); - void find_names (std::map<std::string,std::string>& names, - std::map<std::string,int>& count); + void find_names (std::set<std::string>& names, bool all); void find_properties (std::map<std::string,cdef_property>& props, - std::map<std::string,int>& count); - - void find_methods (std::map<std::string,cdef_method>& meths, - std::map<std::string,int>& count); + bool only_inherited); + + void find_methods (std::map<std::string, cdef_method>& meths, + bool only_inherited); private: + // The @-directory were this class is loaded from. + // (not used yet) std::string directory; + // The methods defined by this class. std::map<std::string,cdef_method> method_map; + // The properties defined by this class. std::map<std::string,cdef_property> property_map; + // TRUE if this class is a handle class. A class is a handle + // class when the abstract "handle" class is one of its superclasses. + bool handle_class; + + // Utility iterator typedef's. typedef std::map<std::string,cdef_method>::iterator method_iterator; typedef std::map<std::string,cdef_method>::const_iterator method_const_iterator; typedef std::map<std::string,cdef_property>::iterator property_iterator; @@ -307,7 +352,7 @@ return *this; } - cdef_method find_method (const std::string& nm); + cdef_method find_method (const std::string& nm, bool local = false); void install_method (const cdef_method& meth) { get_rep ()->install_method (meth); } @@ -330,7 +375,7 @@ { return get_rep ()->get_directory (); } std::string get_name (void) const - { return get ("Name").string_value (); } + { return get_rep ()->get_name (); } bool is_builtin (void) const { return get_directory ().empty (); } @@ -338,7 +383,32 @@ void delete_object (cdef_object obj) { get_rep ()->delete_object (obj); } - static cdef_class make_meta_class (const tree_classdef* t); + octave_value_list subsref_meta (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) + { return get_rep ()->subsref_meta (type, idx, nargout); } + + static cdef_class make_meta_class (tree_classdef* t); + + octave_function* get_method_function (const std::string& nm); + + octave_function* get_constructor_function (void) + { return get_method_function (get_name ()); } + + octave_value construct (const octave_value_list& args) + { return get_rep ()->construct (args); } + + void initialize_object (cdef_object& obj) + { get_rep ()->initialize_object (obj); } + + void run_constructor (cdef_object& obj, const octave_value_list& args) + { get_rep ()->run_constructor (obj, args); } + + void mark_as_handle_class (void) + { get_rep ()->mark_as_handle_class (); } + + bool is_handle_class (void) const + { return get_rep ()->is_handle_class (); } private: cdef_class_rep* get_rep (void) @@ -378,7 +448,10 @@ void set_value (const octave_value& val) { default_value = val; } - void set_value (const cdef_object& obj, const octave_value& val); + void set_value (cdef_object& obj, const octave_value& val); + + private: + bool is_recursive_set (const cdef_object& obj) const; private: octave_value default_value; @@ -414,20 +487,14 @@ octave_value get_value (void) { return get_rep ()->get_value (); } - void set_value (const cdef_object& obj, const octave_value& val) + void set_value (cdef_object& obj, const octave_value& val) { get_rep ()->set_value (obj, val); } void set_value (const octave_value& val) { get_rep ()->set_value (val); } - std::string get_get_access (void) const - { return get ("GetAccess").string_value (); } + bool check_get_access (void) const; - std::string get_set_access (void) const - { return get ("SetAccess").string_value (); } - - bool check_get_access (const std::string& acc) const; - - bool check_set_access (const std::string& acc) const; + bool check_set_access (void) const; std::string get_name (void) const { return get ("Name").string_value (); } @@ -506,10 +573,7 @@ const octave_value_list& args, int nargout) { return get_rep ()->execute (obj, args, nargout); } - std::string get_access (void) const - { return get ("Access").string_value (); } - - bool check_access (const std::string& req) const; + bool check_access (void) const; std::string get_name (void) const { return get ("Name").string_value (); } @@ -533,8 +597,8 @@ { return rep->get_class (); } inline cdef_method -cdef_class::find_method (const std::string& nm) -{ return get_rep ()->find_method (nm); } +cdef_class::find_method (const std::string& nm, bool local) +{ return get_rep ()->find_method (nm, local); } inline cdef_property cdef_class::find_property (const std::string& nm) @@ -679,6 +743,10 @@ return (retval.length () > 0 ? retval(0) : octave_value ()); } + octave_value subsasgn (const std::string& type, + const std::list<octave_value_list>& idx, + const octave_value& rhs); + string_vector map_keys (void) const { return object.map_keys (); } dim_vector dims (void) const { return dim_vector (1, 1); }
--- a/libinterp/octave-value/ov-fcn.h +++ b/libinterp/octave-value/ov-fcn.h @@ -85,6 +85,10 @@ virtual bool is_class_constructor (const std::string& = std::string ()) const { return false; } + virtual bool + is_classdef_constructor (const std::string& = std::string ()) const + { return false; } + virtual bool is_class_method (const std::string& = std::string ()) const { return false; }
--- a/libinterp/octave-value/ov-usr-fcn.cc +++ b/libinterp/octave-value/ov-usr-fcn.cc @@ -191,7 +191,7 @@ num_named_args (param_list ? param_list->length () : 0), subfunction (false), inline_function (false), anonymous_function (false), nested_function (false), - class_constructor (false), class_method (false), + class_constructor (none), class_method (false), parent_scope (-1), local_scope (sid), curr_unwind_protect_frame (0) #ifdef HAVE_LLVM @@ -370,7 +370,7 @@ octave_value_list octave_user_function::do_multi_index_op (int nargout, - const octave_value_list& args, + const octave_value_list& _args, const std::list<octave_lvalue>* lvalue_list) { octave_value_list retval; @@ -381,6 +381,23 @@ if (! cmd_list) return retval; + // If this function is a classdef constructor, extract the first input + // argument, which must be the partially constructed object instance. + + octave_value_list args (_args); + octave_value_list ret_args; + + if (is_classdef_constructor ()) + { + if (args.length () > 0) + { + ret_args = args.slice (0, 1, true); + args = args.slice (1, args.length () - 1, true); + } + else + panic_impossible (); + } + #ifdef HAVE_LLVM if (is_special_expr () && tree_jit::execute (*this, args, retval)) @@ -424,6 +441,25 @@ return retval; } + // For classdef constructor, pre-populate the output arguments + // with the pre-initialized object instance, extracted above. + + if (is_classdef_constructor ()) + { + if (ret_list) + { + ret_list->define_from_arg_vector (ret_args); + if (error_state) + return retval; + } + else + { + ::error ("%s: invalid classdef constructor, no output argument defined", + dispatch_class ().c_str ()); + return retval; + } + } + // Force parameter list to be undefined when this function exits. // Doing so decrements the reference counts on the values of local // variables that are also named function parameters.
--- a/libinterp/octave-value/ov-usr-fcn.h +++ b/libinterp/octave-value/ov-usr-fcn.h @@ -300,11 +300,19 @@ void mark_as_nested_function (void) { nested_function = true; } - void mark_as_class_constructor (void) { class_constructor = true; } + void mark_as_class_constructor (void) { class_constructor = legacy; } + + void mark_as_classdef_constructor (void) { class_constructor = classdef; } bool is_class_constructor (const std::string& cname = std::string ()) const { - return class_constructor + return class_constructor == legacy + ? (cname.empty () ? true : cname == dispatch_class ()) : false; + } + + bool is_classdef_constructor (const std::string& cname = std::string ()) const + { + return class_constructor == classdef ? (cname.empty () ? true : cname == dispatch_class ()) : false; } @@ -380,6 +388,13 @@ private: + enum class_ctor_type + { + none, + legacy, + classdef + }; + // List of arguments for this function. These are local variables. tree_parameter_list *param_list; @@ -436,8 +451,8 @@ // TRUE means this is a nested function. (either a child or parent) bool nested_function; - // TRUE means this function is the constructor for class object. - bool class_constructor; + // Enum describing whether this function is the constructor for class object. + class_ctor_type class_constructor; // TRUE means this function is a method for a class. bool class_method;
--- a/libinterp/parse-tree/oct-parse.yy +++ b/libinterp/parse-tree/oct-parse.yy @@ -3893,8 +3893,11 @@ // Convert parse tree for classdef object to // meta.class info (and stash it in the symbol // table?). Return pointer to constructor? - - octave_value meta_class = classdef_object->make_meta_class (); + + if (fcn_ptr) + panic_impossible (); + + fcn_ptr = classdef_object->make_meta_class (); } } else
--- a/libinterp/parse-tree/pt-classdef.cc +++ b/libinterp/parse-tree/pt-classdef.cc @@ -232,16 +232,16 @@ // Classdef -octave_value -tree_classdef::make_meta_class (void) const +octave_function* +tree_classdef::make_meta_class (void) { octave_value retval; cdef_class cls = cdef_class::make_meta_class (this); if (cls.ok ()) - retval = to_ov (cls); + return cls.get_constructor_function (); - return retval; + return 0; } tree_classdef * @@ -255,6 +255,5 @@ void tree_classdef::accept (tree_walker& tw) { - std::cerr << "I am super accepting" << std::endl; - // tw.visit_classdef (*this); + tw.visit_classdef (*this); }
--- a/libinterp/parse-tree/pt-classdef.h +++ b/libinterp/parse-tree/pt-classdef.h @@ -623,7 +623,7 @@ octave_comment_list *leading_comment (void) { return lead_comm; } octave_comment_list *trailing_comment (void) { return trail_comm; } - octave_value make_meta_class (void) const; + octave_function* make_meta_class (void); tree_classdef *dup (symbol_table::scope_id scope, symbol_table::context_id context) const;