Mercurial > hg > octave-nkf
view libinterp/octave-value/ov-classdef.cc @ 20068:19755f4fc851
maint: Cleanup C++ code to follow Octave coding conventions.
Try to wrap long lines to < 80 characters.
Use GNU style and don't indent first brace of function definition.
"case" statement is aligned flush left with brace of switch stmt.
Remove trailing '\' line continuation from the end of #define macros.
Use 2 spaces for indent.
* files-dock-widget.cc, history-dock-widget.cc, main-window.cc, octave-cmd.cc,
octave-dock-widget.cc, octave-gui.cc, resource-manager.cc, settings-dialog.cc,
shortcut-manager.cc, welcome-wizard.cc, workspace-view.cc, cellfun.cc, data.cc,
debug.cc, debug.h, dirfns.cc, error.h, file-io.cc, gl-render.cc, gl-render.h,
gl2ps-renderer.h, graphics.cc, graphics.in.h, help.cc, input.cc, load-path.cc,
load-path.h, lookup.cc, lu.cc, oct-stream.cc, octave-default-image.h,
ordschur.cc, pr-output.cc, qz.cc, strfns.cc, symtab.cc, symtab.h, sysdep.cc,
variables.cc, zfstream.h, __fltk_uigetfile__.cc, __init_fltk__.cc,
__magick_read__.cc, __osmesa_print__.cc, audiodevinfo.cc, ov-classdef.cc,
ov-classdef.h, ov-fcn.h, ov-float.cc, ov-flt-complex.cc, ov-java.cc,
ov-range.cc, ov-re-mat.cc, ov-usr-fcn.h, ov.cc, op-int.h, options-usage.h,
pt-eval.cc, Array-C.cc, Array-fC.cc, Array.cc, Array.h, PermMatrix.cc,
Sparse.cc, chMatrix.h, dSparse.cc, dim-vector.h, bsxfun-decl.h, bsxfun-defs.cc,
oct-norm.cc, Sparse-op-defs.h, oct-inttypes.cc, oct-inttypes.h, main.in.cc,
mkoctfile.in.cc: Cleanup C++ code to follow Octave coding conventions.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 25 Feb 2015 11:55:49 -0800 |
parents | 4197fc428c7d |
children | 17d647821d61 |
line wrap: on
line source
/* Copyright (C) 2012-2015 Michael Goffioul This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <algorithm> #include "defun.h" #include "load-path.h" #include "ov-builtin.h" #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" #include "pt-misc.h" #include "pt-stmt.h" #include "pt-walk.h" #include "singleton-cleanup.h" #include "symtab.h" #include "toplev.h" #include "Array.cc" // Define to 1 to enable debugging statements. #define DEBUG_TRACE 0 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 (), 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 (), 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 (), 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 make_fcn_handle (octave_builtin::fcn ff, const std::string& nm) { octave_value fcn (new octave_builtin (ff, nm)); octave_value fcn_handle (new octave_fcn_handle (fcn, nm)); return fcn_handle; } static octave_value make_fcn_handle (const octave_value& fcn, const std::string& nm) { octave_value retval; if (fcn.is_defined ()) retval = octave_value (new octave_fcn_handle (fcn, nm)); return retval; } inline octave_value_list execute_ov (octave_value val, const octave_value_list& args, int nargout) { std::list<octave_value_list> idx (1, args); std::string type ("("); return val.subsref (type, idx, nargout); } static cdef_class lookup_class (const std::string& name, bool error_if_not_found = true, bool load_if_not_found = true) { return cdef_manager::find_class (name, error_if_not_found, load_if_not_found); } static cdef_class lookup_class (const cdef_class& cls) { // FIXME: placeholder for the time being, the purpose // is to centralized any class update activity here. return cls; } static cdef_class lookup_class (const octave_value& ov) { if (ov.is_string()) return lookup_class (ov.string_value ()); else { cdef_class cls (to_cdef (ov)); if (! error_state) return lookup_class (cls); } return cdef_class (); } static std::list<cdef_class> lookup_classes (const Cell& cls_list) { std::list<cdef_class> retval; for (int i = 0; i < cls_list.numel (); i++) { cdef_class c = lookup_class (cls_list(i)); if (! error_state) retval.push_back (c); else { retval.clear (); break; } } 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 is_superclass (const cdef_class& clsa, const cdef_class& clsb, bool allow_equal = true, int max_depth = -1) { bool retval = false; if (allow_equal && clsa == clsb) retval = true; else if (max_depth != 0) { Cell c = clsb.get ("SuperClasses").cell_value (); for (int i = 0; ! error_state && ! retval && i < c.numel (); i++) { cdef_class cls = lookup_class (c(i)); if (! error_state) retval = is_superclass (clsa, cls, true, max_depth < 0 ? max_depth : max_depth-1); } } 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 */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object") { cdef_class cls (to_cdef (args(0))); retval(0) = cls.get_properties (); } return retval; } static cdef_class 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_classdef_constructor () || fcn->is_anonymous_function_of_class () || (fcn->is_private_function () && ! fcn->dispatch_class ().empty ()))) { 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 in_class_method (const cdef_class& cls) { cdef_class ctx = get_class_context (); return (ctx.ok () && is_superclass (ctx, cls)); } static bool check_access (const cdef_class& cls, const octave_value& acc, const std::string& meth_name = std::string (), const std::string& prop_name = std::string (), bool is_prop_set = false) { if (acc.is_string ()) { std::string acc_s = acc.string_value (); if (acc_s == "public") return true; cdef_class ctx = get_class_context (); // 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") { if (is_superclass (cls, ctx)) // Calling a protected method in a superclass. return true; else if (is_strict_superclass (ctx, cls)) { // Calling a protected method or property in a derived class. // This is only allowed if the context class knows about it // and has access to it. if (! meth_name.empty ()) { cdef_method m = ctx.find_method (meth_name); if (m.ok ()) return check_access (ctx, m.get ("Access"), meth_name); return false; } else if (! prop_name.empty ()) { cdef_property p = ctx.find_property (prop_name); if (p.ok ()) { octave_value p_access = p.get (is_prop_set ? "SetAccess" : "GetAccess"); return check_access (ctx, p_access, meth_name, prop_name, is_prop_set); } return false; } else panic_impossible (); } return false; } else panic_impossible (); } } else if (acc.is_cell ()) { Cell acc_c = acc.cell_value (); cdef_class ctx = get_class_context (); // At this point, a class context is always required. if (! error_state && ctx.ok ()) { 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; } } } } else error ("invalid property/method access in class `%s'", cls.get_name ().c_str ()); 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) { octave_function* stack_fcn = octave_call_stack::current (); octave_function* method_fcn = ov.function_value (true); // Does the top of the call stack match our target function? if (stack_fcn && stack_fcn == method_fcn) { octave_user_function* uf = method_fcn->user_function_value (true); // We can only check the context object for user-function (not builtin), // where we have access to the parameters (arguments and return values). // That's ok as there's no need to call this function for builtin // methods. if (uf) { // At this point, the method is executing, but we still need to // check the context object for which the method is executing. For // methods, it's the first argument of the function; for ctors, it // is the first return value. tree_parameter_list* pl = uf->is_classdef_constructor () ? uf->return_list () : uf->parameter_list (); if (pl && pl->size () > 0) { octave_value arg0 = pl->front ()->lvalue ().value (); if (arg0.is_defined () && arg0.type_name () == "object") { cdef_object arg0_obj = to_cdef (arg0); return obj.is (arg0_obj); } } } } return false; } static octave_value_list class_get_methods (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object") { cdef_class cls (to_cdef (args(0))); retval(0) = cls.get_methods (); } return retval; } static octave_value_list class_get_superclasses (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object" && args(0).class_name () == "meta.class") { cdef_class cls (to_cdef (args(0))); Cell classes = cls.get ("SuperClasses").cell_value (); retval(0) = to_ov (lookup_classes (classes)); } return retval; } static octave_value_list class_get_inferiorclasses (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object" && args(0).class_name () == "meta.class") { cdef_class cls (to_cdef (args(0))); Cell classes = cls.get ("InferiorClasses").cell_value (); retval(0) = to_ov (lookup_classes (classes)); } return retval; } static octave_value_list class_fromName (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1) { std::string name = args(0).string_value (); if (! error_state) retval(0) = to_ov (lookup_class (name)); else error ("fromName: invalid class name, expected a string value"); } else error ("fromName: invalid number of parameters"); return retval; } static octave_value_list class_fevalStatic (const octave_value_list& args, int nargout) { octave_value_list retval; if (args.length () > 1 && args(0).type_name () == "object") { cdef_class cls (to_cdef (args(0))); if (! error_state) { std::string meth_name = args(1).string_value (); if (! error_state) { cdef_method meth = cls.find_method (meth_name); if (meth.ok ()) { if (meth.is_static ()) retval = meth.execute (args.splice (0, 2), nargout, true, "fevalStatic"); else error ("fevalStatic: method `%s' is not static", meth_name.c_str ()); } else error ("fevalStatic: method not found: %s", meth_name.c_str ()); } else error ("fevalStatic: invalid method name, expected a string value"); } error ("fevalStatic: invalid object, expected a meta.class object"); } else error ("fevalStatic: invalid arguments"); return retval; } static octave_value_list class_getConstant (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 2 && args(0).type_name () == "object" && args(0).class_name () == "meta.class") { cdef_class cls = to_cdef (args(0)); if (! error_state) { std::string prop_name = args(1).string_value (); if (! error_state) { cdef_property prop = cls.find_property (prop_name); if (prop.ok ()) { if (prop.is_constant ()) retval(0) = prop.get_value (true, "getConstant"); else error ("getConstant: property `%s' is not constant", prop_name.c_str ()); } else error ("getConstant: property not found: %s", prop_name.c_str ()); } else error ("getConstant: invalid property name, expected a string value"); } else error ("getConstant: invalid object, expected a meta.class object"); } else error ("getConstant: invalid arguments"); return retval; } #define META_CLASS_CMP(OP, CLSA, CLSB, FUN) \ static octave_value_list \ class_ ## OP (const octave_value_list& args, int /* nargout */) \ { \ octave_value_list retval; \ \ if (args.length () == 2 \ && args(0).type_name () == "object" \ && args(1).type_name () == "object" \ && args(0).class_name () == "meta.class" \ && args(1).class_name () == "meta.class") \ { \ cdef_class clsa = to_cdef (args(0)); \ \ cdef_class clsb = to_cdef (args(1)); \ \ if (! error_state) \ retval(0) = FUN (CLSA, CLSB); \ else \ error (#OP ": invalid objects, expected meta.class objects"); \ } \ else \ error (#OP ": invalid arguments"); \ \ return retval; \ } META_CLASS_CMP (lt, clsb, clsa, is_strict_superclass) META_CLASS_CMP (le, clsb, clsa, is_superclass) META_CLASS_CMP (gt, clsa, clsb, is_strict_superclass) META_CLASS_CMP (ge, clsa, clsb, is_superclass) 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 */) { octave_value_list retval; // FIXME: implement this return retval; } static cdef_class make_class (const std::string& name, const std::list<cdef_class>& super_list = std::list<cdef_class> ()) { cdef_class cls (name, super_list); cls.set_class (cdef_class::meta_class ()); cls.put ("Abstract", false); cls.put ("ConstructOnLoad", false); cls.put ("ContainingPackage", Matrix ()); cls.put ("Description", std::string ()); cls.put ("DetailedDescription", std::string ()); cls.put ("Events", Cell ()); cls.put ("Hidden", false); cls.put ("InferiorClasses", Cell ()); cls.put ("Methods", Cell ()); cls.put ("Properties", Cell ()); cls.put ("Sealed", false); if (name == "handle") { cls.put ("HandleCompatible", true); cls.mark_as_handle_class (); } else if (super_list.empty ()) { cls.put ("HandleCompatible", false); } else { 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 (); if (! name.empty ()) cdef_manager::register_class (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_class make_meta_class (const std::string& name, const cdef_class& super) { cdef_class cls = make_class (name, super); cls.put ("Sealed", true); cls.mark_as_meta_class (); return cls; } static cdef_property 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 (), const std::string& set_access = "public") { cdef_property prop (name); prop.set_class (cdef_class::meta_property ()); prop.put ("Description", std::string ()); prop.put ("DetailedDescription", std::string ()); prop.put ("Abstract", false); prop.put ("Constant", false); prop.put ("GetAccess", get_access); prop.put ("SetAccess", set_access); prop.put ("Dependent", false); prop.put ("Transient", false); prop.put ("Hidden", false); prop.put ("GetObservable", false); prop.put ("SetObservable", false); 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_class& cls, const std::string& name) { return make_property (cls, name, Matrix (), "public", Matrix (), "private"); } static cdef_method 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 (name); meth.set_class (cdef_class::meta_method ()); meth.put ("Abstract", false); meth.put ("Access", m_access); meth.put ("DefiningClass", to_ov (cls)); meth.put ("Description", std::string ()); meth.put ("DetailedDescription", std::string ()); meth.put ("Hidden", false); meth.put ("Sealed", true); meth.put ("Static", is_static); if (fcn.is_defined ()) make_function_of_class (cls, fcn); meth.set_function (fcn); if (is_dummy_method (fcn)) meth.mark_as_external (cls.get_name ()); return meth; } inline cdef_method 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)); return make_method (cls, name, fcn, m_access, is_static); } static cdef_package make_package (const std::string& nm, const std::string& parent = std::string ()) { cdef_package pack (nm); pack.set_class (cdef_class::meta_package ()); if (parent.empty ()) pack.put ("ContainingPackage", Matrix ()); else pack.put ("ContainingPackage", to_ov (cdef_manager::find_package (parent))); if (! nm.empty ()) cdef_manager::register_package (pack); return pack; } //---------------------------------------------------------------------------- int octave_classdef::t_id (-1); const std::string octave_classdef::t_name ("object"); void octave_classdef::register_type (void) { t_id = octave_value_typeinfo::register_type (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) { size_t skip = 0; octave_value_list retval; cdef_class cls = object.get_class (); if (! in_class_method (cls) && ! called_from_builtin ()) { cdef_method meth = cls.find_method ("subsref"); if (meth.ok ()) { octave_value_list args; args(1) = make_idx_args (type, idx, "subsref"); if (! error_state) { count++; args(0) = octave_value (this); retval = meth.execute (args, nargout, true, "subsref"); } return retval; } } // At this point, the default subsref mechanism must be used. retval = object.subsref (type, idx, nargout, skip, cdef_class ()); 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::subsref (const std::string& type, const std::list<octave_value_list>& idx, bool auto_add) { size_t skip = 0; octave_value_list retval; // This variant of subsref is used to create temporary values when doing // assignment with multi-level indexing. AFAIK this is only used for internal // purpose (not sure we should even implement this) and any overload subsref // should not be called. retval = object.subsref (type, idx, 1, skip, cdef_class (), auto_add); if (! error_state) { if (type.length () > skip && idx.size () > skip) retval = retval(0).next_subsref (1, type, idx, skip); } return retval.length () > 0 ? retval(0) : octave_value (); } octave_value octave_classdef::subsasgn (const std::string& type, const std::list<octave_value_list>& idx, const octave_value& rhs) { octave_value retval; cdef_class cls = object.get_class (); if (! in_class_method (cls) && ! called_from_builtin ()) { cdef_method meth = cls.find_method ("subsasgn"); if (meth.ok ()) { octave_value_list args; args(1) = make_idx_args (type, idx, "subsasgn"); if (! error_state) { count++; args(0) = octave_value (this); args(2) = rhs; octave_value_list retlist; retlist = meth.execute (args, 1, true, "subsasgn"); if (! error_state) { if (retlist.length () > 0) retval = retlist(0); else ::error ("overloaded method `subsasgn' did not return any value"); } } } } if (! error_state && ! retval.is_defined ()) retval = object.subsasgn (type, idx, rhs); return retval; } octave_value octave_classdef::undef_subsasgn (const std::string& type, const std::list<octave_value_list>& idx, const octave_value& rhs) { if (type.length () == 1 && type[0] == '(') { object = object.make_array (); if (! error_state) return subsasgn (type, idx, rhs); } else return octave_base_value::undef_subsasgn (type, idx, rhs); return octave_value (); } void octave_classdef::print (std::ostream& os, bool) { if (! called_from_builtin ()) { cdef_method meth = object.get_class ().find_method ("disp"); if (meth.ok ()) { octave_value_list args; count++; args(0) = octave_value (this); indent (os); meth.execute (args, 0, true, "disp"); return; } } print_raw (os); } void octave_classdef::print_raw (std::ostream& os, bool) const { indent (os); os << "<object "; if (object.is_array ()) os << "array "; os << class_name () << ">"; newline (os); } bool octave_classdef::print_name_tag (std::ostream& os, const std::string& name) const { return octave_base_value::print_name_tag (os, name); } void octave_classdef::print_with_name (std::ostream& os, const std::string& name, bool print_padding) { cdef_method meth = object.get_class ().find_method ("display"); if (meth.ok ()) { octave_value_list args; count++; args(0) = octave_value (this); string_vector arg_names (1); arg_names[0] = name; args.stash_name_tags (arg_names); indent (os); meth.execute (args, 0, true, "display"); } else octave_base_value::print_with_name (os, name, print_padding); } bool octave_classdef::is_instance_of (const std::string& cls_name) const { cdef_class cls = lookup_class (cls_name, false, false); if (cls.ok ()) return is_superclass (cls, object.get_class ()); return false; } //---------------------------------------------------------------------------- class octave_classdef_meta : public octave_function { public: octave_classdef_meta (const cdef_meta_object& obj) : object (obj) { } ~octave_classdef_meta (void) { object.meta_release (); } octave_function* function_value (bool = false) { return this; } octave_value_list subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout) { return object.meta_subsref (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) { // Emulate ()-type meta subsref std::list<octave_value_list> l (1, idx); std::string type ("("); return subsref (type, l, nargout); } bool is_postfix_index_handled (char type) const { return object.meta_is_postfix_index_handled (type); } bool is_classdef_constructor (const std::string& cname = std::string ()) const { bool retval = false; if (object.is_class ()) { if (cname.empty ()) retval = true; else { cdef_class cls (object); if (cls.get_name () == cname) retval = true; } } return retval; } private: cdef_meta_object object; }; //---------------------------------------------------------------------------- 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_function* function_value (bool = false) { return this; } octave_value_list subsref (const std::string& type, const std::list<octave_value_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<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) { 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 cname = args(1).string_value (); cdef_class cls = lookup_class (cname); if (! error_state) { if (in_constructor) { if (is_direct_superclass (cls, ctx)) { if (is_constructed_object (mname)) { octave_value sym = symbol_table::varval (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'", cname.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 code, 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 ()) retval = meth.execute (idx, nargout, true, meth_name); else ::error ("no method `%s' found in superclass `%s'", meth_name.c_str (), cname.c_str ()); } else ::error ("`%s' is not a superclass of `%s'", cname.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; }; //---------------------------------------------------------------------------- octave_map cdef_object::map_value (void) const { octave_map retval; warning_with_id ("Octave:classdef-to-struct", "struct: converting a classdef object into a struct " "overrides the access restrictions defined for properties. " "All properties are returned, including private and " "protected ones."); cdef_class cls = get_class (); if (cls.ok ()) { std::map<std::string, cdef_property> props; props = cls.get_property_map (cdef_class::property_all); for (std::map<std::string, cdef_property>::iterator it = props.begin (); it != props.end (); ++it) { octave_value pvalue; if (is_array ()) { Array<cdef_object> a_obj = array_value (); Cell cvalue (a_obj.dims ()); for (octave_idx_type i = 0; i < a_obj.numel (); i++) { cvalue (i) = it->second.get_value (a_obj(i), false); if (error_state) break; } if (! error_state) retval.setfield (it->first, cvalue); } else { Cell cvalue (dim_vector (1, 1), it->second.get_value (*this, false)); if (! error_state) retval.setfield (it->first, cvalue); } if (error_state) break; } } return retval; } string_vector cdef_object_rep::map_keys (void) const { cdef_class cls = get_class (); if (cls.ok ()) return cls.get_names (); return string_vector (); } octave_value_list cdef_object_scalar::subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout, size_t& skip, const cdef_class& context, bool auto_add) { skip = 0; cdef_class cls = (context.ok () ? context : get_class ()); octave_value_list retval; if (! cls.ok ()) return retval; switch (type[0]) { case '.': { std::string name = (idx.front ())(0).string_value (); cdef_method meth = cls.find_method (name); if (meth.ok ()) { int _nargout = (type.length () > 2 ? 1 : nargout); octave_value_list args; skip = 1; if (type.length () > 1 && type[1] == '(') { std::list<octave_value_list>::const_iterator it = idx.begin (); args = *++it; skip++; } if (meth.is_static ()) retval = meth.execute (args, _nargout, true, "subsref"); else { refcount++; retval = meth.execute (cdef_object (this), args, _nargout, true, "subsref"); } } if (skip == 0 && ! error_state) { cdef_property prop = cls.find_property (name); if (prop.ok ()) { if (prop.is_constant ()) retval(0) = prop.get_value (true, "subsref"); else { refcount++; retval(0) = prop.get_value (cdef_object (this), true, "subsref"); } skip = 1; } else error ("subsref: unknown method or property: %s", name.c_str ()); } break; } case '(': { refcount++; cdef_object this_obj (this); Array<cdef_object> arr (dim_vector (1, 1), this_obj); cdef_object new_obj = cdef_object (new cdef_object_array (arr)); new_obj.set_class (get_class ()); retval = new_obj.subsref (type, idx, nargout, skip, cls, auto_add); } break; default: error ("object cannot be indexed with `%c'", type[0]); break; } return retval; } octave_value cdef_object_scalar::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 (prop.is_constant ()) error ("subsasgn: cannot assign constant property: %s", name.c_str ()); else { refcount++; cdef_object obj (this); if (type.length () == 1) { prop.set_value (obj, rhs, true, "subsasgn"); if (! error_state) retval = to_ov (obj); } else { octave_value val = prop.get_value (obj, true, "subsasgn"); if (! error_state) { std::list<octave_value_list> args (idx); args.erase (args.begin ()); val = val.assign (octave_value::op_asn_eq, type.substr (1), args, rhs); if (! error_state) { if (val.class_name () != "object" || ! to_cdef (val).is_handle_object ()) prop.set_value (obj, val, true, "subsasgn"); if (! error_state) retval = to_ov (obj); } } } } } else error ("subsasgn: unknown property: %s", name.c_str ()); } } break; case '(': { refcount++; cdef_object this_obj (this); Array<cdef_object> arr (dim_vector (1, 1), this_obj); cdef_object new_obj = cdef_object (new cdef_object_array (arr)); new_obj.set_class (get_class ()); octave_value tmp = new_obj.subsasgn (type, idx, rhs); if (! error_state) retval = tmp; } break; default: error ("subsasgn: object cannot be index with `%c'", type[0]); break; } return retval; } void cdef_object_scalar::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<cdef_class> supcls_list = lookup_classes (supcls); if (! error_state) ctor_list[cls] = supcls_list; } } octave_value_list cdef_object_array::subsref (const std::string& type, const std::list<octave_value_list>& idx, int /* nargout */, size_t& skip, const cdef_class& /* context */, bool auto_add) { octave_value_list retval; skip = 1; switch (type[0]) { case '(': { const octave_value_list& ival = idx.front (); bool is_scalar = true; Array<idx_vector> iv (dim_vector (1, ival.length ())); for (int i = 0; ! error_state && i < ival.length (); i++) { iv(i) = ival(i).index_vector (); if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } if (! error_state) { Array<cdef_object> ires = array.index (iv, auto_add); if (! error_state) { // If resizing is enabled (auto_add = true), it's possible // indexing was out-of-bound and the result array contains // invalid cdef_objects. if (auto_add) fill_empty_values (ires); if (is_scalar) retval(0) = to_ov (ires(0)); else { cdef_object array_obj (new cdef_object_array (ires)); array_obj.set_class (get_class ()); retval(0) = to_ov (array_obj); } } } } break; case '.': if (type.size () == 1 && idx.size () == 1) { Cell c (dims ()); octave_idx_type n = array.numel (); // dummy variables size_t dummy_skip; cdef_class dummy_cls; for (octave_idx_type i = 0; i < n; i++) { octave_value_list r = array(i).subsref (type, idx, 1, dummy_skip, dummy_cls); if (! error_state) { if (r.length () > 0) c(i) = r(0); } else break; } if (! error_state) retval(0) = octave_value (c, true); break; } // fall through "default" default: ::error ("can't perform indexing operation on array of %s objects", class_name ().c_str ()); break; } return retval; } octave_value cdef_object_array::subsasgn (const std::string& type, const std::list<octave_value_list>& idx, const octave_value& rhs) { octave_value retval; switch (type[0]) { case '(': if (type.length () == 1) { cdef_object rhs_obj = to_cdef (rhs); if (! error_state) { if (rhs_obj.get_class () == get_class ()) { const octave_value_list& ival = idx.front (); bool is_scalar = true; Array<idx_vector> iv (dim_vector (1, ival.length ())); for (int i = 0; ! error_state && i < ival.length (); i++) { iv(i) = ival(i).index_vector (); if (! error_state) is_scalar = is_scalar && iv(i).is_scalar (); } if (! error_state) { Array<cdef_object> rhs_mat; if (! rhs_obj.is_array ()) { rhs_mat = Array<cdef_object> (dim_vector (1, 1)); rhs_mat(0) = rhs_obj; } else rhs_mat = rhs_obj.array_value (); if (! error_state) { octave_idx_type n = array.numel (); array.assign (iv, rhs_mat, cdef_object ()); if (! error_state) { if (array.numel () > n) fill_empty_values (); if (! error_state) { refcount++; retval = to_ov (cdef_object (this)); } } } } } else ::error ("can't assign %s object into array of %s objects.", rhs_obj.class_name ().c_str (), class_name ().c_str ()); } } else { const octave_value_list& ival = idx.front (); bool is_scalar = true; Array<idx_vector> iv (dim_vector (1, ival.length ())); for (int i = 0; ! error_state && i < ival.length (); i++) { iv(i) = ival(i).index_vector (); if (! error_state) { is_scalar = is_scalar && iv(i).is_scalar (); if (! is_scalar) error ("subsasgn: invalid indexing for object array " "assignment, the index must reference a single " "object in the array."); } } if (! error_state) { Array<cdef_object> a = array.index (iv, true); if (a.numel () != 1) error ("subsasgn: invalid indexing for object array " "assignment"); if (! error_state) { cdef_object obj = a(0); int ignore_copies = 0; // If the object in 'a' is not valid, this means the index // was out-of-bound and we need to create a new object. if (! obj.ok ()) obj = get_class ().construct_object (octave_value_list ()); else // Optimize the subsasgn call to come. There are 2 copies // that we can safely ignore: // - 1 in "array" // - 1 in "a" ignore_copies = 2; std::list<octave_value_list> next_idx (idx); next_idx.erase (next_idx.begin ()); octave_value tmp = obj.subsasgn (type.substr (1), next_idx, rhs, ignore_copies); if (! error_state) { cdef_object robj = to_cdef (tmp); if (robj.ok () && ! robj.is_array () && robj.get_class () == get_class ()) { // Small optimization, when dealing with handle // objects, we don't need to re-assign the result // of subsasgn back into the array. if (! robj.is (a(0))) { Array<cdef_object> rhs_a (dim_vector (1, 1), robj); octave_idx_type n = array.numel (); array.assign (iv, rhs_a); if (array.numel () > n) fill_empty_values (); } refcount++; retval = to_ov (cdef_object (this)); } else error ("subasgn: invalid assignment into array of %s " "objects", class_name ().c_str ()); } } } } break; default: ::error ("can't perform indexing operation on array of %s objects", class_name ().c_str ()); break; } return retval; } void cdef_object_array::fill_empty_values (Array<cdef_object>& arr) { cdef_class cls = get_class (); if (! error_state) { cdef_object obj; int n = arr.numel (); for (int i = 0; ! error_state && i < n; i++) { if (! arr.xelem (i).ok ()) { if (! obj.ok ()) { obj = cls.construct_object (octave_value_list ()); if (! error_state) arr.xelem (i) = obj; } else arr.xelem (i) = obj.copy (); } } } } bool cdef_object_scalar::is_constructed_for (const cdef_class& cls) const { return (is_constructed () || ctor_list.find (cls) == ctor_list.end ()); } bool cdef_object_scalar::is_partially_constructed_for (const cdef_class& cls) const { std::map< cdef_class, std::list<cdef_class> >::const_iterator it; if (is_constructed ()) return true; else if ((it = ctor_list.find (cls)) == ctor_list.end () || it->second.empty ()) return true; for (std::list<cdef_class>::const_iterator lit = it->second.begin (); lit != it->second.end (); ++lit) if (! is_constructed_for (*lit)) return false; return true; } handle_cdef_object::~handle_cdef_object (void) { #if DEBUG_TRACE std::cerr << "deleting " << get_class ().get_name () << " object (handle)" << std::endl; #endif } value_cdef_object::~value_cdef_object (void) { #if DEBUG_TRACE std::cerr << "deleting " << get_class ().get_name () << " object (value)" << std::endl; #endif } cdef_class::cdef_class_rep::cdef_class_rep (const std::list<cdef_class>& superclasses) : cdef_meta_object_rep (), member_count (0), handle_class (false), object_count (0), meta (false) { put ("SuperClasses", to_ov (superclasses)); implicit_ctor_list = superclasses; } cdef_method cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local) { method_iterator it = method_map.find (nm); if (it == method_map.end ()) { // FIXME: look into class directory } else { cdef_method& meth = it->second; // FIXME: check if method reload needed if (meth.ok ()) return meth; } if (! local) { // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (! error_state) { cdef_method meth = cls.find_method (nm); if (meth.ok ()) return meth; } } } return cdef_method (); } class ctor_analyzer : public tree_walker { public: ctor_analyzer (const std::string& ctor, const std::string& obj) : tree_walker (), who (ctor), obj_name (obj) { } 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 class_name = args(1).string_value (); cdef_class cls = lookup_class (class_name, false); if (cls.ok ()) ctor_list.push_back (cls); } } } } } std::list<cdef_class> 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<cdef_class> ctor_list; }; void cdef_class::cdef_class_rep::install_method (const cdef_method& meth) { method_map[meth.get_name ()] = meth; member_count++; 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); body->accept (a); if (! error_state) { std::list<cdef_class> explicit_ctor_list = a.get_constructor_list (); for (std::list<cdef_class>::const_iterator it = explicit_ctor_list.begin (); ! error_state && it != explicit_ctor_list.end (); ++it) { #if DEBUG_TRACE std::cerr << "explicit superclass constructor: " << it->get_name () << std::endl; #endif implicit_ctor_list.remove (*it); } } } else ::error ("%s: invalid constructor output arguments", meth.get_name ().c_str ()); } } } } void cdef_class::cdef_class_rep::load_all_methods (void) { // FIXME: re-scan class directory } Cell cdef_class::cdef_class_rep::get_methods (void) { std::map<std::string,cdef_method> meths; find_methods (meths, false); if (! error_state) { Cell c (meths.size (), 1); int idx = 0; for (std::map<std::string,cdef_method>::const_iterator it = meths.begin (); it != meths.end (); ++it, ++idx) c (idx, 0) = to_ov (it->second); return c; } return Cell (); } void cdef_class::cdef_class_rep::find_methods (std::map<std::string, cdef_method>& meths, bool only_inherited) { load_all_methods (); method_const_iterator it; for (it = method_map.begin (); it != method_map.end (); ++it) { if (! it->second.is_constructor ()) { std::string nm = it->second.get_name (); if (meths.find (nm) == meths.end ()) { if (only_inherited) { octave_value acc = it->second.get ("Access"); if (! acc.is_string () || acc.string_value () == "private") continue; } meths[nm] = it->second; } } } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (! error_state) cls.get_rep ()->find_methods (meths, true); else break; } } cdef_property cdef_class::cdef_class_rep::find_property (const std::string& nm) { property_iterator it = property_map.find (nm); if (it != property_map.end ()) { cdef_property& prop = it->second; if (prop.ok ()) return prop; } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (! error_state) { cdef_property prop = cls.find_property (nm); if (prop.ok ()) return prop; } } return cdef_property (); } void cdef_class::cdef_class_rep::install_property (const cdef_property& prop) { property_map[prop.get_name ()] = prop; member_count++; } Cell cdef_class::cdef_class_rep::get_properties (int mode) { std::map<std::string,cdef_property> props; props = get_property_map (mode); if (! error_state) { Cell c (props.size (), 1); int idx = 0; for (std::map<std::string,cdef_property>::const_iterator it = props.begin (); it != props.end (); ++it, ++idx) c (idx, 0) = to_ov (it->second); return c; } return Cell (); } std::map<std::string, cdef_property> cdef_class::cdef_class_rep::get_property_map (int mode) { std::map<std::string,cdef_property> props; find_properties (props, mode); return props; } void cdef_class::cdef_class_rep::find_properties (std::map<std::string, cdef_property>& props, int mode) { property_const_iterator 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 ()) { if (mode == property_inherited) { octave_value acc = it->second.get ("GetAccess"); if (! acc.is_string () || acc.string_value () == "private") continue; } props[nm] = it->second; } } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; ! error_state && i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (! error_state) cls.get_rep ()->find_properties (props, (mode == property_all ? property_all : property_inherited)); else break; } } void cdef_class::cdef_class_rep::find_names (std::set<std::string>& names, bool all) { load_all_methods (); for (method_const_iterator it = method_map.begin (); ! error_state && it != method_map.end(); ++it) { if (! it->second.is_constructor ()) { std::string nm = it->second.get_name (); if (! all) { octave_value acc = it->second.get ("Access"); if (! acc.is_string() || acc.string_value () != "public") continue; } names.insert (nm); } } for (property_const_iterator it = property_map.begin (); ! error_state && it != property_map.end (); ++it) { std::string nm = it->second.get_name (); if (! all) { octave_value acc = it->second.get ("GetAccess"); 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; ! error_state && i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (! error_state) cls.get_rep ()->find_names (names, all); else break; } } string_vector cdef_class::cdef_class_rep::get_names (void) { std::set<std::string> names; find_names (names, false); if (! error_state) { string_vector v (names.size ()); int idx = 0; for (std::set<std::string>::const_iterator it = names.begin (); it != names.end (); ++it, ++idx) v[idx] = *it; return v.sort (true); } return string_vector (); } void cdef_class::cdef_class_rep::delete_object (cdef_object obj) { method_iterator it = method_map.find ("delete"); if (it != method_map.end ()) { cdef_class cls = obj.get_class (); obj.set_class (wrap ()); it->second.execute (obj, octave_value_list (), 0, false); obj.set_class (cls); } // FIXME: should we destroy corresponding properties here? // Call "delete" in super classes Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (!error_state) cls.delete_object (obj); } } octave_value_list cdef_class::cdef_class_rep::meta_subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout) { size_t skip = 1; octave_value_list retval; switch (type[0]) { case '(': // Constructor call #if DEBUG_TRACE std::cerr << "constructor" << std::endl; #endif retval(0) = construct (idx.front ()); break; case '.': // Static method, constant (or property?) #if DEBUG_TRACE std::cerr << "static method/property" << std::endl; #endif if (idx.front ().length () == 1) { std::string nm = idx.front ()(0).string_value (); if (! error_state) { cdef_method meth = find_method (nm); if (meth.ok ()) { if (meth.is_static ()) { octave_value_list args; if (type.length () > 1 && idx.size () > 1 && type[1] == '(') { args = *(++(idx.begin ())); skip++; } retval = meth.execute (args, (type.length () > skip ? 1 : nargout), true, "meta.class"); } else ::error ("method `%s' is not static", nm.c_str ()); } else { cdef_property prop = find_property (nm); if (prop.ok ()) { if (prop.is_constant ()) retval(0) = prop.get_value (true, "meta.class"); else ::error ("property `%s' is not constant", nm.c_str ()); } else ::error ("no such method or property `%s'", nm.c_str ()); } } else ::error ("invalid meta.class indexing, expected a method or property name"); } else ::error ("invalid meta.class indexing"); break; default: ::error ("invalid meta.class indexing"); break; } if (! error_state) { if (type.length () > skip && idx.size () > skip && ! retval.empty ()) retval = retval(0).next_subsref (nargout, type, idx, skip); } return retval; } void cdef_class::cdef_class_rep::meta_release (void) { cdef_manager::unregister_class (wrap ()); } 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 ())); } } if (! error_state) { refcount++; obj.mark_for_construction (cdef_class (this)); } } } } void cdef_class::cdef_class_rep::run_constructor (cdef_object& obj, const octave_value_list& args) { octave_value_list empty_args; for (std::list<cdef_class>::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 ()) { octave_value_list ctor_args (args); octave_value_list ctor_retval; ctor_args.prepend (to_ov (obj)); ctor_retval = ctor.execute (ctor_args, 1, true, "constructor"); if (! error_state) { 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 ()); return; } } } obj.mark_as_constructed (wrap ()); } octave_value cdef_class::cdef_class_rep::construct (const octave_value_list& args) { cdef_object obj = construct_object (args); if (! error_state && obj.ok ()) return to_ov (obj); return octave_value (); } cdef_object cdef_class::cdef_class_rep::construct_object (const octave_value_list& args) { if (! is_abstract ()) { cdef_object obj; if (is_meta_class ()) { // This code path is only used to create empty meta objects // as filler for the empty values within a meta object array. cdef_class this_cls = wrap (); static cdef_object empty_class; if (this_cls == cdef_class::meta_class ()) { if (! empty_class.ok ()) empty_class = make_class ("", std::list<cdef_class> ()); obj = empty_class; } else if (this_cls == cdef_class::meta_property ()) { static cdef_property empty_property; if (! empty_class.ok ()) empty_class = make_class ("", std::list<cdef_class> ()); if (! empty_property.ok ()) empty_property = make_property (empty_class, ""); obj = empty_property; } else if (this_cls == cdef_class::meta_method ()) { static cdef_method empty_method; if (! empty_class.ok ()) empty_class = make_class ("", std::list<cdef_class> ()); if (! empty_method.ok ()) empty_method = make_method (empty_class, "", octave_value ()); obj = empty_method; } else if (this_cls == cdef_class::meta_package ()) { static cdef_package empty_package; if (! empty_package.ok ()) empty_package = make_package (""); obj = empty_package; } else panic_impossible (); return obj; } else { if (is_handle_class ()) obj = cdef_object (new handle_cdef_object ()); else obj = cdef_object (new value_cdef_object ()); obj.set_class (wrap ()); initialize_object (obj); if (! error_state) { run_constructor (obj, args); if (! error_state) return obj; } } } else error ("cannot instantiate object for abstract class `%s'", get_name ().c_str ()); return cdef_object (); } 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 (tree_classdef* t, bool is_at_folder) { cdef_class retval; std::string class_name, full_class_name; // Class creation class_name = full_class_name = t->ident ()->name (); if (! t->package_name ().empty ()) full_class_name = t->package_name () + "." + full_class_name; #if DEBUG_TRACE std::cerr << "class: " << full_class_name << std::endl; #endif 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)->class_name (); #if DEBUG_TRACE std::cerr << "superclass: " << sclass_name << std::endl; #endif cdef_class sclass = lookup_class (sclass_name); if (! error_state) { if (! sclass.get ("Sealed").bool_value ()) slist.push_back (sclass); else { ::error ("`%s' cannot inherit from `%s', because it is sealed", full_class_name.c_str (), sclass_name.c_str ()); return retval; } } else return retval; } } retval = ::make_class (full_class_name, slist); if (error_state) return cdef_class (); // Package owning this class if (! t->package_name ().empty ()) { cdef_package pack = cdef_manager::find_package (t->package_name ()); if (! error_state && pack.ok ()) retval.put ("ContainingPackage", to_ov (pack)); } // 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); #if DEBUG_TRACE std::cerr << "class attribute: " << aname << " = " << attribute_value_to_string (*it, avalue) << std::endl; #endif retval.put (aname, avalue); } } tree_classdef_body* b = t->body (); if (b) { // Keep track of the get/set accessor methods. They will be used // later on when creating properties. std::map<std::string, octave_value> get_methods; std::map<std::string, octave_value> set_methods; // 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; #if DEBUG_TRACE std::cerr << "method block" << std::endl; #endif // 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); #if DEBUG_TRACE std::cerr << "method attribute: " << aname << " = " << attribute_value_to_string (*ait, avalue) << std::endl; #endif 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 (); std::string mprefix = mname.substr (0, 4); if (mprefix == "get.") get_methods[mname.substr (4)] = make_fcn_handle (*mit, full_class_name + ">" + mname); else if (mprefix == "set.") set_methods[mname.substr (4)] = make_fcn_handle (*mit, full_class_name + ">" + mname); else { cdef_method meth = make_method (retval, mname, *mit); #if DEBUG_TRACE std::cerr << (mname == class_name ? "constructor" : "method") << ": " << mname << std::endl; #endif 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); } } } } 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 // 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; #if DEBUG_TRACE std::cerr << "property block" << std::endl; #endif // 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); #if DEBUG_TRACE std::cerr << "property attribute: " << aname << " = " << attribute_value_to_string (*ait, avalue) << std::endl; #endif 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) { std::string prop_name = (*pit)->ident ()->name (); cdef_property prop = ::make_property (retval, prop_name); #if DEBUG_TRACE std::cerr << "property: " << (*pit)->ident ()->name () << std::endl; #endif if ((*pit)->expression ()) { octave_value pvalue = (*pit)->expression ()->rvalue1 (); #if DEBUG_TRACE std::cerr << "property default: " << attribute_value_to_string (*pit, pvalue) << std::endl; #endif prop.put ("DefaultValue", pvalue); } // Install property attributes. This is done before assigning // the property accessors so we can do validationby using // cdef_property methods. for (std::map<std::string, octave_value>::iterator ait = amap.begin (); ait != amap.end (); ++ait) prop.put (ait->first, ait->second); // Install property access methods, if any. Remove the // accessor methods from the temporary storage map, so we can // detect which ones are invalid and do not correspond to a // defined property. std::map<std::string, octave_value>::iterator git = get_methods.find (prop_name); if (git != get_methods.end ()) { make_function_of_class (retval, git->second); prop.put ("GetMethod", git->second); get_methods.erase (git); } std::map<std::string, octave_value>::iterator sit = set_methods.find (prop_name); if (sit != set_methods.end ()) { make_function_of_class (retval, sit->second); prop.put ("SetMethod", sit->second); set_methods.erase (sit); } retval.install_property (prop); } } } } return retval; } octave_function* cdef_class::get_method_function (const std::string& /* nm */) { octave_classdef_meta* p = new octave_classdef_meta (*this); return p; } octave_value cdef_property::cdef_property_rep::get_value (const cdef_object& obj, bool do_check_access, const std::string& who) { octave_value retval; if (do_check_access && ! check_get_access ()) { gripe_property_access (who, wrap (), false); return retval; } if (! obj.is_constructed ()) { cdef_class cls (to_cdef (get ("DefiningClass"))); if (! obj.is_partially_constructed_for (cls)) { ::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 () || is_method_executing (get_fcn, obj)) retval = obj.get (get ("Name").string_value ()); else { octave_value_list args; args(0) = to_ov (obj); args = execute_ov (get_fcn, args, 1); if (! error_state) retval = args(0); } return retval; } octave_value cdef_property::cdef_property_rep::get_value (bool do_check_access, const std::string& who) { if (do_check_access && ! check_get_access ()) { gripe_property_access (who, wrap (), false); return octave_value (); } return get ("DefaultValue"); } bool 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, bool do_check_access, const std::string& who) { if (do_check_access && ! check_set_access ()) { gripe_property_access (who, wrap (), true); return; } if (! obj.is_constructed ()) { cdef_class cls (to_cdef (get ("DefiningClass"))); if (! obj.is_partially_constructed_for (cls)) { ::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_method_executing (set_fcn, 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 && args(0).is_defined ()) { if (args (0).is_classdef_object ()) { cdef_object new_obj = to_cdef (args(0)); if (! error_state) obj = new_obj; } else ::warning ("set-method of property `%s' returned a non-classdef object", get_name ().c_str ()); } } } } bool cdef_property::cdef_property_rep::check_get_access (void) const { cdef_class cls (to_cdef (get ("DefiningClass"))); if (! error_state) return ::check_access (cls, get ("GetAccess"), std::string (), get_name (), false); return false; } bool cdef_property::cdef_property_rep::check_set_access (void) const { cdef_class cls (to_cdef (get ("DefiningClass"))); if (! error_state) return ::check_access (cls, get ("SetAccess"), std::string (), get_name (), true); return false; } void cdef_method::cdef_method_rep::check_method (void) { 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 cdef_method::cdef_method_rep::execute (const octave_value_list& args, int nargout, bool do_check_access, const std::string& who) { octave_value_list retval; if (do_check_access && ! check_access ()) { gripe_method_access (who, wrap ()); return retval; } if (! get ("Abstract").bool_value ()) { check_method (); if (! error_state && function.is_defined ()) { retval = execute_ov (function, args, nargout); } } else error ("%s: cannot execute abstract method", get ("Name").string_value ().c_str ()); return retval; } octave_value_list cdef_method::cdef_method_rep::execute (const cdef_object& obj, const octave_value_list& args, int nargout, bool do_check_access, const std::string& who) { octave_value_list retval; if (do_check_access && ! check_access ()) { gripe_method_access (who, wrap ()); return retval; } if (! get ("Abstract").bool_value ()) { check_method (); if (! error_state && function.is_defined ()) { octave_value_list new_args; new_args.resize (args.length () + 1); new_args(0) = to_ov (obj); for (int i = 0; i < args.length (); i++) new_args(i+1) = args(i); retval = execute_ov (function, new_args, nargout); } } else error ("%s: cannot execute abstract method", get ("Name").string_value ().c_str ()); return retval; } 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::cdef_method_rep::check_access (void) const { cdef_class cls (to_cdef (get ("DefiningClass"))); if (! error_state) return ::check_access (cls, get ("Access"), get_name ()); return false; } octave_value_list cdef_method::cdef_method_rep::meta_subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout) { octave_value_list retval; switch (type[0]) { case '(': retval = execute (idx.front (), type.length () > 1 ? 1 : nargout, true); break; default: error ("invalid meta.method indexing"); break; } if (! error_state) { if (type.length () > 1 && idx.size () > 1 && ! retval.empty ()) retval = retval(0).next_subsref (nargout, type, idx, 1); } return retval; } static cdef_package lookup_package (const std::string& name) { return cdef_manager::find_package (name); } static octave_value_list package_fromName (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1) { std::string name = args(0).string_value (); if (! error_state) retval(0) = to_ov (lookup_package (name)); else error ("fromName: invalid package name, expected a string value"); } else error ("fromName: invalid number of parameters"); return retval; } static octave_value_list package_get_classes (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 1 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_classes (); } return retval; } static octave_value_list package_get_functions (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 0 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_functions (); } return retval; } static octave_value_list package_get_packages (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 0 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_packages (); } return retval; } static octave_value_list package_getAllPackages (const octave_value_list& /* args */, int /* nargout */) { std::map<std::string, cdef_package> toplevel_packages; std::list<std::string> names = load_path::get_all_package_names (); toplevel_packages["meta"] = cdef_manager::find_package ("meta", false, false); for (std::list<std::string>::const_iterator it = names.begin (); it != names.end (); ++it) toplevel_packages[*it] = cdef_manager::find_package (*it, false, true); Cell c (toplevel_packages.size (), 1); int i = 0; for (std::map<std::string, cdef_package>::const_iterator it = toplevel_packages.begin (); it != toplevel_packages.end (); ++it) c(i++,0) = to_ov (it->second); return octave_value_list (octave_value (c)); } void cdef_package::cdef_package_rep::install_class (const cdef_class& cls, const std::string& nm) { class_map[nm] = cls; member_count++; } void cdef_package::cdef_package_rep::install_function (const octave_value& fcn, const std::string& nm) { function_map[nm] = fcn; } void cdef_package::cdef_package_rep::install_package (const cdef_package& pack, const std::string& nm) { package_map[nm] = pack; member_count++; } template<class T1, class T2> Cell map2Cell (const std::map<T1, T2>& m) { Cell retval (1, m.size ()); int i = 0; for (typename std::map<T1, T2>::const_iterator it = m.begin (); it != m.end (); ++it, ++i) { retval(i) = to_ov (it->second); } return retval; } Cell cdef_package::cdef_package_rep::get_classes (void) const { return map2Cell (class_map); } Cell cdef_package::cdef_package_rep::get_functions (void) const { return map2Cell (function_map); } Cell cdef_package::cdef_package_rep::get_packages (void) const { return map2Cell (package_map); } octave_value cdef_package::cdef_package_rep::find (const std::string& nm) { std::string symbol_name = get_name () + "." + nm; return symbol_table::find (symbol_name, octave_value_list (), true, false); } octave_value_list cdef_package::cdef_package_rep::meta_subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout) { octave_value_list retval; switch (type[0]) { case '.': if (idx.front ().length () == 1) { std::string nm = idx.front ()(0).string_value (); if (! error_state) { #if DEBUG_TRACE std::cerr << "meta.package query: " << nm << std::endl; #endif octave_value o = find (nm); if (o.is_defined ()) { if (o.is_function ()) { octave_function* fcn = o.function_value (); if (! error_state) { // NOTE: the case where the package query is the last // part of this subsref index is handled in the parse // tree, because there is some logic to handle magic // "end" that makes it impossible to execute the // function call at this stage. if (type.size () > 1 && ! fcn->is_postfix_index_handled (type[1])) { octave_value_list tmp_args; retval = o.do_multi_index_op (nargout, tmp_args); } else retval(0) = o; if (type.size () > 1 && idx.size () > 1) retval = retval(0).next_subsref (nargout, type, idx, 1); } } else if (type.size () > 1 && idx.size () > 1) retval = o.next_subsref (nargout, type, idx, 1); else retval(0) = o; } else if (! error_state) error ("member `%s' in package `%s' does not exist", nm.c_str (), get_name ().c_str ()); } else error ("invalid meta.package indexing, expected a symbol name"); } else error ("invalid meta.package indexing"); break; default: error ("invalid meta.package indexing"); break; } return retval; } void cdef_package::cdef_package_rep::meta_release (void) { // FIXME: Do we really want to unregister the package, as it // could still be referenced by classes or sub-packages? // If the package object is recreated later on, it won't // match the one already referenced by those classes or // sub-packages. //cdef_manager::unregister_package (wrap ()); } cdef_class cdef_class::_meta_class = cdef_class (); cdef_class cdef_class::_meta_property = cdef_class (); cdef_class cdef_class::_meta_method = cdef_class (); cdef_class cdef_class::_meta_package = cdef_class (); cdef_package cdef_package::_meta = cdef_package (); void install_classdef (void) { octave_classdef::register_type (); /* bootstrap */ cdef_class handle = make_class ("handle"); cdef_class meta_class = cdef_class::_meta_class = make_meta_class ("meta.class", handle); handle.set_class (meta_class); meta_class.set_class (meta_class); /* meta classes */ cdef_class meta_property = cdef_class::_meta_property = make_meta_class ("meta.property", handle); cdef_class meta_method = cdef_class::_meta_method = make_meta_class ("meta.method", handle); cdef_class meta_package = cdef_class::_meta_package = make_meta_class ("meta.package", handle); cdef_class meta_event = make_meta_class ("meta.event", handle); cdef_class meta_dynproperty = make_meta_class ("meta.dynamicproperty", handle); /* meta.class properties */ meta_class.install_property (make_attribute (meta_class, "Abstract")); meta_class.install_property (make_attribute (meta_class, "ConstructOnLoad")); meta_class.install_property (make_property (meta_class, "ContainingPackage")); 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", make_fcn_handle (class_get_inferiorclasses, "meta.class>get.InferiorClasses"), "public", Matrix (), "private")); meta_class.install_property (make_property (meta_class, "Methods", make_fcn_handle (class_get_methods, "meta.class>get.Methods"), "public", Matrix (), "private")); meta_class.install_property (make_property (meta_class, "MethodList", make_fcn_handle (class_get_methods, "meta.class>get.MethodList"), "public", Matrix (), "private")); meta_class.install_property (make_attribute (meta_class, "Name")); meta_class.install_property (make_property (meta_class, "Properties", make_fcn_handle (class_get_properties, "meta.class>get.Properties"), "public", Matrix (), "private")); meta_class.install_property (make_property (meta_class, "PropertyList", make_fcn_handle (class_get_properties, "meta.class>get.PropertyList"), "public", Matrix (), "private")); meta_class.install_property (make_attribute (meta_class, "Sealed")); meta_class.install_property (make_property (meta_class, "SuperClasses", make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClasses"), "public", Matrix (), "private")); meta_class.install_property (make_property (meta_class, "SuperClassList", make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClassList"), "public", Matrix (), "private")); /* meta.class methods */ meta_class.install_method (make_method (meta_class, "fromName", class_fromName, "public", true)); meta_class.install_method (make_method (meta_class, "fevalStatic", class_fevalStatic, "public", false)); meta_class.install_method (make_method (meta_class, "getConstant", class_getConstant, "public", false)); meta_class.install_method (make_method (meta_class, "eq", class_eq)); meta_class.install_method (make_method (meta_class, "ne", class_ne)); meta_class.install_method (make_method (meta_class, "lt", class_lt)); meta_class.install_method (make_method (meta_class, "le", class_le)); meta_class.install_method (make_method (meta_class, "gt", class_gt)); meta_class.install_method (make_method (meta_class, "ge", class_ge)); /* meta.method properties */ meta_method.install_property (make_attribute (meta_method, "Abstract")); meta_method.install_property (make_attribute (meta_method, "Access")); meta_method.install_property (make_attribute (meta_method, "DefiningClass")); meta_method.install_property (make_attribute (meta_method, "Description")); meta_method.install_property (make_attribute (meta_method, "DetailedDescription")); meta_method.install_property (make_attribute (meta_method, "Hidden")); meta_method.install_property (make_attribute (meta_method, "Name")); meta_method.install_property (make_attribute (meta_method, "Sealed")); meta_method.install_property (make_attribute (meta_method, "Static")); /* meta.property properties */ meta_property.install_property (make_attribute (meta_property, "Name")); meta_property.install_property (make_attribute (meta_property, "Description")); meta_property.install_property (make_attribute (meta_property, "DetailedDescription")); meta_property.install_property (make_attribute (meta_property, "Abstract")); meta_property.install_property (make_attribute (meta_property, "Constant")); meta_property.install_property (make_attribute (meta_property, "GetAccess")); meta_property.install_property (make_attribute (meta_property, "SetAccess")); meta_property.install_property (make_attribute (meta_property, "Dependent")); meta_property.install_property (make_attribute (meta_property, "Transient")); meta_property.install_property (make_attribute (meta_property, "Hidden")); meta_property.install_property (make_attribute (meta_property, "GetObservable")); meta_property.install_property (make_attribute (meta_property, "SetObservable")); 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 /* handle methods */ handle.install_method (make_method (handle, "delete", handle_delete)); /* meta.package properties */ meta_package.install_property (make_attribute (meta_package, "Name")); meta_package.install_property (make_property (meta_package, "ContainingPackage")); meta_package.install_property (make_property (meta_package, "ClassList", make_fcn_handle (package_get_classes, "meta.package>get.ClassList"), "public", Matrix (), "private")); meta_package.install_property (make_property (meta_package, "Classes", make_fcn_handle (package_get_classes, "meta.package>get.Classes"), "public", Matrix (), "private")); meta_package.install_property (make_property (meta_package, "FunctionList", make_fcn_handle (package_get_functions, "meta.package>get.FunctionList"), "public", Matrix (), "private")); meta_package.install_property (make_property (meta_package, "Functions", make_fcn_handle (package_get_functions, "meta.package>get.Functions"), "public", Matrix (), "private")); meta_package.install_property (make_property (meta_package, "PackageList", make_fcn_handle (package_get_packages, "meta.package>get.PackageList"), "public", Matrix (), "private")); meta_package.install_property (make_property (meta_package, "Packages", make_fcn_handle (package_get_packages, "meta.package>get.Packages"), "public", Matrix (), "private")); meta_package.install_method (make_method (meta_package, "fromName", package_fromName, "public", true)); meta_package.install_method (make_method (meta_package, "getAllPackages", package_getAllPackages, "public", true)); /* create "meta" package */ cdef_package package_meta = cdef_package::_meta = make_package ("meta"); package_meta.install_class (meta_class, "class"); package_meta.install_class (meta_property, "property"); package_meta.install_class (meta_method, "method"); package_meta.install_class (meta_package, "package"); package_meta.install_class (meta_event, "event"); package_meta.install_class (meta_dynproperty, "dynproperty"); /* install built-in classes into the symbol table */ symbol_table::install_built_in_function ("meta.class", octave_value (meta_class.get_constructor_function ())); symbol_table::install_built_in_function ("meta.method", octave_value (meta_method.get_constructor_function ())); symbol_table::install_built_in_function ("meta.property", octave_value (meta_property.get_constructor_function ())); symbol_table::install_built_in_function ("meta.package", octave_value (meta_package.get_constructor_function ())); symbol_table::install_built_in_function ("meta.event", octave_value (meta_event.get_constructor_function ())); symbol_table::install_built_in_function ("meta.dynproperty", octave_value (meta_dynproperty.get_constructor_function ())); } //---------------------------------------------------------------------------- cdef_manager* cdef_manager::instance = 0; void cdef_manager::create_instance (void) { instance = new cdef_manager (); if (instance) singleton_cleanup_list::add (cleanup_instance); } cdef_class cdef_manager::do_find_class (const std::string& name, bool error_if_not_found, bool load_if_not_found) { std::map<std::string, cdef_class>::iterator it = all_classes.find (name); if (it == all_classes.end ()) { if (load_if_not_found) { octave_value ov_cls; size_t pos = name.rfind ('.'); if (pos == std::string::npos) ov_cls = symbol_table::find (name); else { std::string pack_name = name.substr (0, pos); cdef_package pack = do_find_package (pack_name, false, true); if (pack.ok ()) ov_cls = pack.find (name.substr (pos+1)); } if (ov_cls.is_defined ()) it = all_classes.find (name); } } if (it == all_classes.end ()) { if (error_if_not_found) error ("class not found: %s", name.c_str ()); } else { cdef_class cls = it->second; if (! cls.is_builtin ()) cls = lookup_class (cls); if (cls.ok ()) return cls; else all_classes.erase (it); } return cdef_class (); } octave_function* cdef_manager::do_find_method_symbol (const std::string& method_name, const std::string& class_name) { octave_function *retval = 0; cdef_class cls = find_class (class_name, false, false); if (cls.ok ()) { cdef_method meth = cls.find_method (method_name); if (meth.ok ()) retval = new octave_classdef_meta (meth); } return retval; } cdef_package cdef_manager::do_find_package (const std::string& name, bool error_if_not_found, bool load_if_not_found) { cdef_package retval; std::map<std::string, cdef_package>::const_iterator it = all_packages.find (name); if (it != all_packages.end ()) { retval = it->second; if (! retval.ok ()) error ("invalid package `%s'", name.c_str ()); } else { if (load_if_not_found && load_path::find_package (name)) { size_t pos = name.find ('.'); if (pos == std::string::npos) retval = make_package (name, std::string ()); else { std::string parent_name = name.substr (0, pos); retval = make_package (name, parent_name); } } else if (error_if_not_found) error ("unknown package `%s'", name.c_str ()); } return retval; } octave_function* cdef_manager::do_find_package_symbol (const std::string& pack_name) { octave_function* retval = 0; cdef_package pack = find_package (pack_name, false, false); if (pack.ok ()) retval = new octave_classdef_meta (pack); return retval; } //---------------------------------------------------------------------------- DEFUN (__meta_get_package__, args, , "") { octave_value retval; if (args.length () == 1) { std::string cname = args(0).string_value (); if (! error_state) retval = to_ov (lookup_package (cname)); else error ("invalid package name, expected a string value"); } else print_usage (); return retval; } DEFUN (__superclass_reference__, args, /* nargout */, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} __superclass_reference__ ()\n\ Undocumented internal function.\n\ @end deftypefn") { return octave_value (new octave_classdef_superclass_ref (args)); } DEFUN (__meta_class_query__, args, /* nargout */, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} __meta_class_query__ ()\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value retval; #if DEBUG_TRACE std::cerr << "__meta_class_query__ (" << args(0).string_value () << ")" << std::endl; #endif if (args.length () == 1) { std::string cls = args(0).string_value (); if (! error_state) retval = to_ov (lookup_class (cls)); else error ("invalid class name, expected a string value"); } else print_usage (); return retval; } DEFUN (metaclass, args, /* nargout */, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} metaclass (obj)\n\ Returns the meta.class object corresponding to the class of @var{obj}.\n\ @end deftypefn") { octave_value retval; if (args.length () == 1) { cdef_object obj = to_cdef (args(0)); if (! error_state) retval = to_ov (obj.get_class ()); else print_usage (); } else print_usage (); return retval; } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */