# HG changeset patch # User Michael Goffioul # Date 1357264871 18000 # Node ID 57be060d7672a22bf97ff8033ef157aff7cd28fc # Parent ce8ad12ce8a0e0dd0c8880946399a8c24b35c5a6 Implement full object construction and superclass references. * libinterp/octave-value/ov-classdef.h (cdef_object_rep::subsref): Add class context argument. (cdef_object_rep::ctor_list): New class member. (cdef_object_rep::mark_for_construction, cdef_object_rep::is_constructed_for, cdef_object_rep::is_partially_constructed_for, cdef_object_rep::mark_as_constructed, cdef_object_rep::is_constructed, cdef_object::mark_for_construction, cdef_object::is_constructed_for, cdef_object::is_partially_constructed_for, cdef_object::mark_as_constructed, cdef_object:is_constructed): New methods to manipulate the new ctor_list class member. (cdef_object_rep::cdef_object_rep (const cdef_object_rep&)): New copy constructor. (cdef_class::cdef_class_rep (std::string, std::list)): New utility constructor. (cdef_class (std::string, std::list)): Likewise. (cdef_class::cdef_class_rep::implicit_ctor_list): New class member. (cdef_method::cdef_method_rep::is_constructor, cdef_method::is_construcror): New methods. (cdef_method::get_function): Likewise. (cdef_package::cdef_package_rep::subsref): Remove method. (octave_classdef::get_object_ref): New method. (to_cdef_ref): New function. * libinterp/octave-value/ov-classdef.cc (is_superclass): Add max_depth argument. (is_direct_superclass): New utility function. (get_class_context): Add bool and std::string return values, as new reference arguments. Add overload without any arguments. (check_access): Check for valid class context when required. (make_class): Remove super_name_list argument. Do not set SuperClasses explicitly, use new cdef_class constructor instead. (octave_classdef::subsref): Change skip variable to size_t (avoids compilation warning). Call cdef_object::subsref with additional class context argument. (class octave_classdef_superclass_ref): New utility class. (F__superclass_reference__): Use it. (cdef_object_rep::subsref): Add class context argument. (cdef_object_rep::mark_for_construction): New method. (handle_cdef_object::~handle_cdef_object, value_cdef_object::~value_cdef_object, cdef_class::cdef_class_rep::subsref_meta, cdef_class::make_meta_class): Use gnulib::printf explicitly. (cdef_class::cdef_class_rep (std::string, std::list)): New constructor. (class ctor_analyzer): New utility class. (cdef_class::cdef_class_rep::install_method): Use it to analyze constructors and detect explicit superclass constructor calls. (cdef_class::cdef_class_rep::initialize_object): Call cdef_object::mark_for_construction. (cdef_class::cdef_class_rep::run_constructor): Run all implicit superclass constructors first. (cdef_class::cdef_class_rep::construct): Call cdef_object::mark_as_constructed. (cdef_class::make_meta_class): Remove snamelist variable. (cdef_property::cdef_property_rep::get_value, cdef_property::cdef_property_rep::set_value): Check if object is partially constructed for the property-defining class. (cdef_method::cdef_method_rep::is_constructor): New method. (cdef_package::cdef_package_rep::subsref): Delete method. diff -r ce8ad12ce8a0 -r 57be060d7672 libinterp/octave-value/ov-classdef.cc --- a/libinterp/octave-value/ov-classdef.cc Thu Jan 03 21:01:07 2013 -0500 +++ b/libinterp/octave-value/ov-classdef.cc Thu Jan 03 21:01:11 2013 -0500 @@ -24,6 +24,7 @@ #include #endif +#include #include #include "defun.h" @@ -31,7 +32,11 @@ #include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-typeinfo.h" +#include "pt-assign.h" #include "pt-classdef.h" +#include "pt-funcall.h" +#include "pt-misc.h" +#include "pt-stmt.h" #include "pt-walk.h" #include "symtab.h" #include "toplev.h" @@ -210,32 +215,37 @@ static bool is_superclass (const cdef_class& clsa, const cdef_class& clsb, - bool allow_equal = true) + bool allow_equal = true, int max_depth = -1) { + bool retval = false; + if (allow_equal && clsa == clsb) - return true; - else + retval = true; + else if (max_depth != 0) { Cell c = clsb.get ("SuperClasses").cell_value (); - bool retval = false; - - for (int i = 0; ! retval && i < c.numel (); i++) + for (int i = 0; ! error_state && ! retval && i < c.numel (); i++) { cdef_class cls = lookup_class (c(i).string_value ()); if (! error_state) - retval = is_superclass (clsa, cls, true); + retval = is_superclass (clsa, cls, true, + max_depth < 0 ? max_depth : max_depth-1); } - - return retval; } + + return retval; } inline bool is_strict_superclass (const cdef_class& clsa, const cdef_class& clsb) { return is_superclass (clsa, clsb, false); } +inline bool +is_direct_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false, 1); } + static octave_value_list class_get_properties (const octave_value_list& args, int /* nargout */) { @@ -252,23 +262,41 @@ } static cdef_class -get_class_context (void) +get_class_context (std::string& name, bool& in_constructor) { cdef_class cls; octave_function* fcn = octave_call_stack::current (); + in_constructor = false; + if (fcn && (fcn->is_class_method () - || fcn->is_class_constructor () + || fcn->is_classdef_constructor () || fcn->is_anonymous_function_of_class () || (fcn->is_private_function () && ! fcn->dispatch_class ().empty ()))) - cls = lookup_class (fcn->dispatch_class ()); + { + cls = lookup_class (fcn->dispatch_class ()); + if (! error_state) + { + name = fcn->name (); + in_constructor = fcn->is_classdef_constructor (); + } + } return cls; } +inline cdef_class +get_class_context (void) +{ + std::string dummy_string; + bool dummy_bool; + + return get_class_context (dummy_string, dummy_bool); +} + static bool check_access (const cdef_class& cls, const octave_value& acc) { @@ -281,12 +309,18 @@ 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 (); + // The access is private or protected, this requires a + // valid class context. + + if (! error_state && ctx.ok ()) + { + 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 ()) { @@ -294,21 +328,24 @@ cdef_class ctx = get_class_context (); - if (ctx == cls) - return true; - - for (int i = 0; ! error_state && i < acc.numel (); i++) + // At this point, a class context is always required. + + if (! error_state && ctx.ok ()) { - cdef_class acc_cls (to_cdef (acc_c(i))); - - if (! error_state) + if (ctx == cls) + return true; + + for (int i = 0; ! error_state && i < acc.numel (); i++) { - if (is_superclass (acc_cls, ctx)) - return true; + 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'", @@ -544,10 +581,9 @@ static cdef_class make_class (const std::string& name, - const std::list& super_list = std::list (), - const std::list& super_name_list = std::list ()) + const std::list& super_list = std::list ()) { - cdef_class cls ("meta.class"); + cdef_class cls ("meta.class", super_list); cls.put ("ConstructOnLoad", false); cls.put ("ContainingPackage", Matrix ()); @@ -560,18 +596,6 @@ cls.put ("Name", name); cls.put ("Properties", Cell ()); cls.put ("Sealed", false); - if (super_name_list.size () == super_list.size ()) - cls.put ("SuperClasses", Cell (super_name_list)); - else - { - std::list snamelist; - - for (std::list::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") { @@ -731,12 +755,12 @@ const std::list& idx, int nargout) { - int skip = 0; + size_t skip = 0; octave_value_list retval; // FIXME: should check "subsref" method first - retval = object.subsref (type, idx, nargout, skip); + retval = object.subsref (type, idx, nargout, skip, cdef_class ()); if (! error_state) { @@ -792,6 +816,171 @@ //---------------------------------------------------------------------------- +class octave_classdef_superclass_ref : public octave_function +{ +public: + octave_classdef_superclass_ref (const octave_value_list& a) + : octave_function (), args (a) { } + + ~octave_classdef_superclass_ref (void) { } + + octave_value_list + subsref (const std::string& type, + const std::list& idx, + int nargout) + { + size_t skip = 0; + octave_value_list retval; + + switch (type[0]) + { + case '(': + skip = 1; + retval = do_multi_index_op (type.length () > 1 ? 1 : nargout, + idx.front ()); + break; + default: + retval = do_multi_index_op (1, octave_value_list ()); + break; + } + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip + && retval.length () > 0) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; + } + + octave_value + subsref (const std::string& type, + const std::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) + { + octave_value_list retval; + + std::string meth_name; + bool in_constructor; + cdef_class ctx; + + ctx = get_class_context (meth_name, in_constructor); + + if (! error_state && ctx.ok ()) + { + std::string mname = args(0).string_value (); + std::string pname = args(1).string_value (); + std::string cname = args(2).string_value (); + + std::string cls_name = (pname.empty () ? + cname : pname + "." + cname); + cdef_class cls = lookup_class (cls_name); + + if (! error_state) + { + if (in_constructor) + { + if (is_direct_superclass (cls, ctx)) + { + if (is_constructed_object (mname)) + { + octave_value& sym = symbol_table::varref (mname); + + cls.run_constructor (to_cdef_ref (sym), idx); + + retval(0) = sym; + } + else + ::error ("cannot call superclass constructor with " + "variable `%s'", mname.c_str ()); + } + else + ::error ("`%s' is not a direct superclass of `%s'", + cls_name.c_str (), ctx.get_name ().c_str ()); + } + else + { + if (mname == meth_name) + { + if (is_strict_superclass (cls, ctx)) + { + // I see 2 possible implementations here: + // 1) use cdef_object::subsref with a different class + // context; this avoids duplicating codem but + // assumes the object is always the first argument + // 2) lookup the method manually and call + // cdef_method::execute; this duplicates part of + // logic in cdef_object::subsref, but avoid the + // assumption of 1) + // Not being sure about the assumption of 1), I + // go with option 2) for the time being. + + cdef_method meth = cls.find_method (meth_name, false); + + if (meth.ok ()) + { + if (meth.check_access ()) + retval = meth.execute (idx, nargout); + else + gripe_method_access (meth_name, meth); + } + else + ::error ("no method `%s' found in superclass `%s'", + meth_name.c_str (), cls_name.c_str ()); + } + else + ::error ("`%s' is not a superclass of `%s'", + cls_name.c_str (), ctx.get_name ().c_str ()); + } + else + ::error ("method name mismatch (`%s' != `%s')", + mname.c_str (), meth_name.c_str ()); + } + } + } + else if (! error_state) + ::error ("superclass calls can only occur in methods or constructors"); + + return retval; + } + +private: + bool is_constructed_object (const std::string nm) + { + octave_function *of = octave_call_stack::current (); + + if (of->is_classdef_constructor ()) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + + if (ret_list && ret_list->length () == 1) + return (ret_list->front ()->name () == nm); + } + } + + return false; + } + +private: + octave_value_list args; +}; + +//---------------------------------------------------------------------------- + cdef_class cdef_object_rep::get_class (void) const { @@ -814,11 +1003,12 @@ octave_value_list cdef_object_rep::subsref (const std::string& type, const std::list& idx, - int nargout, int& skip) + int nargout, size_t& skip, + const cdef_class& context) { skip = 0; - cdef_class cls = get_class (); + cdef_class cls = (context.ok () ? context : get_class ()); octave_value_list retval; @@ -952,14 +1142,44 @@ return retval; } +void +cdef_object_rep::mark_for_construction (const cdef_class& cls) +{ + std::string cls_name = cls.get_name (); + + Cell supcls = cls.get ("SuperClasses").cell_value (); + + if (! error_state) + { + std::list supcls_names; + + for (int i = 0; ! error_state && i < supcls.numel (); i++) + supcls_names.push_back (supcls(i).string_value ()); + + if (! error_state) + ctor_list[cls_name] = supcls_names; + } +} + handle_cdef_object::~handle_cdef_object (void) { - printf ("deleting %s object (handle)\n", cname.c_str ()); + gnulib::printf ("deleting %s object (handle)\n", cname.c_str ()); } value_cdef_object::~value_cdef_object (void) { - printf ("deleting %s object (value)\n", cname.c_str ()); + gnulib::printf ("deleting %s object (value)\n", cname.c_str ()); +} + +cdef_class::cdef_class_rep::cdef_class_rep (const std::string& nm, + const std::list& superclasses) + : handle_cdef_object (nm), handle_class (false) +{ + for (std::list::const_iterator it = superclasses.begin (); + it != superclasses.end (); ++it) + implicit_ctor_list.push_back (it->get_name ()); + + put ("SuperClasses", Cell (implicit_ctor_list)); } cdef_method @@ -1004,10 +1224,184 @@ return cdef_method (); } +class ctor_analyzer : public tree_walker +{ +public: + ctor_analyzer (const std::string& ctor, const std::string& obj, + const std::list& l) + : tree_walker (), who (ctor), obj_name (obj), available_ctor_list (l) { } + + void visit_statement_list (tree_statement_list& t) + { + for (tree_statement_list::const_iterator it = t.begin (); + ! error_state && it != t.end (); ++it) + (*it)->accept (*this); + } + + void visit_statement (tree_statement& t) + { + if (t.is_expression ()) + t.expression ()->accept (*this); + } + + void visit_simple_assignment (tree_simple_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_multi_assignment (tree_multi_assignment& t) + { + t.right_hand_side ()->accept (*this); + } + + void visit_index_expression (tree_index_expression& t) + { + t.expression ()->accept (*this); + } + + void visit_funcall (tree_funcall& t) + { + octave_value fcn = t.function (); + + if (fcn.is_function ()) + { + octave_function *of = fcn.function_value (true); + + if (of) + { + if (of->name () == "__superclass_reference__") + { + octave_value_list args = t.arguments (); + + if (args(0).string_value () == obj_name) + { + std::string package_name = args(1).string_value (); + std::string class_name = args(2).string_value (); + + std::string ctor_name = (package_name.empty () + ? class_name + : package_name + "." + class_name); + + if (std::find (available_ctor_list.begin (), + available_ctor_list.end (), ctor_name) + == available_ctor_list.end ()) + ::error ("`%s' is not a direct superclass of `%s'", + ctor_name.c_str (), who.c_str ()); + else if (std::find (ctor_list.begin (), ctor_list.end (), + ctor_name) != ctor_list.end ()) + ::error ("calling constructor `%s' more than once", + ctor_name.c_str ()); + + ctor_list.push_back (ctor_name); + } + } + } + } + } + + std::list get_constructor_list (void) const + { return ctor_list; } + + // NO-OP + void visit_anon_fcn_handle (tree_anon_fcn_handle&) { } + void visit_argument_list (tree_argument_list&) { } + void visit_binary_expression (tree_binary_expression&) { } + void visit_break_command (tree_break_command&) { } + void visit_colon_expression (tree_colon_expression&) { } + void visit_continue_command (tree_continue_command&) { } + void visit_global_command (tree_global_command&) { } + void visit_persistent_command (tree_persistent_command&) { } + void visit_decl_elt (tree_decl_elt&) { } + void visit_decl_init_list (tree_decl_init_list&) { } + void visit_simple_for_command (tree_simple_for_command&) { } + void visit_complex_for_command (tree_complex_for_command&) { } + void visit_octave_user_script (octave_user_script&) { } + void visit_octave_user_function (octave_user_function&) { } + void visit_function_def (tree_function_def&) { } + void visit_identifier (tree_identifier&) { } + void visit_if_clause (tree_if_clause&) { } + void visit_if_command (tree_if_command&) { } + void visit_if_command_list (tree_if_command_list&) { } + void visit_switch_case (tree_switch_case&) { } + void visit_switch_case_list (tree_switch_case_list&) { } + void visit_switch_command (tree_switch_command&) { } + void visit_matrix (tree_matrix&) { } + void visit_cell (tree_cell&) { } + void visit_no_op_command (tree_no_op_command&) { } + void visit_constant (tree_constant&) { } + void visit_fcn_handle (tree_fcn_handle&) { } + void visit_parameter_list (tree_parameter_list&) { } + void visit_postfix_expression (tree_postfix_expression&) { } + void visit_prefix_expression (tree_prefix_expression&) { } + void visit_return_command (tree_return_command&) { } + void visit_return_list (tree_return_list&) { } + void visit_try_catch_command (tree_try_catch_command&) { } + void visit_unwind_protect_command (tree_unwind_protect_command&) { } + void visit_while_command (tree_while_command&) { } + void visit_do_until_command (tree_do_until_command&) { } + +private: + /* The name of the constructor being analyzed */ + std::string who; + + /* The name of the first output argument of the constructor */ + std::string obj_name; + + /* The list of superclass constructors that are explicitly called */ + std::list ctor_list; + + /* The list of possible superclass constructors */ + std::list available_ctor_list; +}; + void cdef_class::cdef_class_rep::install_method (const cdef_method& meth) { method_map[meth.get_name ()] = meth; + + if (meth.is_constructor ()) + { + // Analyze the constructor code to determine what superclass + // constructors are called explicitly. + + octave_function *of = meth.get_function ().function_value (true); + + if (of) + { + octave_user_function *uf = of->user_function_value (true); + + if (uf) + { + tree_parameter_list *ret_list = uf->return_list (); + tree_statement_list *body = uf->body (); + + if (ret_list && ret_list->size () == 1) + { + std::string obj_name = ret_list->front ()->name (); + ctor_analyzer a (meth.get_name (), obj_name, + implicit_ctor_list); + + body->accept (a); + if (! error_state) + { + std::list explicit_ctor_list + = a.get_constructor_list (); + + for (std::list::const_iterator it = explicit_ctor_list.begin (); + ! error_state && it != explicit_ctor_list.end (); ++it) + { + gnulib::printf ("explicit superclass constructor: %s\n", + it->c_str ()); + implicit_ctor_list.remove (*it); + } + } + } + else + ::error ("%s: invalid constructor output arguments", + meth.get_name ().c_str ()); + } + } + } } void @@ -1313,12 +1707,12 @@ { case '(': // Constructor call - printf ("constructor\n"); + gnulib::printf ("constructor\n"); retval(0) = construct (idx.front ()); break; case '.': // Static method, constant (or property?) - printf ("static method\n"); + gnulib::printf ("static method\n"); break; } @@ -1359,6 +1753,12 @@ obj.put (it->first, octave_value (Matrix ())); } } + + if (! error_state) + { + refcount++; + obj.mark_for_construction (cdef_class (this)); + } } } } @@ -1367,11 +1767,23 @@ 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 ()); + octave_value_list empty_args; + + for (std::list::const_iterator it = implicit_ctor_list.begin (); + ! error_state && it != implicit_ctor_list.end (); ++it) + { + cdef_class supcls = lookup_class (*it); + + if (! error_state) + supcls.run_constructor (obj, empty_args); + } + + if (error_state) + return; + + std::string cls_name = get_name (); + std::string ctor_name = get_base_name (cls_name); + cdef_method ctor = find_method (ctor_name); if (ctor.ok ()) @@ -1387,10 +1799,15 @@ 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 ()); + { + ::error ("%s: invalid number of output arguments for classdef constructor", + ctor_name.c_str ()); + return; + } } } + + obj.mark_as_constructed (cls_name); } octave_value @@ -1462,9 +1879,8 @@ // Class creation class_name = t->ident ()->name (); - printf ("class: %s\n", class_name.c_str ()); - - std::list snamelist; + gnulib::printf ("class: %s\n", class_name.c_str ()); + std::list slist; if (t->superclass_list ()) @@ -1476,17 +1892,14 @@ ((*it)->package () ? (*it)->package ()->name () + "." : std::string ()) + (*it)->ident ()->name (); - printf ("superclass: %s\n", sclass_name.c_str ()); + gnulib::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); - } + slist.push_back (sclass); else { ::error ("`%s' cannot inherit from `%s', because it is sealed", @@ -1515,7 +1928,7 @@ std::string aname = (*it)->ident ()->name (); octave_value avalue = compute_attribute_value (*it); - printf ("class attribute: %s = %s\n", aname.c_str (), + gnulib::printf ("class attribute: %s = %s\n", aname.c_str (), attribute_value_to_string (*it, avalue).c_str ()); retval.put (aname, avalue); } @@ -1533,7 +1946,7 @@ it != mb_list.end (); ++it) { std::map amap; - printf ("method block\n"); + gnulib::printf ("method block\n"); // Method attributes @@ -1545,7 +1958,7 @@ std::string aname = (*ait)->ident ()->name (); octave_value avalue = compute_attribute_value (*ait); - printf ("method attribute: %s = %s\n", aname.c_str (), + gnulib::printf ("method attribute: %s = %s\n", aname.c_str (), attribute_value_to_string (*ait, avalue).c_str ()); amap[aname] = avalue; } @@ -1561,7 +1974,7 @@ std::string mname = mit->function_value ()->name (); cdef_method meth = make_method (retval, mname, *mit); - printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), + gnulib::printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), mname.c_str ()); for (std::map::iterator ait = amap.begin (); ait != amap.end (); ++ait) @@ -1585,7 +1998,7 @@ it != pb_list.end (); ++it) { std::map amap; - printf ("property block\n"); + gnulib::printf ("property block\n"); // Property attributes @@ -1597,7 +2010,7 @@ std::string aname = (*ait)->ident ()->name (); octave_value avalue = compute_attribute_value (*ait); - printf ("property attribute: %s = %s\n", aname.c_str (), + gnulib::printf ("property attribute: %s = %s\n", aname.c_str (), attribute_value_to_string (*ait, avalue).c_str ()); if (aname == "Access") { @@ -1618,12 +2031,12 @@ { cdef_property prop = ::make_property (retval, (*pit)->ident ()->name ()); - printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); + gnulib::printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); if ((*pit)->expression ()) { octave_value pvalue = (*pit)->expression ()->rvalue1 (); - printf ("property default: %s\n", + gnulib::printf ("property default: %s\n", attribute_value_to_string (*pit, pvalue).c_str ()); prop.put ("DefaultValue", pvalue); } @@ -1652,12 +2065,24 @@ octave_value cdef_property::cdef_property_rep::get_value (const cdef_object& obj) { - // FIXME: should check whether we're already in get accessor method - octave_value retval; + + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls.get_name ())) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return retval; + } + } octave_value get_fcn = get ("GetMethod"); + // FIXME: should check whether we're already in get accessor method + if (get_fcn.is_empty ()) retval = obj.get (get ("Name").string_value ()); else @@ -1686,6 +2111,18 @@ cdef_property::cdef_property_rep::set_value (cdef_object& obj, const octave_value& val) { + if (! obj.is_constructed ()) + { + cdef_class cls (to_cdef (get ("DefiningClass"))); + + if (! obj.is_partially_constructed_for (cls.get_name ())) + { + ::error ("cannot reference properties of class `%s' for non-constructed object", + cls.get_name ().c_str ()); + return; + } + } + octave_value set_fcn = get ("SetMethod"); if (set_fcn.is_empty () || is_recursive_set (obj)) @@ -1796,6 +2233,15 @@ } bool +cdef_method::cdef_method_rep::is_constructor (void) const +{ + if (function.is_function()) + return function.function_value ()->is_classdef_constructor (); + + return false; +} + +bool cdef_method::check_access (void) const { cdef_class cls (to_cdef (get ("DefiningClass"))); @@ -1915,14 +2361,6 @@ package_map[nm] = pack; } -octave_value_list -cdef_package::cdef_package_rep::subsref (const std::string& type, - const std::list& idx, - int nargout, int& skip) -{ - return handle_cdef_object::subsref (type, idx, nargout, skip); -} - template Cell map2Cell (const std::map& m) @@ -2128,15 +2566,7 @@ Undocumented internal function.\n\ @end deftypefn") { - octave_value retval; - - std::cerr << "__superclass_reference__ (" - << args(0).string_value () << ", " - << args(1).string_value () << ", " - << args(2).string_value () << ")" - << std::endl; - - return retval; + return octave_value (new octave_classdef_superclass_ref (args)); } DEFUN (__meta_class_query__, args, /* nargout */, diff -r ce8ad12ce8a0 -r 57be060d7672 libinterp/octave-value/ov-classdef.h --- a/libinterp/octave-value/ov-classdef.h Thu Jan 03 21:01:07 2013 -0500 +++ b/libinterp/octave-value/ov-classdef.h Thu Jan 03 21:01:11 2013 -0500 @@ -77,13 +77,13 @@ } } - virtual octave_value_list subsref (const std::string& type, - const std::list& idx, - int nargout, int& skip); + virtual octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context); - virtual octave_value subsasgn (const std::string& type, - const std::list& idx, - const octave_value& rhs); + virtual octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs); virtual string_vector map_keys(void) const; @@ -91,8 +91,41 @@ std::string class_name (void) const { return cname; } - void set_class_name (const std::string& nm) - { cname = nm; } + void set_class_name (const std::string& nm) { cname = nm; } + + void mark_for_construction (const cdef_class&); + + //bool is_constructed_for (const cdef_class&) const; + + bool is_constructed_for (const std::string& nm) const + { + return (is_constructed () + || ctor_list.find (nm) == ctor_list.end ()); + } + + bool is_partially_constructed_for (const std::string& nm) const + { + std::map< std::string, std::list >::const_iterator it; + + if (is_constructed ()) + return true; + else if ((it = ctor_list.find (nm)) == ctor_list.end () + || it->second.empty ()) + return true; + + for (std::list::const_iterator lit = it->second.begin (); + lit != it->second.end (); ++lit) + if (! is_constructed_for (*lit)) + return false; + + return true; + } + + void mark_as_constructed (void) { ctor_list.clear (); } + + void mark_as_constructed (const std::string& nm) { ctor_list.erase (nm); } + + bool is_constructed (void) const { return ctor_list.empty (); } protected: /* reference count */ @@ -104,9 +137,17 @@ /* object property values */ Octave_map map; + /* Internal/temporary structure used during object construction */ + std::map< std::string, std::list > ctor_list; + +protected: + /* Restricted copying */ + cdef_object_rep (const cdef_object_rep& r) + : refcount (1), cname (r.cname), map (r.map), + ctor_list (r.ctor_list) { } + private: - // No copying - cdef_object_rep (const cdef_object_rep&); + /* No assignment */ cdef_object_rep& operator = (const cdef_object_rep& ); }; @@ -164,14 +205,14 @@ octave_value get (const std::string& pname) const { return rep->get (pname); } - octave_value_list subsref (const std::string& type, - const std::list& idx, - int nargout, int& skip) - { return rep->subsref (type, idx, nargout, skip); } + octave_value_list + subsref (const std::string& type, const std::list& idx, + int nargout, size_t& skip, const cdef_class& context) + { return rep->subsref (type, idx, nargout, skip, context); } - octave_value subsasgn (const std::string& type, - const std::list& idx, - const octave_value& rhs) + octave_value + subsasgn (const std::string& type, const std::list& idx, + const octave_value& rhs) { return rep->subsasgn (type, idx, rhs); } string_vector map_keys (void) const { return rep->map_keys (); } @@ -180,6 +221,22 @@ bool ok (void) const { return rep->is_valid (); } + void mark_for_construction (const cdef_class& cls) + { rep->mark_for_construction (cls); } + + bool is_constructed (void) const { return rep->is_constructed (); } + + bool is_constructed_for (const std::string& nm) const + { return rep->is_constructed_for (nm); } + + bool is_partially_constructed_for (const std::string& nm) const + { return rep->is_partially_constructed_for (nm); } + + void mark_as_constructed (void) { rep->mark_as_constructed (); } + + void mark_as_constructed (const std::string& nm) + { rep->mark_as_constructed (nm); } + protected: cdef_object_rep* get_rep (void) { return rep; } @@ -253,6 +310,9 @@ cdef_class_rep (const std::string& nm) : handle_cdef_object (nm), handle_class (false) { } + cdef_class_rep (const std::string& nm, + const std::list& superclasses); + std::string get_name (void) const { return get ("Name").string_value (); } @@ -276,9 +336,9 @@ void delete_object (cdef_object obj); - octave_value_list subsref_meta (const std::string& type, - const std::list& idx, - int nargout); + octave_value_list + subsref_meta (const std::string& type, + const std::list& idx, int nargout); octave_value construct (const octave_value_list& args); @@ -316,6 +376,11 @@ // class when the abstract "handle" class is one of its superclasses. bool handle_class; + // The list of super-class constructors that are called implicitly by the + // the classdef engine when creating an object. These constructors are not + // called explicitly by the class constructor. + std::list implicit_ctor_list; + // Utility iterator typedef's. typedef std::map::iterator method_iterator; typedef std::map::const_iterator method_const_iterator; @@ -331,6 +396,10 @@ cdef_class (const std::string& nm) : cdef_object (new cdef_class_rep (nm)) { } + cdef_class (const std::string& nm, + const std::list& superclasses) + : cdef_object (new cdef_class_rep (nm, superclasses)) { } + cdef_class (const cdef_class& cls) : cdef_object (cls) { } @@ -533,14 +602,15 @@ octave_value get_function (void) const { return function; } - void set_function (const octave_value& fcn) - { function = fcn; } + void set_function (const octave_value& fcn) { function = fcn; } octave_value_list execute (const octave_value_list& args, int nargout); octave_value_list execute (const cdef_object& obj, const octave_value_list& args, int nargout); + bool is_constructor (void) const; + private: void check_method (void); @@ -593,6 +663,12 @@ void set_function (const octave_value& fcn) { get_rep ()->set_function (fcn); } + octave_value get_function (void) const + { return get_rep ()->get_function (); } + + bool is_constructor (void) const + { return get_rep ()->is_constructor (); } + private: cdef_method_rep* get_rep (void) { return dynamic_cast (cdef_object::get_rep ()); } @@ -631,10 +707,6 @@ void install_package (const cdef_package& pack, const std::string& nm); - octave_value_list subsref (const std::string& type, - const std::list& idx, - int nargout, int& skip); - Cell get_classes (void) const; Cell get_functions (void) const; @@ -721,8 +793,9 @@ octave_base_value* empty_clone (void) const { return new octave_classdef (); } - cdef_object get_object (void) const - { return object; } + cdef_object get_object (void) const { return object; } + + cdef_object& get_object_ref (void) { return object; } bool is_defined (void) const { return true; } @@ -807,6 +880,20 @@ } } +inline cdef_object& +to_cdef_ref (octave_value& val) +{ + static cdef_object empty; + + if (val.type_name () == "object") + return dynamic_cast (val.internal_rep ())->get_object_ref (); + else + { + warning ("trying to cast non-object into object"); + return empty; + } +} + inline cdef_object to_cdef (const cdef_object& obj) { return obj; }