# HG changeset patch # User John W. Eaton # Date 1344172857 14400 # Node ID 28ffdc42b5504de1f87388b58d14594076e06a62 # Parent 7c7b9ea23a86f3c0447ebaa2a148d1b22511ed0d# Parent 03381a36f70d2a786b619460e4614d1a722e2ee3 maint: periodic merge of default to classdef diff -r 03381a36f70d -r 28ffdc42b550 liboctave/base-list.h --- a/liboctave/base-list.h Sun Aug 05 09:04:30 2012 -0400 +++ b/liboctave/base-list.h Sun Aug 05 09:20:57 2012 -0400 @@ -87,8 +87,6 @@ // For backward compatibility. void append (const elt_type& s) { lst.push_back (s); } -protected: - octave_base_list (void) : lst () { } octave_base_list (const std::list& l) : lst (l) { } diff -r 03381a36f70d -r 28ffdc42b550 src/Makefile.am diff -r 03381a36f70d -r 28ffdc42b550 src/octave-value/module.mk --- a/src/octave-value/module.mk Sun Aug 05 09:04:30 2012 -0400 +++ b/src/octave-value/module.mk Sun Aug 05 09:20:57 2012 -0400 @@ -36,6 +36,7 @@ octave-value/ov-cell.h \ octave-value/ov-ch-mat.h \ octave-value/ov-class.h \ + octave-value/ov-classdef.h \ octave-value/ov-colon.h \ octave-value/ov-complex.h \ octave-value/ov-cs-list.h \ @@ -92,6 +93,7 @@ octave-value/ov-cell.cc \ octave-value/ov-ch-mat.cc \ octave-value/ov-class.cc \ + octave-value/ov-classdef.cc \ octave-value/ov-colon.cc \ octave-value/ov-complex.cc \ octave-value/ov-cs-list.cc \ diff -r 03381a36f70d -r 28ffdc42b550 src/octave-value/ov-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/octave-value/ov-classdef.cc Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,1454 @@ +/* + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "defun.h" +#include "ov-builtin.h" +#include "ov-classdef.h" +#include "ov-fcn-handle.h" +#include "ov-typeinfo.h" +#include "pt-classdef.h" + +static std::map all_classes; +static std::map 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 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::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, "", 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& 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::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 meths; + + std::map 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::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& meths, + std::map& 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 props; + + std::map 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::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& props, + std::map& 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& names, + std::map& 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 names; + + std::map 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::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); + } +} + +cdef_class +cdef_class::make_meta_class (const tree_classdef* t) +{ + cdef_class retval; + + return retval; +} + +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::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& idx, + int nargout, int& skip) +{ + return handle_cdef_object::subsref (type, idx, nargout, skip); +} + +template +Cell +map2Cell (const std::map& m) +{ + Cell retval (1, m.size ()); + int i = 0; + + for (typename std::map::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& 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_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") +{ + octave_value retval; + + std::cerr << "__superclass_reference__ (" + << args(0).string_value () << ", " + << args(1).string_value () << ", " + << args(2).string_value () << ")" + << std::endl; + + return retval; +} + +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; + + std::cerr << "__meta_class_query__ (" + << args(0).string_value () << ", " + << args(1).string_value () << ")" + << std::endl; + + if (args.length () == 2) + { + std::string pkg = args(0).string_value (); + std::string cls = args(1).string_value (); + + if (! pkg.empty ()) + cls = pkg + "." + cls; + + if (! error_state) + retval = to_ov (lookup_class (cls)); + else + error ("invalid class name, expected a string value"); + } + else + print_usage (); + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r 03381a36f70d -r 28ffdc42b550 src/octave-value/ov-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/octave-value/ov-classdef.h Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,745 @@ +/* + +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 +. + +*/ + +#if !defined (octave_classdef_h) +#define octave_classdef_h 1 + +#include + +#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 tree_classdef; + +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&, + 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 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& 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 (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& 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& names, + std::map& count); + + void find_properties (std::map& props, + std::map& count); + + void find_methods (std::map& meths, + std::map& count); + + private: + std::string directory; + + std::map method_map; + + std::map property_map; + + typedef std::map::iterator method_iterator; + typedef std::map::const_iterator method_const_iterator; + typedef std::map::iterator property_iterator; + typedef std::map::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); } + + static cdef_class make_meta_class (const tree_classdef* t); + +private: + cdef_class_rep* get_rep (void) + { return dynamic_cast (cdef_object::get_rep ()); } + + const cdef_class_rep* get_rep (void) const + { return dynamic_cast (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_object::get_rep ()); } + + const cdef_property_rep* get_rep (void) const + { return dynamic_cast (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_object::get_rep ()); } + + const cdef_method_rep* get_rep (void) const + { return dynamic_cast (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& idx, + int nargout, int& skip); + + Cell get_classes (void) const; + + Cell get_functions (void) const; + + Cell get_packages (void) const; + + private: + std::map class_map; + std::map function_map; + std::map package_map; + + typedef std::map::iterator class_iterator; + typedef std::map::const_iterator class_const_iterator; + typedef std::map::iterator function_iterator; + typedef std::map::const_iterator function_const_iterator; + typedef std::map::iterator package_iterator; + typedef std::map::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_object::get_rep ()); } + + const cdef_package_rep* get_rep (void) const + { return dynamic_cast (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& idx, int nargout); + + octave_value subsref (const std::string& type, + const std::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 ""; } + 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 (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: *** +*/ diff -r 03381a36f70d -r 28ffdc42b550 src/octave-value/ov.cc --- a/src/octave-value/ov.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/octave-value/ov.cc Sun Aug 05 09:20:57 2012 -0400 @@ -65,6 +65,7 @@ #include "ov-range.h" #include "ov-struct.h" #include "ov-class.h" +#include "ov-classdef.h" #include "ov-oncleanup.h" #include "ov-cs-list.h" #include "ov-colon.h" diff -r 03381a36f70d -r 28ffdc42b550 src/octave.cc --- a/src/octave.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/octave.cc Sun Aug 05 09:20:57 2012 -0400 @@ -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; diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/lex.h --- a/src/parse-tree/lex.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/lex.h Sun Aug 05 09:20:57 2012 -0400 @@ -52,6 +52,7 @@ extern void prep_lexer_for_script_file (void); extern void prep_lexer_for_function_file (void); +extern void prep_lexer_for_classdef_file (void); // For communication between the lexer and parser. @@ -72,7 +73,8 @@ looking_for_object_index (false), do_comma_insert (false), looking_at_indirect_ref (false), parsed_function_name (), parsing_class_method (false), maybe_classdef_get_set_method (false), - parsing_classdef (false), quote_is_transpose (false), + parsing_classdef (false), parsing_classdef_get_method (false), + parsing_classdef_set_method (false), quote_is_transpose (false), pending_local_variables () { @@ -157,6 +159,12 @@ // TRUE means we are parsing a classdef file bool parsing_classdef; + // TRUE means we are parsing a classdef get.method. + bool parsing_classdef_get_method; + + // TRUE means we are parsing a classdef set.method. + bool parsing_classdef_set_method; + // Return transpose or start a string? bool quote_is_transpose; diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/lex.ll --- a/src/parse-tree/lex.ll Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/lex.ll Sun Aug 05 09:20:57 2012 -0400 @@ -34,6 +34,7 @@ %x SCRIPT_FILE_BEGIN %x FUNCTION_FILE_BEGIN +%x CLASSDEF_FILE_BEGIN %{ @@ -373,6 +374,14 @@ COUNT_TOK_AND_RETURN (FUNCTION_FILE); } +. { + LEXER_DEBUG ("."); + + BEGIN (INITIAL); + xunput (yytext[0], yytext); + COUNT_TOK_AND_RETURN (CLASSDEF_FILE); + } + %{ // Help and other command-style functions. %} @@ -756,7 +765,7 @@ { lexer_flags.looking_for_object_index = true; - COUNT_TOK_AND_RETURN (SUPERCLASSREF); + COUNT_TOK_AND_RETURN (id_tok); } } @@ -774,7 +783,7 @@ { lexer_flags.looking_for_object_index = true; - COUNT_TOK_AND_RETURN (METAQUERY); + COUNT_TOK_AND_RETURN (id_tok); } } @@ -3152,37 +3161,40 @@ static int handle_superclass_identifier (void) { - eat_continuation (); + int c = yytext[yyleng-1]; + + std::string meth = strip_trailing_whitespace (yytext); + + int cont_is_spc = eat_continuation (); + + int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); + + size_t pos = meth.find ("@"); + std::string cls = meth.substr (pos + 1); + meth = meth.substr (0, pos); std::string pkg; - std::string meth = strip_trailing_whitespace (yytext); - size_t pos = meth.find ("@"); - std::string cls = meth.substr (pos).substr (1); - meth = meth.substr (0, pos - 1); - pos = cls.find ("."); if (pos != std::string::npos) { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); + pkg = cls.substr (0, pos); + cls = cls.substr (pos + 1); } int kw_token = (is_keyword_token (meth) || is_keyword_token (cls) || is_keyword_token (pkg)); if (kw_token) { - error ("method, class and package names may not be keywords"); + error ("method, class, and package names may not be keywords"); return LEXICAL_ERROR; } - yylval.tok_val - = new token (meth.empty () ? 0 : &(symbol_table::insert (meth)), - cls.empty () ? 0 : &(symbol_table::insert (cls)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg)), - input_line_number, current_input_column); + yylval.tok_val = new token (meth, pkg, cls, input_line_number, + current_input_column); token_stack.push (yylval.tok_val); - lexer_flags.convert_spaces_to_comma = true; + do_comma_insert_check (); + maybe_unput_comma (spc_gobbled); current_input_column += yyleng; return SUPERCLASSREF; @@ -3191,33 +3203,35 @@ static int handle_meta_identifier (void) { - eat_continuation (); + int c = yytext[yyleng-1]; + + std::string cls = strip_trailing_whitespace (yytext).substr (1); + + int cont_is_spc = eat_continuation (); + + int spc_gobbled = (cont_is_spc || c == ' ' || c == '\t'); std::string pkg; - std::string cls = strip_trailing_whitespace (yytext).substr (1); size_t pos = cls.find ("."); - if (pos != std::string::npos) { - pkg = cls.substr (pos).substr (1); - cls = cls.substr (0, pos - 1); + pkg = cls.substr (0, pos); + cls = cls.substr (pos + 1); } int kw_token = is_keyword_token (cls) || is_keyword_token (pkg); if (kw_token) { - error ("class and package names may not be keywords"); + error ("class and package names may not be keywords"); return LEXICAL_ERROR; } - yylval.tok_val - = new token (cls.empty () ? 0 : &(symbol_table::insert (cls)), - pkg.empty () ? 0 : &(symbol_table::insert (pkg)), - input_line_number, current_input_column); - + yylval.tok_val = new token (pkg, cls, input_line_number, + current_input_column); token_stack.push (yylval.tok_val); - lexer_flags.convert_spaces_to_comma = true; + do_comma_insert_check (); + maybe_unput_comma (spc_gobbled); current_input_column += yyleng; return METAQUERY; @@ -3422,6 +3436,8 @@ // Not initially defining a class with classdef. maybe_classdef_get_set_method = false; parsing_classdef = false; + parsing_classdef_get_method = false; + parsing_classdef_set_method = false; // Not initiallly looking at a function handle. looking_at_function_handle = 0; @@ -3550,6 +3566,12 @@ BEGIN (FUNCTION_FILE_BEGIN); } +void +prep_lexer_for_classdef_file (void) +{ + BEGIN (CLASSDEF_FILE_BEGIN); +} + static void maybe_warn_separator_insert (char sep) { @@ -3722,6 +3744,7 @@ case CLOSE_BRACE: std::cerr << "CLOSE_BRACE\n"; break; case SCRIPT_FILE: std::cerr << "SCRIPT_FILE\n"; break; case FUNCTION_FILE: std::cerr << "FUNCTION_FILE\n"; break; + case CLASSDEF_FILE: std::cerr << "CLASSDEF_FILE\n"; break; case SUPERCLASSREF: std::cerr << "SUPERCLASSREF\n"; break; case METAQUERY: std::cerr << "METAQUERY\n"; break; case GET: std::cerr << "GET\n"; break; @@ -3771,6 +3794,10 @@ std::cerr << "FUNCTION_FILE_BEGIN" << std::endl; break; + case CLASSDEF_FILE_BEGIN: + std::cerr << "CLASSDEF_FILE_BEGIN" << std::endl; + break; + default: std::cerr << "UNKNOWN START STATE!" << std::endl; break; diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/module.mk --- a/src/parse-tree/module.mk Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/module.mk Sun Aug 05 09:20:57 2012 -0400 @@ -23,6 +23,7 @@ parse-tree/pt-cbinop.h \ parse-tree/pt-cell.h \ parse-tree/pt-check.h \ + parse-tree/pt-classdef.h \ parse-tree/pt-cmd.h \ parse-tree/pt-colon.h \ parse-tree/pt-const.h \ @@ -31,6 +32,7 @@ parse-tree/pt-except.h \ parse-tree/pt-exp.h \ parse-tree/pt-fcn-handle.h \ + parse-tree/pt-funcall.h \ parse-tree/pt-id.h \ parse-tree/pt-idx.h \ parse-tree/pt-jump.h \ @@ -54,6 +56,7 @@ parse-tree/pt-cbinop.cc \ parse-tree/pt-cell.cc \ parse-tree/pt-check.cc \ + parse-tree/pt-classdef.cc \ parse-tree/pt-cmd.cc \ parse-tree/pt-colon.cc \ parse-tree/pt-const.cc \ @@ -62,6 +65,7 @@ parse-tree/pt-except.cc \ parse-tree/pt-exp.cc \ parse-tree/pt-fcn-handle.cc \ + parse-tree/pt-funcall.cc \ parse-tree/pt-id.cc \ parse-tree/pt-idx.cc \ parse-tree/pt-jump.cc \ diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/oct-parse.yy --- a/src/parse-tree/oct-parse.yy Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/oct-parse.yy Sun Aug 05 09:20:57 2012 -0400 @@ -62,6 +62,7 @@ #include "load-path.h" #include "oct-hist.h" #include "oct-map.h" +#include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "ov-null-mat.h" @@ -71,6 +72,7 @@ #include "parse-private.h" #include "pt-all.h" #include "pt-eval.h" +#include "pt-funcall.h" #include "symtab.h" #include "token.h" #include "unwind-prot.h" @@ -152,6 +154,9 @@ // used while reading function files. static symbol_table::scope_id primary_fcn_scope; +// Pointer to the classdef object we just parsed, if any. +static tree_classdef *classdef_object = 0; + // List of autoloads (function -> file mapping). static std::map autoload_map; @@ -356,6 +361,47 @@ append_statement_list (tree_statement_list *list, char sep, tree_statement *stmt, bool warn_missing_semi); +static tree_funcall * +make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c); + +static tree_funcall * +make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c); + +static tree_classdef * +make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc); + +static tree_classdef_properties_block * +make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc); + +static tree_classdef_methods_block * +make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc); + +static tree_classdef_events_block * +make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc); + +static tree_classdef_enum_block * +make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, octave_comment_list *lc); + // Finish building a statement. template static tree_statement * @@ -400,12 +446,15 @@ // Types for the nonterminals we generate. char sep_type; + token *tok_type; tree *tree_type; tree_matrix *tree_matrix_type; tree_cell *tree_cell_type; tree_expression *tree_expression_type; tree_constant *tree_constant_type; tree_fcn_handle *tree_fcn_handle_type; + tree_funcall *tree_funcall_type; + tree_function_def *tree_function_def_type; tree_anon_fcn_handle *tree_anon_fcn_handle_type; tree_identifier *tree_identifier_type; tree_index_expression *tree_index_expression_type; @@ -425,7 +474,24 @@ tree_statement *tree_statement_type; tree_statement_list *tree_statement_list_type; octave_user_function *octave_user_function_type; - void *dummy_type; + + tree_classdef *tree_classdef_type; + tree_classdef_attribute* tree_classdef_attribute_type; + tree_classdef_attribute_list* tree_classdef_attribute_list_type; + tree_classdef_superclass* tree_classdef_superclass_type; + tree_classdef_superclass_list* tree_classdef_superclass_list_type; + tree_classdef_body* tree_classdef_body_type; + tree_classdef_property* tree_classdef_property_type; + tree_classdef_property_list* tree_classdef_property_list_type; + tree_classdef_properties_block* tree_classdef_properties_block_type; + tree_classdef_methods_list* tree_classdef_methods_list_type; + tree_classdef_methods_block* tree_classdef_methods_block_type; + tree_classdef_event* tree_classdef_event_type; + tree_classdef_events_list* tree_classdef_events_list_type; + tree_classdef_events_block* tree_classdef_events_block_type; + tree_classdef_enum* tree_classdef_enum_type; + tree_classdef_enum_list* tree_classdef_enum_list_type; + tree_classdef_enum_block* tree_classdef_enum_block_type; } // Tokens with line and column information. @@ -452,6 +518,7 @@ %token TRY CATCH %token GLOBAL PERSISTENT %token FCN_HANDLE +%token CLASSDEF %token PROPERTIES METHODS EVENTS ENUMERATION %token METAQUERY %token SUPERCLASSREF @@ -459,13 +526,13 @@ // Other tokens. %token END_OF_INPUT LEXICAL_ERROR -%token FCN SCRIPT_FILE FUNCTION_FILE CLASSDEF +%token FCN SCRIPT_FILE CLASSDEF_FILE FUNCTION_FILE // %token VARARGIN VARARGOUT %token CLOSE_BRACE // Nonterminals we construct. -%type stash_comment function_beg classdef_beg -%type properties_beg methods_beg events_beg enum_beg +%type stash_comment function_beg +%type classdef_beg %type sep_no_nl opt_sep_no_nl sep opt_sep opt_comma %type input %type string constant magic_colon @@ -477,18 +544,19 @@ %type primary_expr oper_expr %type simple_expr colon_expr assign_expr expression %type identifier fcn_name magic_tilde -%type superclass_identifier meta_identifier -%type function1 function2 classdef1 +%type superclass_identifier meta_identifier +%type function1 function2 %type word_list_cmd %type colon_expr1 %type arg_list word_list assign_lhs %type cell_or_matrix_row %type param_list param_list1 param_list2 %type return_list return_list1 -%type superclasses opt_superclasses %type command select_command loop_command -%type jump_command except_command function -%type script_file classdef +%type jump_command except_command +%type function +%type classdef +%type script_file classdef_file %type function_file function_list %type if_command %type elseif_clause else_clause @@ -499,25 +567,26 @@ %type decl2 %type decl1 %type declaration -%type statement function_end classdef_end +%type statement function_end %type simple_list simple_list1 list list1 %type opt_list input1 -// These types need to be specified. -%type attr -%type class_event -%type class_enum -%type class_property -%type properties_list -%type properties_block -%type methods_list -%type methods_block -%type opt_attr_list -%type attr_list -%type events_list -%type events_block -%type enum_list -%type enum_block -%type class_body + +%type attr +%type attr_list opt_attr_list +%type superclass +%type superclass_list opt_superclass_list +%type class_body +%type class_property +%type property_list +%type properties_block +%type methods_list +%type methods_block +%type class_event +%type events_list +%type events_block +%type class_enum +%type enum_list +%type enum_block // Precedence and associativity. %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ @@ -552,6 +621,8 @@ } | function_file { YYACCEPT; } + | classdef_file + { YYACCEPT; } | simple_list parse_error { ABORT_PARSE; } | parse_error @@ -641,11 +712,24 @@ superclass_identifier : SUPERCLASSREF - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string method_nm = $1->superclass_method_name (); + std::string package_nm = $1->superclass_package_name (); + std::string class_nm = $1->superclass_class_name (); + + $$ = make_superclass_ref (method_nm, package_nm, class_nm, + $1->line (), $1->column ()); + } ; meta_identifier : METAQUERY - { $$ = new tree_identifier ($1->line (), $1->column ()); } + { + std::string package_nm = $1->meta_package_name (); + std::string class_nm = $1->meta_class_name (); + + $$ = make_meta_class_query (package_nm, class_nm, + $1->line (), $1->column ()); + } ; string : DQ_STRING @@ -984,8 +1068,6 @@ { $$ = $1; } | script_file { $$ = $1; } - | classdef - { $$ = $1; } ; // ===================== @@ -1404,12 +1486,14 @@ { lexer_flags.parsed_function_name.top () = true; lexer_flags.maybe_classdef_get_set_method = false; + lexer_flags.parsing_classdef_get_method = true; $$ = $3; } | SET '.' identifier { lexer_flags.parsed_function_name.top () = true; lexer_flags.maybe_classdef_get_set_method = false; + lexer_flags.parsing_classdef_set_method = true; $$ = $3; } ; @@ -1474,161 +1558,211 @@ } ; +// ============= +// Classdef file +// ============= + +classdef_file : CLASSDEF_FILE classdef opt_sep END_OF_INPUT + { + classdef_object = $2; + $$ = 0; + } + ; + // ======== // Classdef // ======== -classdef_beg : CLASSDEF stash_comment +classdef_beg : CLASSDEF { - $$ = 0; + if (! reading_classdef_file) + { + yyerror ("classdef must appear inside a file containing only a class definition"); + YYABORT; + } + lexer_flags.parsing_classdef = true; + $$ = $1; } ; -classdef_end : END +classdef : classdef_beg stash_comment opt_attr_list identifier opt_superclass_list opt_sep class_body opt_sep END { lexer_flags.parsing_classdef = false; - - if (end_token_ok ($1, token::classdef_end)) - $$ = make_end ("endclassdef", $1->line (), $1->column ()); - else - ABORT_PARSE; + $$ = make_classdef ($1, $3, $4, $5, $7, $9, $2); } ; -classdef1 : classdef_beg opt_attr_list identifier opt_superclasses - { $$ = 0; } - ; - -classdef : classdef1 opt_sep class_body opt_sep stash_comment classdef_end - { $$ = 0; } - ; - opt_attr_list : // empty { $$ = 0; } | '(' attr_list ')' - { $$ = 0; } + { $$ = $2; } ; attr_list : attr - { $$ = 0; } + { $$ = new tree_classdef_attribute_list ($1); } | attr_list ',' attr - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; attr : identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($1); } | identifier '=' decl_param_init expression - { $$ = 0; } + { + lexer_flags.looking_at_initializer_expression = false; + $$ = new tree_classdef_attribute ($1, $4); + } | EXPR_NOT identifier - { $$ = 0; } + { $$ = new tree_classdef_attribute ($2, false); } ; -opt_superclasses +opt_superclass_list : // empty { $$ = 0; } - | superclasses - { $$ = 0; } + | superclass_list + { $$ = $1; } ; -superclasses : EXPR_LT identifier '.' identifier - { $$ = 0; } - | EXPR_LT identifier - { $$ = 0; } - | superclasses EXPR_AND identifier '.' identifier - { $$ = 0; } - | superclasses EXPR_AND identifier - { $$ = 0; } +superclass_list : EXPR_LT superclass + { $$ = new tree_classdef_superclass_list ($2); } + | superclass_list EXPR_AND superclass + { + $1->append ($3); + $$ = $1; + } + ; + +superclass : identifier + { $$ = new tree_classdef_superclass ($1); } + | identifier '.' identifier + { $$ = new tree_classdef_superclass ($3, $1); } ; class_body : properties_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | methods_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | events_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | enum_block - { $$ = 0; } + { $$ = new tree_classdef_body ($1); } | class_body opt_sep properties_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep methods_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep events_block - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } | class_body opt_sep enum_block - { $$ = 0; } - ; - -properties_beg : PROPERTIES stash_comment - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; properties_block - : properties_beg opt_attr_list opt_sep properties_list opt_sep END - { $$ = 0; } + : PROPERTIES stash_comment opt_attr_list opt_sep property_list opt_sep END + { + if (! ($$ = make_classdef_properties_block ($1, $3, $5, $7, $2))) + ABORT_PARSE; + } ; -properties_list +property_list : class_property - { $$ = 0; } - | properties_list opt_sep class_property - { $$ = 0; } + { $$ = new tree_classdef_property_list ($1); } + | property_list opt_sep class_property + { + $1->append ($3); + $$ = $1; + } ; class_property : identifier - { $$ = 0; } + { $$ = new tree_classdef_property ($1); } | identifier '=' decl_param_init expression ';' - { $$ = 0; } + { + lexer_flags.looking_at_initializer_expression = false; + $$ = new tree_classdef_property ($1, $4); + } ; -methods_beg : METHODS stash_comment - { $$ = 0; } - ; - -methods_block : methods_beg opt_attr_list opt_sep methods_list opt_sep END - { $$ = 0; } +methods_block : METHODS stash_comment opt_attr_list opt_sep methods_list opt_sep END + { + if (! ($$ = make_classdef_methods_block ($1, $3, $5, $7, $2))) + ABORT_PARSE; + } ; methods_list : function - { $$ = 0; } + { + octave_value fcn; + if ($1) + fcn = $1->function (); + delete $1; + $$ = new tree_classdef_methods_list (fcn); + } | methods_list opt_sep function - { $$ = 0; } + { + octave_value fcn; + if ($3) + fcn = $3->function (); + delete $3; + + $1->append (fcn); + $$ = $1; + } ; -events_beg : EVENTS stash_comment - { $$ = 0; } - ; - -events_block : events_beg opt_attr_list opt_sep events_list opt_sep END - { $$ = 0; } +events_block : EVENTS stash_comment opt_attr_list opt_sep events_list opt_sep END + { + if (! ($$ = make_classdef_events_block ($1, $3, $5, $7, $2))) + ABORT_PARSE; + } ; events_list : class_event - { $$ = 0; } + { $$ = new tree_classdef_events_list ($1); } | events_list opt_sep class_event - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_event : identifier - { $$ = 0; } + { $$ = new tree_classdef_event ($1); } ; -enum_beg : ENUMERATION stash_comment - { $$ = 0; } - ; - -enum_block : enum_beg opt_attr_list opt_sep enum_list opt_sep END - { $$ = 0; } +enum_block : ENUMERATION stash_comment opt_attr_list opt_sep enum_list opt_sep END + { + if (! ($$ = make_classdef_enum_block ($1, $3, $5, $7, $2))) + ABORT_PARSE; + } ; enum_list : class_enum - { $$ = 0; } + { $$ = new tree_classdef_enum_list ($1); } | enum_list opt_sep class_enum - { $$ = 0; } + { + $1->append ($3); + $$ = $1; + } ; class_enum : identifier '(' expression ')' - { $$ = 0; } + { $$ = new tree_classdef_enum ($1, $3); } ; // ============= @@ -3268,6 +3402,151 @@ return list; } +static tree_funcall * +make_superclass_ref (const std::string& method_nm, + const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(2) = class_nm; + args(1) = package_nm; + args(0) = method_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__superclass_reference__"); + + return new tree_funcall (fcn, args); +} + +static tree_funcall * +make_meta_class_query (const std::string& package_nm, + const std::string& class_nm, + int l, int c) +{ + octave_value_list args; + + args(1) = class_nm; + args(0) = package_nm; + + octave_value fcn + = symbol_table::find_built_in_function ("__meta_class_query__"); + + return new tree_funcall (fcn, args); +} + +// A CLASSDEF block defines a class that has a constructor and other +// methods, but it is not an executable command. Parsing the block +// makes some changes in the symbol table (inserting the constructor +// and methods, and adding to the list of known objects) and creates +// a parse tree containing meta information about the class. + +static tree_classdef * +make_classdef (token *tok_val, tree_classdef_attribute_list *a, + tree_identifier *id, tree_classdef_superclass_list *sc, + tree_classdef_body *body, token *end_tok, + octave_comment_list *lc) +{ + tree_classdef *retval = 0; + + if (end_token_ok (end_tok, token::classdef_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef (a, id, sc, body, lc, tc, l, c); + } + + return retval; +} + +static tree_classdef_properties_block * +make_classdef_properties_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + token *end_tok, octave_comment_list *lc) +{ + tree_classdef_properties_block *retval = 0; + + if (end_token_ok (end_tok, token::properties_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_properties_block (a, plist, lc, tc, l, c); + } + + return retval; +} + +static tree_classdef_methods_block * +make_classdef_methods_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + token *end_tok, octave_comment_list *lc) +{ + tree_classdef_methods_block *retval = 0; + + if (end_token_ok (end_tok, token::methods_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_methods_block (a, mlist, lc, tc, l, c); + } + + return retval; +} + +static tree_classdef_events_block * +make_classdef_events_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + token *end_tok, octave_comment_list *lc) +{ + tree_classdef_events_block *retval = 0; + + if (end_token_ok (end_tok, token::events_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_events_block (a, elist, lc, tc, l, c); + } + + return retval; +} + +static tree_classdef_enum_block * +make_classdef_enum_block (token *tok_val, + tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + token *end_tok, octave_comment_list *lc) +{ + tree_classdef_enum_block *retval = 0; + + if (end_token_ok (end_tok, token::enumeration_end)) + { + octave_comment_list *tc = octave_comment_buffer::get_comment (); + + int l = tok_val->line (); + int c = tok_val->column (); + + retval = new tree_classdef_enum_block (a, elist, lc, tc, l, c); + } + + return retval; +} + static void safe_fclose (FILE *f) { @@ -3546,11 +3825,7 @@ reading_classdef_file = true; reading_fcn_file = false; - // FIXME -- Should classdef files be handled as - // scripts or separately? Currently, without setting up - // for reading script files, parsing classdef files - // fails. - reading_script_file = true; + reading_script_file = false; } else { @@ -3574,6 +3849,9 @@ frame.protect_var (primary_fcn_ptr); primary_fcn_ptr = 0; + frame.protect_var (classdef_object); + classdef_object = 0; + reset_parser (); // Do this with an unwind-protect cleanup function so that @@ -3587,6 +3865,8 @@ if (reading_script_file) prep_lexer_for_script_file (); + else if (reading_classdef_file) + prep_lexer_for_classdef_file (); else prep_lexer_for_function_file (); @@ -3606,9 +3886,22 @@ fcn_ptr = primary_fcn_ptr; - if (status != 0) - error ("parse error while reading %s file %s", - file_type.c_str (), ff.c_str ()); + if (status == 0) + { + if (reading_classdef_file && classdef_object) + { + // Convert parse tree for classdef object to + // meta.class info (and stash it in the symbol + // table?). Return pointer to constructor? + + octave_value meta_class = classdef_object->make_meta_class (); + } + } + else + { + error ("parse error while reading %s file %s", + file_type.c_str(), ff.c_str ()); + } } else { diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-all.h --- a/src/parse-tree/pt-all.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-all.h Sun Aug 05 09:20:57 2012 -0400 @@ -30,6 +30,7 @@ #include "pt-binop.h" #include "pt-cbinop.h" #include "pt-check.h" +#include "pt-classdef.h" #include "pt-cmd.h" #include "pt-colon.h" #include "pt-const.h" @@ -37,6 +38,7 @@ #include "pt-except.h" #include "pt-exp.h" #include "pt-fcn-handle.h" +#include "pt-funcall.h" #include "pt-id.h" #include "pt-idx.h" #include "pt-jump.h" diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-bp.cc --- a/src/parse-tree/pt-bp.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-bp.cc Sun Aug 05 09:20:57 2012 -0400 @@ -299,6 +299,12 @@ } void +tree_breakpoint::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_breakpoint::visit_parameter_list (tree_parameter_list&) { panic_impossible (); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-bp.h --- a/src/parse-tree/pt-bp.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-bp.h Sun Aug 05 09:20:57 2012 -0400 @@ -106,6 +106,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-check.cc --- a/src/parse-tree/pt-check.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-check.cc Sun Aug 05 09:20:57 2012 -0400 @@ -357,6 +357,11 @@ } void +tree_checker::visit_funcall (tree_funcall& /* fc */) +{ +} + +void tree_checker::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-check.h --- a/src/parse-tree/pt-check.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-check.h Sun Aug 05 09:20:57 2012 -0400 @@ -91,6 +91,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-classdef.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/pt-classdef.cc Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,260 @@ +/* + +Copyright (C) 2012 John W. Eaton + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-classdef.h" +#include "pt-classdef.h" + +// Classdef attribute + +void +tree_classdef_attribute::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute (*this); +} + +// Classdef attribute_list + +tree_classdef_attribute_list::~tree_classdef_attribute_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_attribute_list::accept (tree_walker& tw) +{ + tw.visit_classdef_attribute_list (*this); +} + +// Classdef superclass + +void +tree_classdef_superclass::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass (*this); +} + +// Classdef superclass_list + +tree_classdef_superclass_list::~tree_classdef_superclass_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_superclass_list::accept (tree_walker& tw) +{ + tw.visit_classdef_superclass_list (*this); +} + +// Classdef property + +void +tree_classdef_property::accept (tree_walker& tw) +{ + tw.visit_classdef_property (*this); +} + +// Classdef property_list + +tree_classdef_property_list::~tree_classdef_property_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_property_list::accept (tree_walker& tw) +{ + tw.visit_classdef_property_list (*this); +} + +// Classdef properties_block + +void +tree_classdef_properties_block::accept (tree_walker& tw) +{ + tw.visit_classdef_properties_block (*this); +} + +// Classdef methods_list + +void +tree_classdef_methods_list::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_list (*this); +} + +// Classdef methods_block + +void +tree_classdef_methods_block::accept (tree_walker& tw) +{ + tw.visit_classdef_methods_block (*this); +} + +// Classdef event + +void +tree_classdef_event::accept (tree_walker& tw) +{ + tw.visit_classdef_event (*this); +} + +// Classdef events_list + +tree_classdef_events_list::~tree_classdef_events_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_events_list::accept (tree_walker& tw) +{ + tw.visit_classdef_events_list (*this); +} + +// Classdef events_block + +void +tree_classdef_events_block::accept (tree_walker& tw) +{ + tw.visit_classdef_events_block (*this); +} + +// Classdef enum + +void +tree_classdef_enum::accept (tree_walker& tw) +{ + tw.visit_classdef_enum (*this); +} + +// Classdef enum_list + +tree_classdef_enum_list::~tree_classdef_enum_list (void) +{ + while (! empty ()) + { + iterator p = begin (); + delete *p; + erase (p); + } +} + +void +tree_classdef_enum_list::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_list (*this); +} + +// Classdef enum_block + +void +tree_classdef_enum_block::accept (tree_walker& tw) +{ + tw.visit_classdef_enum_block (*this); +} + +// Classdef body + +tree_classdef_body::~tree_classdef_body (void) +{ + while (! properties_lst.empty ()) + { + properties_list_iterator p = properties_lst.begin (); + delete *p; + properties_lst.erase (p); + } + + while (! methods_lst.empty ()) + { + methods_list_iterator p = methods_lst.begin (); + delete *p; + methods_lst.erase (p); + } + + while (! events_lst.empty ()) + { + events_list_iterator p = events_lst.begin (); + delete *p; + events_lst.erase (p); + } + + while (! enum_lst.empty ()) + { + enum_list_iterator p = enum_lst.begin (); + delete *p; + enum_lst.erase (p); + } +} + +// Classdef + +octave_value +tree_classdef::make_meta_class (void) const +{ + octave_value retval; + cdef_class cls = cdef_class::make_meta_class (this); + + if (cls.ok ()) + retval = to_ov (cls); + + return retval; +} + +tree_classdef * +tree_classdef::dup (symbol_table::scope_id, + symbol_table::context_id) const +{ + // FIXME + return 0; +} + +void +tree_classdef::accept (tree_walker& tw) +{ + std::cerr << "I am super accepting" << std::endl; + // tw.visit_classdef (*this); +} diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-classdef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/pt-classdef.h Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,653 @@ +/* + +Copyright (C) 2012 John W. Eaton + +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 +. + +*/ + +#if !defined (octave_tree_classdef_h) +#define octave_tree_classdef_h 1 + +class octave_value; + +class tree_walker; + +#include "pt-cmd.h" +#include "pt-exp.h" +#include "pt-id.h" + +#include "base-list.h" + +#include + +class tree_classdef_attribute +{ +public: + + tree_classdef_attribute (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e), neg (false) { } + + tree_classdef_attribute (tree_identifier *i, bool b) + : id (i), expr (0), neg (b) { } + + ~tree_classdef_attribute (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + bool negate (void) { return neg; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + bool neg; + + // No copying! + + tree_classdef_attribute (const tree_classdef_attribute&); + + tree_classdef_attribute& operator = (const tree_classdef_attribute&); +}; + +class tree_classdef_attribute_list : public octave_base_list +{ +public: + + tree_classdef_attribute_list (void) { } + + tree_classdef_attribute_list (tree_classdef_attribute *a) { append (a); } + + tree_classdef_attribute_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_attribute_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_attribute_list (const tree_classdef_attribute_list&); + + tree_classdef_attribute_list& operator = (const tree_classdef_attribute_list&); +}; + +class tree_classdef_superclass +{ +public: + + tree_classdef_superclass (tree_identifier *i = 0, tree_identifier *p = 0) + : id (i), pkg (p) { } + + ~tree_classdef_superclass (void) + { + delete id; + delete pkg; + } + + tree_identifier *ident (void) { return id; } + + tree_identifier * package (void) { return pkg; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_identifier *pkg; + + // No copying! + + tree_classdef_superclass (const tree_classdef_superclass&); + + tree_classdef_superclass& operator = (const tree_classdef_superclass&); +}; + +class tree_classdef_superclass_list : public octave_base_list +{ +public: + + tree_classdef_superclass_list (void) { } + + tree_classdef_superclass_list (tree_classdef_superclass *sc) { append (sc); } + + tree_classdef_superclass_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_superclass_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_superclass_list (const tree_classdef_superclass_list&); + + tree_classdef_superclass_list& operator = (const tree_classdef_superclass_list&); +}; + +template +class tree_classdef_element : public tree +{ +public: + + tree_classdef_element (tree_classdef_attribute_list *a, + octave_base_list *elist, + octave_comment_list *lc, octave_comment_list *tc, + int l = -1, int c = -1) + : tree (l, c), attr_list (a), elt_list (elist), + lead_comm (lc), trail_comm (tc) + { } + + ~tree_classdef_element (void) + { + delete attr_list; + delete elt_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + octave_base_list *element_list (void) { return elt_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + + octave_comment_list *trailing_comment (void) { return trail_comm; } + + void accept (tree_walker&) { } + +private: + + // List of attributes that apply to this class. + tree_classdef_attribute_list *attr_list; + + // The list of objects contained in this block. + octave_base_list *elt_list; + + // Comment preceding the token marking the beginning of the block. + octave_comment_list *lead_comm; + + // Comment preceding END token. + octave_comment_list *trail_comm; + + // No copying! + + tree_classdef_element (const tree_classdef_element&); + + tree_classdef_element& operator = (const tree_classdef_element&); +}; + +class tree_classdef_property +{ +public: + + tree_classdef_property (tree_identifier *i = 0, tree_expression *e = 0) + : id (i), expr (e) { } + + ~tree_classdef_property (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_property (const tree_classdef_property&); + + tree_classdef_property& operator = (const tree_classdef_property&); +}; + +class tree_classdef_property_list : public octave_base_list +{ +public: + + tree_classdef_property_list (void) { } + + tree_classdef_property_list (tree_classdef_property* p) { append (p); } + + tree_classdef_property_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_property_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_property_list (const tree_classdef_property_list&); + + tree_classdef_property_list& operator = (const tree_classdef_property_list&); +}; + +class tree_classdef_properties_block + : public tree_classdef_element +{ +public: + + tree_classdef_properties_block (tree_classdef_attribute_list *a, + tree_classdef_property_list *plist, + octave_comment_list *lc, + octave_comment_list *tc, + int l = -1, int c = -1) + : tree_classdef_element (a, plist, lc, tc, l, c) { } + + ~tree_classdef_properties_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_properties_block (const tree_classdef_properties_block&); + + tree_classdef_properties_block& operator = (const tree_classdef_properties_block&); +}; + +class tree_classdef_methods_list : public octave_base_list +{ +public: + + tree_classdef_methods_list (void) { } + + tree_classdef_methods_list (const octave_value& f) { append (f); } + + tree_classdef_methods_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_methods_list (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_list (const tree_classdef_methods_list&); + + tree_classdef_methods_list& operator = (const tree_classdef_methods_list&); +}; + +class tree_classdef_methods_block : public tree_classdef_element +{ +public: + + tree_classdef_methods_block (tree_classdef_attribute_list *a, + tree_classdef_methods_list *mlist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, mlist, lc, tc, l, c) { } + + ~tree_classdef_methods_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_methods_block (const tree_classdef_methods_block&); + + tree_classdef_methods_block& operator = (const tree_classdef_methods_block&); +}; + +class tree_classdef_event +{ +public: + + tree_classdef_event (tree_identifier *i = 0) : id (i) { } + + ~tree_classdef_event (void) + { + delete id; + } + + tree_identifier *ident (void) { return id; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + + // No copying! + + tree_classdef_event (const tree_classdef_event&); + + tree_classdef_event& operator = (const tree_classdef_event&); +}; + +class tree_classdef_events_list : public octave_base_list +{ +public: + + tree_classdef_events_list (void) { } + + tree_classdef_events_list (tree_classdef_event *e) { append (e); } + + tree_classdef_events_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_events_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_list (const tree_classdef_events_list&); + + tree_classdef_events_list& operator = (const tree_classdef_events_list&); +}; + +class tree_classdef_events_block + : public tree_classdef_element +{ +public: + + tree_classdef_events_block (tree_classdef_attribute_list *a, + tree_classdef_events_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_events_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_events_block (const tree_classdef_events_block&); + + tree_classdef_events_block& operator = (const tree_classdef_events_block&); +}; + +class tree_classdef_enum +{ +public: + + tree_classdef_enum (void) : id (0), expr (0) { } + + tree_classdef_enum (tree_identifier *i, tree_expression *e) + : id (i), expr (e) { } + + ~tree_classdef_enum (void) + { + delete id; + delete expr; + } + + tree_identifier *ident (void) { return id; } + + tree_expression *expression (void) { return expr; } + + void accept (tree_walker&); + +private: + + tree_identifier *id; + tree_expression *expr; + + // No copying! + + tree_classdef_enum (const tree_classdef_enum&); + + tree_classdef_enum& operator = (const tree_classdef_enum&); +}; + +class tree_classdef_enum_list : public octave_base_list +{ +public: + + tree_classdef_enum_list (void) { } + + tree_classdef_enum_list (tree_classdef_enum *e) { append (e); } + + tree_classdef_enum_list (const octave_base_list& a) + : octave_base_list (a) { } + + ~tree_classdef_enum_list (void); + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_list (const tree_classdef_enum_list&); + + tree_classdef_enum_list& operator = (const tree_classdef_enum_list&); +}; + +class tree_classdef_enum_block + : public tree_classdef_element +{ +public: + + tree_classdef_enum_block (tree_classdef_attribute_list *a, + tree_classdef_enum_list *elist, + octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_classdef_element (a, elist, lc, tc, l, c) { } + + ~tree_classdef_enum_block (void) { } + + void accept (tree_walker&); + +private: + + // No copying! + + tree_classdef_enum_block (const tree_classdef_enum_block&); + + tree_classdef_enum_block& operator = (const tree_classdef_enum_block&); +}; + +class tree_classdef_body +{ +public: + + typedef typename std::list::iterator properties_list_iterator; + typedef typename std::list::const_iterator properties_list_const_iterator; + + typedef typename std::list::iterator methods_list_iterator; + typedef typename std::list::const_iterator methods_list_const_iterator; + + typedef typename std::list::iterator events_list_iterator; + typedef typename std::list::const_iterator events_list_const_iterator; + + typedef typename std::list::iterator enum_list_iterator; + typedef typename std::list::const_iterator enum_list_const_iterator; + + tree_classdef_body (void) + : properties_lst (), methods_lst (), events_lst (), enum_lst () { } + + tree_classdef_body (tree_classdef_properties_block *pb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (pb); + } + + tree_classdef_body (tree_classdef_methods_block *mb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (mb); + } + + tree_classdef_body (tree_classdef_events_block *evb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (evb); + } + + tree_classdef_body (tree_classdef_enum_block *enb) + : properties_lst (), methods_lst (), events_lst (), enum_lst () + { + append (enb); + } + + ~tree_classdef_body (void); + + void append (tree_classdef_properties_block *pb) + { + properties_lst.push_back (pb); + } + + void append (tree_classdef_methods_block *mb) + { + methods_lst.push_back (mb); + } + + void append (tree_classdef_events_block *evb) + { + events_lst.push_back (evb); + } + + void append (tree_classdef_enum_block *enb) + { + enum_lst.push_back (enb); + } + + std::list properties_list (void) + { + return properties_lst; + } + + std::list methods_list (void) + { + return methods_lst; + } + + std::list events_list (void) + { + return events_lst; + } + + std::list enum_list (void) + { + return enum_lst; + } + + void accept (tree_walker&); + +private: + + std::list properties_lst; + + std::list methods_lst; + + std::list events_lst; + + std::list enum_lst; + + // No copying! + + tree_classdef_body (const tree_classdef_body&); + + tree_classdef_body& operator = (const tree_classdef_body&); +}; + +// Classdef definition. + +class tree_classdef : public tree_command +{ +public: + + tree_classdef (tree_classdef_attribute_list *a, tree_identifier *i, + tree_classdef_superclass_list *sc, + tree_classdef_body *b, octave_comment_list *lc, + octave_comment_list *tc, int l = -1, int c = -1) + : tree_command (l, c), attr_list (a), id (i), + supclass_list (sc), element_list (b), lead_comm (lc), trail_comm (tc) { } + + ~tree_classdef (void) + { + delete attr_list; + delete id; + delete supclass_list; + delete element_list; + delete lead_comm; + delete trail_comm; + } + + tree_classdef_attribute_list *attribute_list (void) { return attr_list; } + + tree_identifier *ident (void) { return id; } + + tree_classdef_superclass_list *superclass_list (void) { return supclass_list; } + + tree_classdef_body *body (void) { return element_list; } + + octave_comment_list *leading_comment (void) { return lead_comm; } + octave_comment_list *trailing_comment (void) { return trail_comm; } + + octave_value make_meta_class (void) const; + + tree_classdef *dup (symbol_table::scope_id scope, + symbol_table::context_id context) const; + + void accept (tree_walker& tw); + +private: + + tree_classdef_attribute_list *attr_list; + + tree_identifier *id; + + tree_classdef_superclass_list *supclass_list; + + tree_classdef_body *element_list; + + octave_comment_list *lead_comm; + octave_comment_list *trail_comm; + + // No copying! + + tree_classdef (const tree_classdef&); + + tree_classdef& operator = (const tree_classdef&); +}; + +#endif diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-eval.cc --- a/src/parse-tree/pt-eval.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-eval.cc Sun Aug 05 09:20:57 2012 -0400 @@ -633,6 +633,12 @@ } void +tree_evaluator::visit_funcall (tree_funcall&) +{ + panic_impossible (); +} + +void tree_evaluator::visit_parameter_list (tree_parameter_list&) { panic_impossible (); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-eval.h --- a/src/parse-tree/pt-eval.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-eval.h Sun Aug 05 09:20:57 2012 -0400 @@ -102,6 +102,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-funcall.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/pt-funcall.cc Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,83 @@ +/* + +Copyright (C) 2012 John W. Eaton + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ov-fcn.h" +#include "pt-funcall.h" +#include "pt-walk.h" + +// Function call objects. + +void +tree_funcall::print (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + print_raw (os, pr_as_read_syntax, pr_orig_text); +} + +void +tree_funcall::print_raw (std::ostream& os, bool pr_as_read_syntax, + bool pr_orig_text) +{ + if (pr_orig_text) + { + os << original_text (); + } + else + { + octave_function *fp = fcn.function_value (); + std::string nm = fp ? fp->name () : std::string (""); + + os << nm << " ("; + + octave_idx_type len = args.length (); + for (octave_idx_type i = 0; i < len; i++) + { + args(i).print_raw (os, pr_as_read_syntax); + + if (i < len - 1) + os << ", "; + } + + os << ")"; + } +} + +tree_funcall * +tree_funcall::dup (symbol_table::scope_id, + symbol_table::context_id context) const +{ + tree_funcall *new_fc = new tree_funcall (fcn, args, line (), column ()); + + new_fc->copy_base (*new_fc); + + return new_fc; +} + +void +tree_funcall::accept (tree_walker& tw) +{ + tw.visit_funcall (*this); +} diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-funcall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/pt-funcall.h Sun Aug 05 09:20:57 2012 -0400 @@ -0,0 +1,101 @@ +/* + +Copyright (C) 2012 John W. Eaton + +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 +. + +*/ + +#if !defined (octave_tree_funcall_h) +#define octave_tree_funcall_h 1 + +#include "ov.h" +#include "oct-obj.h" +#include "parse.h" +#include "pt-exp.h" + +// Function call. This class only represents function calls that have +// known functions (most useful for calls to built-in functions that +// are generated by the parser) and fixed argument lists, known at +// compile time. + +class +tree_funcall : public tree_expression +{ +public: + + tree_funcall (const octave_value& f, const octave_value_list& a, + int l = -1, int c = -1) + : tree_expression (l, c), fcn (f), args (a) + { + if (! fcn.is_function ()) + error ("tree_funcall: invalid function"); + } + + ~tree_funcall (void) { } + + bool has_magic_end (void) const { return false; } + + void print (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false, + bool pr_orig_txt = true); + + tree_funcall *dup (symbol_table::scope_id, + symbol_table::context_id context) const; + + octave_value rvalue1 (int nargout) + { + octave_value retval; + + const octave_value_list tmp = rvalue (nargout); + + if (! tmp.empty ()) + retval = tmp(0); + + return retval; + } + + octave_value_list rvalue (int nargout) + { + return feval (fcn.function_value (), args, nargout); + } + + octave_value function (void) const { return fcn; } + + octave_value_list arguments (void) const { return args; } + + void accept (tree_walker& tw); + +private: + + // Function to call. Error if not a valid function at time of + // construction. + octave_value fcn; + + // Argument list. + octave_value_list args; + + // No copying! + + tree_funcall (const tree_funcall&); + + tree_funcall& operator = (const tree_funcall&); +}; + +#endif diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-id.h --- a/src/parse-tree/pt-id.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-id.h Sun Aug 05 09:20:57 2012 -0400 @@ -32,6 +32,7 @@ class tree_walker; +#include "oct-lvalue.h" #include "pt-bp.h" #include "pt-exp.h" #include "symtab.h" diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-pr-code.cc --- a/src/parse-tree/pt-pr-code.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-pr-code.cc Sun Aug 05 09:20:57 2012 -0400 @@ -749,6 +749,18 @@ } void +tree_print_code::visit_funcall (tree_funcall& fc) +{ + indent (); + + print_parens (fc, "("); + + fc.print_raw (os, true, print_original_text); + + print_parens (fc, ")"); +} + +void tree_print_code::visit_parameter_list (tree_parameter_list& lst) { tree_parameter_list::iterator p = lst.begin (); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-pr-code.h --- a/src/parse-tree/pt-pr-code.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-pr-code.h Sun Aug 05 09:20:57 2012 -0400 @@ -109,6 +109,8 @@ void visit_fcn_handle (tree_fcn_handle&); + void visit_funcall (tree_funcall&); + void visit_parameter_list (tree_parameter_list&); void visit_postfix_expression (tree_postfix_expression&); diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/pt-walk.h --- a/src/parse-tree/pt-walk.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/pt-walk.h Sun Aug 05 09:20:57 2012 -0400 @@ -52,6 +52,7 @@ class tree_no_op_command; class tree_constant; class tree_fcn_handle; +class tree_funcall; class tree_parameter_list; class tree_postfix_expression; class tree_prefix_expression; @@ -65,6 +66,24 @@ class tree_while_command; class tree_do_until_command; +class tree_classdef_attribute; +class tree_classdef_attribute_list; +class tree_classdef_superclass; +class tree_classdef_superclass_list; +class tree_classdef_property; +class tree_classdef_property_list; +class tree_classdef_properties_block; +class tree_classdef_methods_list; +class tree_classdef_methods_block; +class tree_classdef_event; +class tree_classdef_events_list; +class tree_classdef_events_block; +class tree_classdef_enum; +class tree_classdef_enum_list; +class tree_classdef_enum_block; +class tree_classdef_body; +class tree_classdef; + class tree_walker { @@ -158,6 +177,9 @@ visit_fcn_handle (tree_fcn_handle&) = 0; virtual void + visit_funcall (tree_funcall&) = 0; + + virtual void visit_parameter_list (tree_parameter_list&) = 0; virtual void @@ -193,6 +215,57 @@ virtual void visit_do_until_command (tree_do_until_command&) = 0; + virtual void + visit_classdef_attribute (tree_classdef_attribute&) { } /* = 0; */ + + virtual void + visit_classdef_attribute_list (tree_classdef_attribute_list&) { } /* = 0; */ + + virtual void + visit_classdef_superclass (tree_classdef_superclass&) { } /* = 0; */ + + virtual void + visit_classdef_superclass_list (tree_classdef_superclass_list&) { } /* = 0; */ + + virtual void + visit_classdef_property (tree_classdef_property&) { } /* = 0; */ + + virtual void + visit_classdef_property_list (tree_classdef_property_list&) { } /* = 0; */ + + virtual void + visit_classdef_properties_block (tree_classdef_properties_block&) { } /* = 0; */ + + virtual void + visit_classdef_methods_list (tree_classdef_methods_list&) { } /* = 0; */ + + virtual void + visit_classdef_methods_block (tree_classdef_methods_block&) { } /* = 0; */ + + virtual void + visit_classdef_event (tree_classdef_event&) { } /* = 0; */ + + virtual void + visit_classdef_events_list (tree_classdef_events_list&) { } /* = 0; */ + + virtual void + visit_classdef_events_block (tree_classdef_events_block&) { } /* = 0; */ + + virtual void + visit_classdef_enum (tree_classdef_enum&) { } /* = 0; */ + + virtual void + visit_classdef_enum_list (tree_classdef_enum_list&) { } /* = 0; */ + + virtual void + visit_classdef_enum_block (tree_classdef_enum_block&) { } /* = 0; */ + + virtual void + visit_classdef_body (tree_classdef_body&) { } /* = 0; */ + + virtual void + visit_classdef (tree_classdef&) { } /* = 0; */ + protected: tree_walker (void) { } diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/token.cc --- a/src/parse-tree/token.cc Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/token.cc Sun Aug 05 09:20:57 2012 -0400 @@ -72,32 +72,43 @@ sr = s; } -token::token (symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) +token::token (const std::string& pkg, const std::string& cls, int l, int c) { line_num = l; column_num = c; - type_tag = meta_rec_token; - mc.cr = cls; - mc.pr = pkg; + type_tag = meta_name_token; + mc.package_nm = new std::string (pkg); + mc.class_nm = new std::string (cls); } -token::token (symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) +token::token (const std::string& mth, const std::string& pkg, + const std::string& cls, int l, int c) { line_num = l; column_num = c; - type_tag = scls_rec_token; - sc.mr = mth; - sc.cr = cls; - sc.pr = pkg; + type_tag = scls_name_token; + sc.method_nm = new std::string (mth); + sc.package_nm = new std::string (pkg); + sc.class_nm = new std::string (cls); } token::~token (void) { if (type_tag == string_token) delete str; + + if (type_tag == scls_name_token) + { + delete sc.method_nm; + delete sc.package_nm; + delete sc.class_nm; + } + + if (type_tag == meta_name_token) + { + delete mc.package_nm; + delete mc.class_nm; + } } std::string @@ -128,39 +139,39 @@ return sr; } -symbol_table::symbol_record * -token::method_rec (void) +std::string +token::superclass_method_name (void) { - assert (type_tag == scls_rec_token); - return sc.mr; + assert (type_tag == scls_name_token); + return *sc.method_nm; } -symbol_table::symbol_record * -token::class_rec (void) +std::string +token::superclass_package_name (void) { - assert (type_tag == scls_rec_token); - return sc.cr; + assert (type_tag == scls_name_token); + return *sc.package_nm; } -symbol_table::symbol_record * -token::package_rec (void) +std::string +token::superclass_class_name (void) { - assert (type_tag == scls_rec_token); - return sc.pr; + assert (type_tag == scls_name_token); + return *sc.class_nm; } -symbol_table::symbol_record * -token::meta_class_rec (void) +std::string +token::meta_package_name (void) { - assert (type_tag == meta_rec_token); - return mc.cr; + assert (type_tag == meta_name_token); + return *mc.package_nm; } -symbol_table::symbol_record * -token::meta_package_rec (void) +std::string +token::meta_class_name (void) { - assert (type_tag == meta_rec_token); - return mc.pr; + assert (type_tag == meta_name_token); + return *mc.class_nm; } std::string diff -r 03381a36f70d -r 28ffdc42b550 src/parse-tree/token.h --- a/src/parse-tree/token.h Sun Aug 05 09:04:30 2012 -0400 +++ b/src/parse-tree/token.h Sun Aug 05 09:20:57 2012 -0400 @@ -37,8 +37,8 @@ double_token, ettype_token, sym_rec_token, - scls_rec_token, - meta_rec_token + scls_name_token, + meta_name_token }; enum end_tok_type @@ -65,11 +65,10 @@ int l = -1, int c = -1); token (end_tok_type t, int l = -1, int c = -1); token (symbol_table::symbol_record *s, int l = -1, int c = -1); - token (symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); - token (symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); + token (const std::string& pkg, const std::string& cls, + int l = -1, int c = -1); + token (const std::string& mth, const std::string& pkg, + const std::string& cls, int l = -1, int c = -1); ~token (void); @@ -81,12 +80,12 @@ end_tok_type ettype (void); symbol_table::symbol_record *sym_rec (void); - symbol_table::symbol_record *method_rec (void); - symbol_table::symbol_record *class_rec (void); - symbol_table::symbol_record *package_rec (void); + std::string superclass_method_name (void); + std::string superclass_package_name (void); + std::string superclass_class_name (void); - symbol_table::symbol_record *meta_class_rec (void); - symbol_table::symbol_record *meta_package_rec (void); + std::string meta_package_name (void); + std::string meta_class_name (void); std::string text_rep (void); @@ -109,14 +108,14 @@ symbol_table::symbol_record *sr; struct { - symbol_table::symbol_record *mr; - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; + std::string *method_nm; + std::string *package_nm; + std::string *class_nm; } sc; struct { - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; + std::string *package_nm; + std::string *class_nm; } mc; }; std::string orig_text;