Mercurial > hg > octave-nkf
changeset 15036:aa1f9e479c6e classdef
octave_value classdef objects
* ov-classdef.h, ov-classdef.cc: New files.
* octave.cc: Include ov-classdef.h.
(octave_main): Call install_classdef.
* src/Makefile.am (OV_SRC): Add ov-classdef.cc to the list.
(OV_INCLUDES): Add ov-classdef.h to the list.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Fri, 27 Jul 2012 16:02:01 -0400 |
parents | a820a990968e |
children | 56b8eb7c9c04 |
files | src/Makefile.am src/octave.cc src/ov-classdef.cc src/ov-classdef.h |
diffstat | 4 files changed, 2161 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,6 +163,7 @@ ov-cell.h \ ov-ch-mat.h \ ov-class.h \ + ov-classdef.h \ ov-colon.h \ ov-complex.h \ ov-cs-list.h \ @@ -350,6 +351,7 @@ ov-cell.cc \ ov-ch-mat.cc \ ov-class.cc \ + ov-classdef.cc \ ov-colon.cc \ ov-complex.cc \ ov-cs-list.cc \
--- a/src/octave.cc +++ b/src/octave.cc @@ -62,6 +62,7 @@ #include "oct-obj.h" #include "ops.h" #include "ov.h" +#include "ov-classdef.h" #include "ov-range.h" #include "toplev.h" #include "parse.h" @@ -682,6 +683,8 @@ install_builtins (); + install_classdef (); + bool forced_line_editing = false; bool read_history_file = true;
new file mode 100644 --- /dev/null +++ b/src/ov-classdef.cc @@ -0,0 +1,1415 @@ +/* + +Copyright (C) 2012 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 <map> + +#include "defun.h" +#include "ov-builtin.h" +#include "ov-classdef.h" +#include "ov-fcn-handle.h" +#include "ov-typeinfo.h" + +static std::map<std::string, cdef_class> all_classes; +static std::map<std::string, cdef_package> all_packages; + +static void +gripe_method_access (const std::string& from, const cdef_method& meth) +{ + error ("%s: method `%s' has %s access and cannot be run in this context", + from.c_str (), meth.get_name ().c_str (), + meth.get_access ().c_str ()); +} + +static void +gripe_property_access (const std::string& from, const cdef_property& prop, + bool is_set = false) +{ + if (is_set) + error ("%s: property `%s' has %s access and cannot be set in this context", + from.c_str (), prop.get_name ().c_str (), + prop.get_set_access ().c_str ()); + else + error ("%s: property `%s' has %s access and cannot be obtained in this context", + from.c_str (), prop.get_name ().c_str (), + prop.get_get_access ().c_str ()); +} + +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; +} + +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 bool +check_access (const std::string& req, const std::string& acc) +{ + if (req == "private") + return true; + else if (req == "protected") + return (acc != "private"); + else + return (acc == "public"); +} + +static std::string +get_base_name (const std::string& nm) +{ + std::string::size_type pos = nm.find_last_of ('.'); + + if (pos != std::string::npos) + return nm.substr (pos + 1); + + return nm; +} + +static std::string +superclass_access (const std::string& acc) +{ + if (acc == "public") + return acc; + else + return "protected"; +} + +static cdef_class +lookup_class (const std::string& name, bool error_if_not_found = true) +{ + std::map<std::string, cdef_class>::iterator it = all_classes.find (name); + + if (it == all_classes.end ()) + { + // FIXME: should look into load-path + if (error_if_not_found) + error ("class not found: %s", name.c_str ()); + } + else + { + cdef_class& cls = it->second; + + if (! cls.is_builtin ()) + { + // FIXME: check whether a class reload is needed + } + + if (cls.ok ()) + return cls; + else + all_classes.erase (it); + } + + return cdef_class (); +} + +static Cell +lookup_classes (const Cell& cls_names) +{ + Cell cls (cls_names.numel (), 1); + + for (int i = 0; i < cls_names.numel (); i++) + { + cdef_class c = lookup_class (cls_names(i).string_value ()); + + if (! error_state) + cls(i) = to_ov (c); + else + return Cell (); + } + + return cls; +} + +static bool +is_superclass (const cdef_class& clsa, const cdef_class& clsb, + bool allow_equal = true) +{ + if (allow_equal && clsa == clsb) + return true; + else + { + Cell c = clsb.get ("SuperClasses").cell_value (); + + bool retval = false; + + for (int i = 0; ! retval && i < c.numel (); i++) + { + cdef_class cls = lookup_class (c(i).string_value ()); + + if (! error_state) + retval = is_superclass (clsa, cls, true); + } + + return retval; + } +} + +inline bool +is_strict_superclass (const cdef_class& clsa, const cdef_class& clsb) +{ return is_superclass (clsa, clsb, false); } + +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 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) = 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) = 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 ()) + { + // FIXME: can the context be something else? + if (meth.check_access ("public")) + { + if (meth.is_static ()) + retval = meth.execute (args.splice (0, 2), nargout); + else + error ("fevalStatic: method `%s' is not static", + meth_name.c_str ()); + } + else + gripe_method_access ("fevalStatic", meth); + } + 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 ()) + { + // FIXME: can the context be something else? + if (prop.check_get_access ("public")) + { + if (prop.is_constant ()) + retval(0) = prop.get_value (); + else + error ("getConstant: property `%s' is not constant", + prop_name.c_str ()); + } + else + gripe_property_access ("getConstant", prop); + } + 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!=) + +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::string& super = std::string()) +{ + cdef_class cls ("meta.class"); + + all_classes[name] = cls; + 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 ("Name", name); + cls.put ("Properties", Cell ()); + cls.put ("Sealed", true); + if (super.empty ()) + cls.put ("SuperClasses", Cell ()); + else + cls.put ("SuperClasses", Cell (octave_value (super))); + + return cls; +} + +static cdef_property +make_property (const cdef_object& 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") +{ + // FIXME: what about default value? + + cdef_property prop ("meta.property"); + + prop.put ("Name", name); + 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)); + + return prop; +} + +inline cdef_property +make_attribute (const cdef_object& cls, const std::string& name) +{ + return make_property (cls, name, Matrix (), "public", Matrix (), "private"); +} + +static cdef_method +make_method (const cdef_object& cls, const std::string& name, const octave_value& fcn, + const std::string& m_access = "public", bool is_static = false) +{ + cdef_method meth ("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 ("Name", name); + meth.put ("Sealed", true); + meth.put ("Static", is_static); + + meth.set_function (fcn); + + return meth; +} + +inline cdef_method +make_method (const cdef_object& cls, const std::string& name, octave_builtin::fcn ff, + const std::string& m_access = "public", bool is_static = false) +{ + octave_value fcn (new octave_builtin (ff, name)); + + octave_value fcn_handle (new octave_fcn_handle (fcn, name)); + + return make_method (cls, name, fcn_handle, m_access, is_static); +} + +static cdef_package +make_package (const std::string& nm, + const std::string& parent = std::string ()) +{ + cdef_package pack ("meta.package"); + + all_packages[nm] = pack; + pack.put ("Name", nm); + pack.put ("ContainingPackage", to_ov (all_packages[parent])); + + return pack; +} + +DEFINE_OCTAVE_ALLOCATOR (octave_classdef); + +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 ())); +} + +cdef_class +cdef_object_rep::get_class (void) const +{ + cdef_class cls = lookup_class (class_name ()); + + return cls; +} + +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 +handle_cdef_object::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, int& skip) +{ + skip = 0; + + cdef_class cls = get_class (); + + octave_value_list retval; + + if (! cls.ok ()) + return retval; + + switch (type[0]) + { + case '.': + { + std::string name = (idx.front ())(0).string_value (); + + // FIXME: get the right context; context should also + // be linked to the current executing class (if any) + // such that protected/private methods found in inherited + // classes are correctly resolved. + std::string context = "public"; + + cdef_method meth = cls.find_method (name); + + if (meth.ok ()) + { + if (meth.check_access (context)) + { + 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); + else + { + refcount++; + retval = meth.execute (cdef_object (this), args, _nargout); + } + } + else + gripe_method_access ("subsref", meth); + } + + if (skip == 0 && ! error_state) + { + cdef_property prop = cls.find_property (name); + + if (prop.ok ()) + { + if (prop.check_get_access (context)) + { + refcount++; + retval(0) = prop.get_value (cdef_object (this)); + + skip = 1; + } + else + gripe_property_access ("subsref", prop); + } + else + error ("subsref: unknown method or property: %s", name.c_str ()); + } + break; + } + default: + error ("object cannot be indexed with `%c'", type[0]); + break; + } + + return retval; +} + +cdef_method +cdef_class::cdef_class_rep::find_method (const std::string& nm) +{ + 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; + } + + // 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).string_value ()); + + if (! error_state) + { + cdef_method meth = cls.find_method (nm); + + if (meth.ok ()) + return meth; + } + } + + return cdef_method (); +} + +void +cdef_class::cdef_class_rep::install_method (const cdef_method& meth) +{ + method_map[meth.get_name ()] = meth; +} + +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; + + std::map<std::string,int> count; + + count["public"] = count["protected"] = count["private"] = 0; + + find_methods (meths, count); + + if (! error_state) + { + Cell c (count["public"] + count["protected"], 1); + + int idx = 0; + + for (std::map<std::string,cdef_method>::const_iterator it = meths.begin (); + it != meths.end (); ++it) + if (::check_access ("protected", it->second.get_access ())) + c (idx++, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_methods (std::map<std::string,cdef_method>& meths, + std::map<std::string,int>& count) +{ + load_all_methods (); + + method_const_iterator it; + + for (it = method_map.begin (); it != method_map.end (); ++it) + { + std::string nm = it->second.get_name (); + + if (meths.find (nm) == meths.end ()) + { + std::string acc = it->second.get_access (); + + meths[nm] = it->second; + count[acc]++; + } + } + + // 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).string_value ()); + + if (! error_state) + cls.get_rep ()->find_methods (meths, count); + 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).string_value ()); + + 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; +} + +Cell +cdef_class::cdef_class_rep::get_properties (void) +{ + std::map<std::string,cdef_property> props; + + std::map<std::string,int> count; + + count["public"] = count["protected"] = count["private"] = 0; + + find_properties (props, count); + + if (! error_state) + { + Cell c (count["public"] + count["protected"], 1); + + int idx = 0; + + for (std::map<std::string,cdef_property>::const_iterator it = props.begin (); + it != props.end (); ++it) + if (::check_access ("protected", it->second.get_get_access ())) + c (idx++, 0) = to_ov (it->second); + + return c; + } + + return Cell (); +} + +void +cdef_class::cdef_class_rep::find_properties (std::map<std::string,cdef_property>& props, + std::map<std::string,int>& count) +{ + property_const_iterator it; + + for (it = property_map.begin (); it != property_map.end (); ++it) + { + std::string nm = it->second.get_name (); + + if (props.find (nm) == props.end ()) + { + std::string acc = it->second.get_get_access (); + + props[nm] = it->second; + count[acc]++; + } + } + + // 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).string_value ()); + + if (! error_state) + cls.get_rep ()->find_properties (props, count); + else + break; + } +} + +void +cdef_class::cdef_class_rep::find_names (std::map<std::string,std::string>& names, + std::map<std::string,int>& count) +{ + load_all_methods (); + + for (method_const_iterator it = method_map.begin (); + it != method_map.end(); ++it) + { + std::string nm = it->second.get_name (); + + if (names.find (nm) == names.end ()) + { + std::string acc = it->second.get_access (); + + names[nm] = acc; + count[acc]++; + } + } + + for (property_const_iterator it = property_map.begin (); + it != property_map.end (); ++it) + { + std::string nm = it->second.get_name (); + + if (names.find (nm) == names.end ()) + { + std::string acc = it->second.get_get_access (); + + names[nm] = acc; + count[acc]++; + } + } + + // 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).string_value ()); + + if (! error_state) + cls.get_rep ()->find_names (names, count); + else + break; + } +} + +string_vector +cdef_class::cdef_class_rep::get_names (void) +{ + std::map<std::string,std::string> names; + + std::map<std::string,int> count; + + count["public"] = count["protected"] = count["private"] = 0; + + find_names (names, count); + + if (! error_state) + { + string_vector v (count["public"]); + + int idx = 0; + for (std::map<std::string,std::string>::const_iterator it = names.begin (); + it != names.end (); ++it) + { + if (it->second == "public") + v[idx++] = it->first; + } + + 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 ()) + { + std::string cls_name = obj.class_name (); + + obj.set_class_name (get ("Name").string_value ()); + + it->second.execute (obj, octave_value_list (), 0); + + obj.set_class_name (cls_name); + } + + // 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).string_value ()); + + if (!error_state) + cls.delete_object (obj); + } +} + +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; + + octave_value get_fcn = get ("GetMethod"); + + std::string get_access = get ("GetAccess").string_value (); + + if (get_access != "public") + { + // FIXME: should check the current call stack + } + + if (get_fcn.is_empty ()) + retval = obj.get (get ("Name").string_value ()); + else + { + octave_value_list args; + + args(0) = to_ov (obj); + + args = execute_ov (get_fcn, args, 1); + + if (! error_state) + retval = args(0); + } + + return retval; +} + +bool +cdef_property::check_get_access (const std::string& req) const +{ + return ::check_access (req, get_get_access ()); +} + +bool +cdef_property::check_set_access (const std::string& req) const +{ + return ::check_access (req, get_set_access ()); +} + +void +cdef_method::cdef_method_rep::check_method (void) +{ + // FIXME: check whether re-load is needed +} + +octave_value_list +cdef_method::cdef_method_rep::execute (const octave_value_list& args, + int nargout) +{ + octave_value_list retval; + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + if (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) +{ + octave_value_list retval; + + if (! get ("Abstract").bool_value ()) + { + check_method (); + + octave_value_list new_args; + + if (function.is_defined ()) + { + 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::check_access (const std::string& req) const +{ + return ::check_access (req, get_access ()); +} + +static cdef_package +lookup_package (const std::string& name) +{ + std::map<std::string, cdef_package>::const_iterator it = all_packages.find (name); + + if (it != all_packages.end ()) + { + cdef_package pack = it->second; + + if (pack.ok ()) + return pack; + else + error ("invalid package: %s", name.c_str ()); + } + else + error ("package not found: %s", name.c_str ()); + + return cdef_package (); +} + +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; +} + +void +cdef_package::cdef_package_rep::install_class (const cdef_class& cls, + const std::string& nm) +{ + class_map[nm] = cls; +} + +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; +} + +octave_value_list +cdef_package::cdef_package_rep::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, int& skip) +{ + return handle_cdef_object::subsref (type, idx, nargout, skip); +} + +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_list +octave_classdef::subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout) +{ + int skip = 0; + octave_value_list retval; + + // FIXME: should check "subsref" method first + + retval = object.subsref (type, idx, nargout, skip); + + if (! error_state) + { + if (type.length () > skip && idx.size () > skip) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + + return retval; +} + +void +install_classdef (void) +{ + octave_classdef::register_type (); + + /* meta classes */ + cdef_class handle = make_class ("handle"); + cdef_class meta_class = make_class ("meta.class", "handle"); + cdef_class meta_property = make_class ("meta.property", "handle"); + cdef_class meta_method = make_class ("meta.method", "handle"); + cdef_class meta_event = make_class ("meta.event", "handle"); + cdef_class meta_package = make_class ("meta.package", "handle"); + cdef_class meta_dynproperty = make_class ("meta.dynamicproperty", "handle"); + + /* meta.class properties */ + 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, "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 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)); + + /* create "meta" package */ + cdef_package 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"); +} + +DEFUN (__meta_get_class__, args, , "") +{ + octave_value retval; + + if (args.length () == 1) + { + std::string cname = args(0).string_value (); + + if (! error_state) + retval = to_ov (lookup_class (cname)); + else + error ("invalid class name, expected a string value"); + } + else + print_usage (); + + 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; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/
new file mode 100644 --- /dev/null +++ b/src/ov-classdef.h @@ -0,0 +1,741 @@ +/* + +Copyright (C) 2012 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/>. + +*/ + +#if !defined (octave_classdef_h) +#define octave_classdef_h 1 + +#include <string> + +#include "oct-map.h" +#include "oct-refcount.h" +#include "ov-base.h" + +class cdef_object; +class cdef_class; +class cdef_property; +class cdef_method; +class cdef_package; + +class +cdef_object_rep +{ +public: + friend class cdef_object; + +public: + cdef_object_rep (void) + : refcount (1), cname () { } + + cdef_object_rep (const std::string& nm) + : refcount (1), cname (nm) { } + + virtual ~cdef_object_rep (void) { } + + virtual cdef_class get_class (void) const; + + virtual void set_class (const cdef_object&) + { error ("set_class: invalid object"); } + + virtual cdef_object_rep* clone (void) const + { + error ("clone: invalid object"); + return new cdef_object_rep (); + } + + virtual void put (const std::string&, const octave_value&) + { error ("put: invalid object"); } + + virtual octave_value get (const std::string&) const + { + error ("get: invalid object"); + return octave_value (); + } + + virtual octave_value_list subsref (const std::string&, + const std::list<octave_value_list>&, + int, int&) + { + error ("subsref: invalid object"); + return octave_value_list (); + } + + virtual string_vector map_keys(void) const; + + virtual bool is_valid (void) const { return false; } + + std::string class_name (void) const { return cname; } + + void set_class_name (const std::string& nm) + { cname = nm; } + +protected: + /* reference count */ + octave_refcount<int> refcount; + + /* class name */ + std::string cname; +}; + +class +cdef_object +{ +public: + /* FIXME: use a null object */ + cdef_object (void) + : rep (new cdef_object_rep ()) { } + + cdef_object (const cdef_object& obj) + : rep (obj.rep) + { + rep->refcount++; + } + + cdef_object (cdef_object_rep *r) + : rep (r) { } + + virtual ~cdef_object (void) + { + if (--rep->refcount == 0) + delete rep; + } + + cdef_object& operator = (const cdef_object& obj) + { + if (rep != obj.rep) + { + if (--rep->refcount == 0) + delete rep; + + rep = obj.rep; + rep->refcount++; + } + + return *this; + } + + cdef_class get_class (void) const; + + void set_class_name (const std::string& nm) + { rep->set_class_name (nm); } + + std::string class_name (void) const + { return rep->class_name (); } + + cdef_object clone (void) const + { return cdef_object (rep->clone ()); } + + void put (const std::string& pname, const octave_value& val) + { rep->put (pname, val); } + + octave_value get (const std::string& pname) const + { return rep->get (pname); } + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, int& skip) + { return rep->subsref (type, idx, nargout, skip); } + + string_vector map_keys (void) const { return rep->map_keys (); } + + const cdef_object_rep* get_rep (void) const { return rep; } + + bool ok (void) const { return rep->is_valid (); } + +protected: + cdef_object_rep* get_rep (void) { return rep; } + +private: + cdef_object_rep *rep; +}; + +class +handle_cdef_object : public cdef_object_rep +{ +public: + handle_cdef_object (void) + : cdef_object_rep () { } + + handle_cdef_object (const std::string& nm) + : cdef_object_rep (nm) { } + + cdef_object_rep* clone (void) const + { + handle_cdef_object *obj = const_cast<handle_cdef_object *> (this); + obj->refcount++; + return obj; + } + + void put (const std::string& pname, const octave_value& val) + { map.assign (pname, val); } + + octave_value get (const std::string& pname) const + { + Cell val = map.contents (pname); + + if (val.numel () > 0) + return val(0, 0); + else + { + error ("get: unknown slot: %s", pname.c_str ()); + return octave_value (); + } + } + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, int& skip); + + bool is_valid (void) const { return true; } + +protected: + Octave_map map; +}; + +class +cdef_class : public cdef_object +{ +private: + + class + cdef_class_rep : public handle_cdef_object + { + public: + cdef_class_rep (const std::string& nm) + : handle_cdef_object (nm) { } + + cdef_method find_method (const std::string& nm); + + void install_method (const cdef_method& meth); + + Cell get_methods (void); + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop); + + Cell get_properties (void); + + string_vector get_names (void); + + void set_directory (const std::string& dir) { directory = dir; } + + std::string get_directory (void) const { return directory; } + + void delete_object (cdef_object obj); + + private: + void load_all_methods (void); + + void find_names (std::map<std::string,std::string>& names, + std::map<std::string,int>& count); + + void find_properties (std::map<std::string,cdef_property>& props, + std::map<std::string,int>& count); + + void find_methods (std::map<std::string,cdef_method>& meths, + std::map<std::string,int>& count); + + private: + std::string directory; + + std::map<std::string,cdef_method> method_map; + + std::map<std::string,cdef_property> property_map; + + typedef std::map<std::string,cdef_method>::iterator method_iterator; + typedef std::map<std::string,cdef_method>::const_iterator method_const_iterator; + typedef std::map<std::string,cdef_property>::iterator property_iterator; + typedef std::map<std::string,cdef_property>::const_iterator property_const_iterator; + }; + +public: + // Create and invalid class object + cdef_class (void) + : cdef_object () { } + + cdef_class (const std::string& nm) + : cdef_object (new cdef_class_rep (nm)) { } + + cdef_class (const cdef_class& cls) + : cdef_object (cls) { } + + cdef_class (const cdef_object& obj) + : cdef_object (obj) + { + // This should never happen... + if (class_name () != "meta.class") + error ("internal error: invalid assignment from %s to meta.class object", + class_name ().c_str ()); + } + + cdef_class& operator = (const cdef_class& cls) + { + cdef_object::operator= (cls); + + return *this; + } + + cdef_class& operator = (const cdef_object& obj) + { + if (obj.class_name () == "meta.class") + cdef_object::operator= (obj); + else + error ("internal error: invalid assignment from %s to meta.class object", + class_name ().c_str ()); + + return *this; + } + + cdef_method find_method (const std::string& nm); + + void install_method (const cdef_method& meth) + { get_rep ()->install_method (meth); } + + Cell get_methods (void) { return get_rep ()->get_methods (); } + + cdef_property find_property (const std::string& nm); + + void install_property (const cdef_property& prop) + { get_rep ()->install_property (prop); } + + Cell get_properties (void) { return get_rep ()->get_properties (); } + + string_vector get_names (void) { return get_rep ()->get_names (); } + + void set_directory (const std::string& dir) + { get_rep ()->set_directory (dir); } + + std::string get_directory (void) const + { return get_rep ()->get_directory (); } + + std::string get_name (void) const + { return get ("Name").string_value (); } + + bool is_builtin (void) const + { return get_directory ().empty (); } + + void delete_object (cdef_object obj) + { get_rep ()->delete_object (obj); } + +private: + cdef_class_rep* get_rep (void) + { return dynamic_cast<cdef_class_rep *> (cdef_object::get_rep ()); } + + const cdef_class_rep* get_rep (void) const + { return dynamic_cast<const cdef_class_rep *> (cdef_object::get_rep ()); } + + friend bool operator == (const cdef_class&, const cdef_class&); + friend bool operator != (const cdef_class&, const cdef_class&); +}; + +inline bool +operator == (const cdef_class& clsa, const cdef_class& clsb) +// FIXME: is this really the right way to check class equality? +{ return (clsa.get_rep () == clsb.get_rep ()); } + +inline bool +operator != (const cdef_class& clsa, const cdef_class& clsb) +{ return ! (clsa == clsb); } + +class +cdef_property : public cdef_object +{ +private: + + class + cdef_property_rep : public handle_cdef_object + { + public: + cdef_property_rep (const std::string& nm) + : handle_cdef_object (nm) { } + + octave_value get_value (void) const { return default_value; } + + octave_value get_value (const cdef_object& obj); + + void set_value (const octave_value& val) { default_value = val; } + + void set_value (const cdef_object& obj, const octave_value& val); + + private: + octave_value default_value; + }; + +public: + cdef_property (void) : cdef_object () { } + + cdef_property (const std::string& nm) + : cdef_object (new cdef_property_rep (nm)) { } + + cdef_property (const cdef_property& prop) + : cdef_object (prop) { } + + cdef_property (const cdef_object& obj) + : cdef_object (obj) + { + // This should never happen... + if (class_name () != "meta.property") + error ("internal error: invalid assignment from %s to meta.property object", + class_name ().c_str ()); + } + + cdef_property& operator = (const cdef_property& prop) + { + cdef_object::operator= (prop); + + return *this; + } + + octave_value get_value (const cdef_object& obj) + { return get_rep ()->get_value (obj); } + + octave_value get_value (void) { return get_rep ()->get_value (); } + + void set_value (const cdef_object& obj, const octave_value& val) + { get_rep ()->set_value (obj, val); } + + void set_value (const octave_value& val) { get_rep ()->set_value (val); } + + std::string get_get_access (void) const + { return get ("GetAccess").string_value (); } + + std::string get_set_access (void) const + { return get ("SetAccess").string_value (); } + + bool check_get_access (const std::string& acc) const; + + bool check_set_access (const std::string& acc) const; + + std::string get_name (void) const + { return get ("Name").string_value (); } + + bool is_constant (void) const + { return get ("Constant").bool_value (); } + +private: + cdef_property_rep* get_rep (void) + { return dynamic_cast<cdef_property_rep *> (cdef_object::get_rep ()); } + + const cdef_property_rep* get_rep (void) const + { return dynamic_cast<const cdef_property_rep *> (cdef_object::get_rep ()); } +}; + +class +cdef_method : public cdef_object +{ +private: + + class + cdef_method_rep : public handle_cdef_object + { + public: + cdef_method_rep (const std::string& nm) + : handle_cdef_object (nm) { } + + octave_value get_function (void) const { return function; } + + 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); + + private: + void check_method (void); + + private: + octave_value function; + }; + +public: + cdef_method (void) : cdef_object () { } + + cdef_method (const std::string& nm) + : cdef_object (new cdef_method_rep (nm)) { } + + cdef_method (const cdef_property& prop) + : cdef_object (prop) { } + + cdef_method (const cdef_object& obj) + : cdef_object (obj) + { + // This should never happen... + if (class_name () != "meta.method") + error ("internal error: invalid assignment from %s to meta.method object", + class_name ().c_str ()); + } + + cdef_method& operator = (const cdef_method& meth) + { + cdef_object::operator= (meth); + + return *this; + } + + /* normal invokation */ + octave_value_list execute (const octave_value_list& args, int nargout) + { return get_rep ()->execute (args, nargout); } + + /* dot-invokation: object is pushed as 1st argument */ + octave_value_list execute (const cdef_object& obj, + const octave_value_list& args, int nargout) + { return get_rep ()->execute (obj, args, nargout); } + + std::string get_access (void) const + { return get ("Access").string_value (); } + + bool check_access (const std::string& req) const; + + std::string get_name (void) const + { return get ("Name").string_value (); } + + bool is_static (void) const + { return get ("Static").bool_value (); } + + void set_function (const octave_value& fcn) + { get_rep ()->set_function (fcn); } + +private: + cdef_method_rep* get_rep (void) + { return dynamic_cast<cdef_method_rep *> (cdef_object::get_rep ()); } + + const cdef_method_rep* get_rep (void) const + { return dynamic_cast<const cdef_method_rep *> (cdef_object::get_rep ()); } +}; + +inline cdef_class +cdef_object::get_class (void) const +{ return rep->get_class (); } + +inline cdef_method +cdef_class::find_method (const std::string& nm) +{ return get_rep ()->find_method (nm); } + +inline cdef_property +cdef_class::find_property (const std::string& nm) +{ return get_rep ()->find_property (nm); } + +class +cdef_package : public cdef_object +{ +private: + + class + cdef_package_rep : public handle_cdef_object + { + public: + cdef_package_rep (const std::string& nm) + : handle_cdef_object (nm) { } + + void install_class (const cdef_class& cls, const std::string& nm); + + void install_function (const octave_value& fcn, const std::string& nm); + + void install_package (const cdef_package& pack, const std::string& nm); + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, + int nargout, int& skip); + + Cell get_classes (void) const; + + Cell get_functions (void) const; + + Cell get_packages (void) const; + + private: + std::map<std::string, cdef_class> class_map; + std::map<std::string, octave_value> function_map; + std::map<std::string, cdef_package> package_map; + + typedef std::map<std::string, cdef_class>::iterator class_iterator; + typedef std::map<std::string, cdef_class>::const_iterator class_const_iterator; + typedef std::map<std::string, octave_value>::iterator function_iterator; + typedef std::map<std::string, octave_value>::const_iterator function_const_iterator; + typedef std::map<std::string, cdef_package>::iterator package_iterator; + typedef std::map<std::string, cdef_package>::const_iterator package_const_iterator; + }; + +public: + cdef_package (void) : cdef_object () { } + + cdef_package (const std::string& nm) + : cdef_object (new cdef_package_rep (nm)) { } + + cdef_package (const cdef_object& obj) + : cdef_object (obj) + { + // This should never happen... + if (class_name () != "meta.package") + error ("internal error: invalid assignment from %s to meta.package object", + class_name ().c_str ()); + } + + cdef_package& operator = (const cdef_package& pack) + { + cdef_object::operator= (pack); + + return *this; + } + + void install_class (const cdef_class& cls, const std::string& nm) + { get_rep ()->install_class (cls, nm); } + + void install_function (const octave_value& fcn, const std::string& nm) + { get_rep ()->install_function (fcn, nm); } + + void install_package (const cdef_package& pack, const std::string& nm) + { get_rep ()->install_package (pack, nm); } + + Cell get_classes (void) const + { return get_rep ()->get_classes (); } + + Cell get_functions (void) const + { return get_rep ()->get_functions (); } + + Cell get_packages (void) const + { return get_rep ()->get_packages (); } + +private: + cdef_package_rep* get_rep (void) + { return dynamic_cast<cdef_package_rep *> (cdef_object::get_rep ()); } + + const cdef_package_rep* get_rep (void) const + { return dynamic_cast<const cdef_package_rep *> (cdef_object::get_rep ()); } +}; + +class +octave_classdef : public octave_base_value +{ +public: + octave_classdef (void) + : octave_base_value (), object () { } + + octave_classdef (const cdef_object& obj) + : octave_base_value (), object (obj) { } + + octave_classdef (const octave_classdef& obj) + : octave_base_value (obj), object (obj.object) { } + + octave_base_value* clone (void) const + { return new octave_classdef (object.clone ()); } + + octave_base_value* empty_clone (void) const + { return new octave_classdef (); } + + cdef_object get_object (void) const + { return object; } + + bool is_defined (void) const { return true; } + + bool is_map (void) const { return true; } + + bool print_as_scalar (void) const { return true; } + + void print(std::ostream& os, bool pr_as_read_syntax = false) const + { + // FIXME: should call "display" method + print_raw(os, pr_as_read_syntax); + newline(os); + } + + void print_raw(std::ostream& os, bool /* pr_as_read_syntax */ = false) const + { + os << object.class_name () << " object"; + } + + octave_value_list subsref (const std::string& type, + const std::list<octave_value_list>& idx, int nargout); + + octave_value subsref (const std::string& type, + const std::list<octave_value_list>& idx) + { + octave_value_list retval = subsref (type, idx, 1); + return (retval.length () > 0 ? retval(0) : octave_value ()); + } + + string_vector map_keys (void) const { return object.map_keys (); } + + dim_vector dims (void) const { return dim_vector (1, 1); } + +private: + cdef_object object; + +private: + DECLARE_OCTAVE_ALLOCATOR + +public: + int type_id (void) const { return t_id; } + std::string type_name (void) const { return t_name; } + std::string class_name (void) const { return object.class_name (); } + + static int static_type_id (void) { return t_id; } + static std::string static_type_name (void) { return t_name; } + static std::string static_class_name (void) { return "<unknown>"; } + static void register_type (void); + +private: + static int t_id; + + static const std::string t_name; +}; + +inline octave_value +to_ov (const cdef_object& obj) +{ + if (obj.ok ()) + return octave_value (new octave_classdef (obj)); + else + return octave_value (Matrix ()); +} + +inline octave_value +to_ov (const octave_value& ov) +{ return ov; } + +inline cdef_object +to_cdef (const octave_value& val) +{ + if (val.type_name () == "object") + return dynamic_cast<octave_classdef *> (val.internal_rep ())->get_object (); + else + { + warning ("trying to cast non-object into object"); + return cdef_object (); + } +} + +inline cdef_object +to_cdef (const cdef_object& obj) +{ return obj; } + +OCTINTERP_API void install_classdef (void); + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/