Mercurial > octave
view libinterp/octave-value/cdef-manager.cc @ 30564:796f54d4ddbf stable
update Octave Project Developers copyright for the new year
In files that have the "Octave Project Developers" copyright notice,
update for 2021.
In all .txi and .texi files except gpl.txi and gpl.texi in the
doc/liboctave and doc/interpreter directories, change the copyright
to "Octave Project Developers", the same as used for other source
files. Update copyright notices for 2022 (not done since 2019). For
gpl.txi and gpl.texi, change the copyright notice to be "Free Software
Foundation, Inc." and leave the date at 2007 only because this file
only contains the text of the GPL, not anything created by the Octave
Project Developers.
Add Paul Thomas to contributors.in.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 28 Dec 2021 18:22:40 -0500 |
parents | a61e1a0f6024 |
children | 83f9f8bda883 |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2012-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // 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 // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include "cdef-manager.h" #include "cdef-utils.h" #include "interpreter.h" #include "ov-classdef.h" namespace octave { static octave_value make_fcn_handle (octave_builtin::fcn ff, const std::string& nm) { octave_value fcn (new octave_builtin (ff, nm)); return octave_value (new octave_fcn_handle (fcn)); } 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) = to_ov (lookup_classes (classes)); } return retval; } static octave_value_list class_get_inferiorclasses (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object" && args(0).class_name () == "meta.class") { cdef_class cls (to_cdef (args(0))); Cell classes = cls.get ("InferiorClasses").cell_value (); retval(0) = to_ov (lookup_classes (classes)); } return retval; } static octave_value_list class_fromName (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () != 1) error ("fromName: invalid number of parameters"); std::string name = args(0).xstring_value ("fromName: CLASS_NAME must be a string"); retval(0) = to_ov (lookup_class (name, false)); return retval; } static octave_value_list class_fevalStatic (const octave_value_list& args, int nargout) { if (args.length () <= 1 || args(0).type_name () != "object") error ("fevalStatic: first argument must be a meta.class object"); cdef_class cls (to_cdef (args(0))); std::string meth_name = args(1).xstring_value ("fevalStatic: method name must be a string"); cdef_method meth = cls.find_method (meth_name); if (! meth.ok ()) error ("fevalStatic: method not found: %s", meth_name.c_str ()); if (! meth.is_static ()) error ("fevalStatic: method '%s' is not static", meth_name.c_str ()); return meth.execute (args.splice (0, 2), nargout, true, "fevalStatic"); } 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") error ("getConstant: first argument must be a meta.class object"); cdef_class cls = to_cdef (args(0)); std::string prop_name = args(1).xstring_value ("getConstant: property name must be a string"); cdef_property prop = cls.find_property (prop_name); if (! prop.ok ()) error ("getConstant: property not found: %s", prop_name.c_str ()); if (! prop.is_constant ()) error ("getConstant: property '%s' is not constant", prop_name.c_str ()); retval(0) = prop.get_value (true, "getConstant"); 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") \ error (#OP ": invalid arguments"); \ \ cdef_class clsa = to_cdef (args(0)); \ \ cdef_class clsb = to_cdef (args(1)); \ \ retval(0) = FUN (CLSA, CLSB); \ \ 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 property_get_defaultvalue (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () == 1 && args(0).type_name () == "object") { cdef_property prop (to_cdef (args(0))); retval(0) = prop.get ("DefaultValue"); if (! retval(0).is_defined ()) error_with_id ("Octave:class:NoDefaultDefined", "no default value for property '%s'", prop.get_name ().c_str ()); } return retval; } static octave_value_list handle_delete (const octave_value_list& /* args */, int /* nargout */) { octave_value_list retval; // FIXME: implement this. Wait, what is this supposed to do? return retval; } static octave_value_list package_get_classes (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 1 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_classes (); } return retval; } static octave_value_list package_get_functions (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 0 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_functions (); } return retval; } static octave_value_list package_get_packages (const octave_value_list& args, int /* nargout */) { octave_value_list retval (1, Matrix ()); if (args.length () == 0 && args(0).type_name () == "object" && args(0).class_name () == "meta.package") { cdef_package pack (to_cdef (args(0))); retval(0) = pack.get_packages (); } return retval; } static octave_value_list package_getAllPackages (interpreter& interp, const octave_value_list& /* args */, int /* nargout */) { std::map<std::string, cdef_package> toplevel_packages; load_path& lp = interp.get_load_path (); std::list<std::string> names = lp.get_all_package_names (); cdef_manager& cdm = interp.get_cdef_manager (); toplevel_packages["meta"] = cdm.find_package ("meta", false, false); for (const auto& nm : names) toplevel_packages[nm] = cdm.find_package (nm, false, true); Cell c (toplevel_packages.size (), 1); int i = 0; for (const auto& nm_pkg : toplevel_packages) c(i++, 0) = to_ov (nm_pkg.second); return octave_value_list (octave_value (c)); } static octave_value_list package_fromName (const octave_value_list& args, int /* nargout */) { octave_value_list retval; if (args.length () != 1) error ("fromName: invalid number of parameters"); std::string name = args(0).xstring_value ("fromName: PACKAGE_NAME must be a string"); retval(0) = to_ov (lookup_package (name, false)); return retval; } cdef_manager::cdef_manager (interpreter& interp) : m_interpreter (interp), m_all_classes (), m_all_packages (), m_meta_class (), m_meta_property (), m_meta_method (), m_meta_package (), m_meta () { type_info& ti = m_interpreter.get_type_info (); octave_classdef::register_type (ti); // bootstrap cdef_class tmp_handle = make_class ("handle"); m_meta_class = make_meta_class ("meta.class", tmp_handle); tmp_handle.set_class (m_meta_class); m_meta_class.set_class (m_meta_class); // meta classes m_meta_property = make_meta_class ("meta.property", tmp_handle); m_meta_method = make_meta_class ("meta.method", tmp_handle); m_meta_package = make_meta_class ("meta.package", tmp_handle); cdef_class tmp_meta_event = make_meta_class ("meta.event", tmp_handle); cdef_class tmp_meta_dynproperty = make_meta_class ("meta.dynamicproperty", tmp_handle); // meta.class properties m_meta_class.install_property (make_attribute (m_meta_class, "Abstract")); m_meta_class.install_property (make_attribute (m_meta_class, "ConstructOnLoad")); m_meta_class.install_property (make_property (m_meta_class, "ContainingPackage")); m_meta_class.install_property (make_property (m_meta_class, "Description")); m_meta_class.install_property (make_property (m_meta_class, "DetailedDescription")); m_meta_class.install_property (make_property (m_meta_class, "Events")); m_meta_class.install_property (make_attribute (m_meta_class, "HandleCompatible")); m_meta_class.install_property (make_attribute (m_meta_class, "Hidden")); m_meta_class.install_property (make_property (m_meta_class, "InferiorClasses", make_fcn_handle (class_get_inferiorclasses, "meta.class>get.InferiorClasses"), "public", Matrix (), "private")); m_meta_class.install_property (make_property (m_meta_class, "Methods", make_fcn_handle (class_get_methods, "meta.class>get.Methods"), "public", Matrix (), "private")); m_meta_class.install_property (make_property (m_meta_class, "MethodList", make_fcn_handle (class_get_methods, "meta.class>get.MethodList"), "public", Matrix (), "private")); m_meta_class.install_property (make_attribute (m_meta_class, "Name")); m_meta_class.install_property (make_property (m_meta_class, "Properties", make_fcn_handle (class_get_properties, "meta.class>get.Properties"), "public", Matrix (), "private")); m_meta_class.install_property (make_property (m_meta_class, "PropertyList", make_fcn_handle (class_get_properties, "meta.class>get.PropertyList"), "public", Matrix (), "private")); m_meta_class.install_property (make_attribute (m_meta_class, "Sealed")); m_meta_class.install_property (make_property (m_meta_class, "SuperClasses", make_fcn_handle (class_get_superclasses, "meta.class>get.SuperClasses"), "public", Matrix (), "private")); m_meta_class.install_property (make_property (m_meta_class, "SuperclassList", make_fcn_handle (class_get_superclasses, "meta.class>get.SuperclassList"), "public", Matrix (), "private")); // FIXME: Matlab supports this property under "SuperclassList". // Octave, however, has supported this under "SuperClassList". // Alias the property. Remove in Octave version 8.1. m_meta_class.install_property (make_property (m_meta_class, "SuperClassList", make_fcn_handle (class_get_superclasses, "meta.class>get.SuperclassList"), "public", Matrix (), "private")); // meta.class methods m_meta_class.install_method (make_method (m_meta_class, "fromName", class_fromName, "public", true)); m_meta_class.install_method (make_method (m_meta_class, "fevalStatic", class_fevalStatic, "public", false)); m_meta_class.install_method (make_method (m_meta_class, "getConstant", class_getConstant, "public", false)); m_meta_class.install_method (make_method (m_meta_class, "eq", class_eq)); m_meta_class.install_method (make_method (m_meta_class, "ne", class_ne)); m_meta_class.install_method (make_method (m_meta_class, "lt", class_lt)); m_meta_class.install_method (make_method (m_meta_class, "le", class_le)); m_meta_class.install_method (make_method (m_meta_class, "gt", class_gt)); m_meta_class.install_method (make_method (m_meta_class, "ge", class_ge)); // meta.method properties m_meta_method.install_property (make_attribute (m_meta_method, "Abstract")); m_meta_method.install_property (make_attribute (m_meta_method, "Access")); m_meta_method.install_property (make_attribute (m_meta_method, "DefiningClass")); m_meta_method.install_property (make_attribute (m_meta_method, "Description")); m_meta_method.install_property (make_attribute (m_meta_method, "DetailedDescription")); m_meta_method.install_property (make_attribute (m_meta_method, "Hidden")); m_meta_method.install_property (make_attribute (m_meta_method, "Name")); m_meta_method.install_property (make_attribute (m_meta_method, "Sealed")); m_meta_method.install_property (make_attribute (m_meta_method, "Static")); // meta.property properties m_meta_property.install_property (make_attribute (m_meta_property, "Name")); m_meta_property.install_property (make_attribute (m_meta_property, "Description")); m_meta_property.install_property (make_attribute (m_meta_property, "DetailedDescription")); m_meta_property.install_property (make_attribute (m_meta_property, "Abstract")); m_meta_property.install_property (make_attribute (m_meta_property, "Constant")); m_meta_property.install_property (make_attribute (m_meta_property, "GetAccess")); m_meta_property.install_property (make_attribute (m_meta_property, "SetAccess")); m_meta_property.install_property (make_attribute (m_meta_property, "Dependent")); m_meta_property.install_property (make_attribute (m_meta_property, "Transient")); m_meta_property.install_property (make_attribute (m_meta_property, "Hidden")); m_meta_property.install_property (make_attribute (m_meta_property, "GetObservable")); m_meta_property.install_property (make_attribute (m_meta_property, "SetObservable")); m_meta_property.install_property (make_attribute (m_meta_property, "GetMethod")); m_meta_property.install_property (make_attribute (m_meta_property, "SetMethod")); m_meta_property.install_property (make_attribute (m_meta_property, "DefiningClass")); m_meta_property.install_property (make_property (m_meta_property, "DefaultValue", make_fcn_handle (property_get_defaultvalue, "meta.property>get.DefaultValue"), "public", Matrix (), "private")); m_meta_property.install_property (make_attribute (m_meta_property, "HasDefault")); // meta.property events // FIXME: add events // handle methods tmp_handle.install_method (make_method (tmp_handle, "delete", handle_delete)); // meta.package properties m_meta_package.install_property (make_attribute (m_meta_package, "Name")); m_meta_package.install_property (make_property (m_meta_package, "ContainingPackage")); m_meta_package.install_property (make_property (m_meta_package, "ClassList", make_fcn_handle (package_get_classes, "meta.package>get.ClassList"), "public", Matrix (), "private")); m_meta_package.install_property (make_property (m_meta_package, "Classes", make_fcn_handle (package_get_classes, "meta.package>get.Classes"), "public", Matrix (), "private")); m_meta_package.install_property (make_property (m_meta_package, "FunctionList", make_fcn_handle (package_get_functions, "meta.package>get.FunctionList"), "public", Matrix (), "private")); m_meta_package.install_property (make_property (m_meta_package, "Functions", make_fcn_handle (package_get_functions, "meta.package>get.Functions"), "public", Matrix (), "private")); m_meta_package.install_property (make_property (m_meta_package, "PackageList", make_fcn_handle (package_get_packages, "meta.package>get.PackageList"), "public", Matrix (), "private")); m_meta_package.install_property (make_property (m_meta_package, "Packages", make_fcn_handle (package_get_packages, "meta.package>get.Packages"), "public", Matrix (), "private")); m_meta_package.install_method (make_method (m_meta_package, "fromName", package_fromName, "public", true)); m_meta_package.install_method (make_method (m_meta_package, "getAllPackages", package_getAllPackages, "public", true)); // create "meta" package cdef_package package_meta = m_meta = make_package ("meta"); package_meta.install_class (m_meta_class, "class"); package_meta.install_class (m_meta_property, "property"); package_meta.install_class (m_meta_method, "method"); package_meta.install_class (m_meta_package, "package"); package_meta.install_class (tmp_meta_event, "event"); package_meta.install_class (tmp_meta_dynproperty, "dynproperty"); symbol_table& symtab = m_interpreter.get_symbol_table (); // install built-in classes into the symbol table symtab.install_built_in_function ("meta.class", m_meta_class.get_constructor_function ()); symtab.install_built_in_function ("meta.method", m_meta_method.get_constructor_function ()); symtab.install_built_in_function ("meta.property", m_meta_property.get_constructor_function ()); symtab.install_built_in_function ("meta.package", m_meta_package.get_constructor_function ()); // FIXME: meta.event and meta.dynproperty are not implemented // and should not be installed into symbol table. // symtab.install_built_in_function // ("meta.event", tmp_meta_event.get_constructor_function ()); // symtab.install_built_in_function // ("meta.dynproperty", tmp_meta_dynproperty.get_constructor_function ()); } cdef_class cdef_manager::find_class (const std::string& name, bool error_if_not_found, bool load_if_not_found) { auto it = m_all_classes.find (name); if (it == m_all_classes.end ()) { if (load_if_not_found) { octave_value ov_cls; std::size_t pos = name.rfind ('.'); if (pos == std::string::npos) ov_cls = m_interpreter.find (name); else { std::string pack_name = name.substr (0, pos); cdef_package pack = find_package (pack_name, false, true); if (pack.ok ()) ov_cls = pack.find (name.substr (pos+1)); } if (ov_cls.is_defined ()) it = m_all_classes.find (name); } } if (it == m_all_classes.end ()) { if (error_if_not_found) error ("class not found: %s", name.c_str ()); } else { cdef_class cls = it->second; if (! cls.is_builtin ()) cls = lookup_class (cls); if (cls.ok ()) return cls; else m_all_classes.erase (it); } return cdef_class (); } octave_value cdef_manager::find_method_symbol (const std::string& method_name, const std::string& class_name) { cdef_class cls = find_class (class_name, false, false); if (cls.ok ()) { cdef_method meth = cls.find_method (method_name); if (meth.ok ()) return octave_value (new octave_classdef_meta (meth)); } return octave_value (); } cdef_package cdef_manager::find_package (const std::string& name, bool error_if_not_found, bool load_if_not_found) { cdef_package retval; std::map<std::string, cdef_package>::const_iterator it = m_all_packages.find (name); if (it != m_all_packages.end ()) { retval = it->second; if (! retval.ok ()) error ("invalid package '%s'", name.c_str ()); } else { load_path& lp = m_interpreter.get_load_path (); if (load_if_not_found && lp.find_package (name)) { std::size_t pos = name.rfind ('.'); if (pos == std::string::npos) retval = make_package (name, ""); else { std::string parent_name = name.substr (0, pos); retval = make_package (name, parent_name); } } else if (error_if_not_found) error ("unknown package '%s'", name.c_str ()); } return retval; } octave_value cdef_manager::find_package_symbol (const std::string& pack_name) { cdef_package pack = find_package (pack_name, false); if (pack.ok ()) return octave_value (new octave_classdef_meta (pack)); return octave_value (); } cdef_class cdef_manager::make_class (const std::string& name, const std::list<cdef_class>& super_list) { cdef_class cls (name, super_list); cls.set_class (meta_class ()); cls.put ("Abstract", false); cls.put ("ConstructOnLoad", false); cls.put ("ContainingPackage", Matrix ()); cls.put ("Description", ""); cls.put ("DetailedDescription", ""); cls.put ("Events", Cell ()); cls.put ("Hidden", false); cls.put ("InferiorClasses", Cell ()); cls.put ("Methods", Cell ()); cls.put ("Properties", Cell ()); cls.put ("Sealed", false); if (name == "handle") { cls.put ("HandleCompatible", true); cls.mark_as_handle_class (); } else if (super_list.empty ()) { cls.put ("HandleCompatible", false); } else { bool all_handle_compatible = true; bool has_handle_class = false; for (const auto& cl : super_list) { all_handle_compatible = all_handle_compatible && cl.get ("HandleCompatible").bool_value (); has_handle_class = has_handle_class || cl.is_handle_class (); } if (has_handle_class && ! all_handle_compatible) error ("%s: cannot mix handle and non-HandleCompatible classes", name.c_str ()); cls.put ("HandleCompatible", all_handle_compatible); if (has_handle_class) cls.mark_as_handle_class (); } if (! name.empty ()) register_class (cls); return cls; } cdef_class cdef_manager::make_class (const std::string& name, const cdef_class& super) { return make_class (name, std::list<cdef_class> (1, super)); } cdef_class cdef_manager::make_meta_class (const std::string& name, const cdef_class& super) { cdef_class cls = make_class (name, super); cls.put ("Sealed", true); cls.mark_as_meta_class (); return cls; } cdef_property cdef_manager::make_property (const cdef_class& cls, const std::string& name, const octave_value& get_method, const std::string& get_access, const octave_value& set_method, const std::string& set_access) { cdef_property prop (name); prop.set_class (meta_property ()); prop.put ("Description", ""); prop.put ("DetailedDescription", ""); prop.put ("Abstract", false); prop.put ("Constant", false); prop.put ("GetAccess", get_access); prop.put ("SetAccess", set_access); prop.put ("Dependent", false); prop.put ("Transient", false); prop.put ("Hidden", false); prop.put ("GetObservable", false); prop.put ("SetObservable", false); prop.put ("GetMethod", get_method); prop.put ("SetMethod", set_method); prop.put ("DefiningClass", to_ov (cls)); prop.put ("DefaultValue", octave_value ()); prop.put ("HasDefault", false); std::string class_name = cls.get_name (); if (! get_method.isempty ()) make_function_of_class (class_name, get_method); if (! set_method.isempty ()) make_function_of_class (class_name, set_method); return prop; } cdef_property cdef_manager::make_attribute (const cdef_class& cls, const std::string& name) { return make_property (cls, name, Matrix (), "public", Matrix (), "private"); } cdef_method cdef_manager::make_method (const cdef_class& cls, const std::string& name, const octave_value& fcn, const std::string& m_access, bool is_static) { cdef_method meth (name); meth.set_class (meta_method ()); meth.put ("Abstract", false); meth.put ("Access", m_access); meth.put ("DefiningClass", to_ov (cls)); meth.put ("Description", ""); meth.put ("DetailedDescription", ""); meth.put ("Hidden", false); meth.put ("Sealed", true); meth.put ("Static", is_static); if (fcn.is_defined ()) make_function_of_class (cls, fcn); meth.set_function (fcn); if (is_dummy_method (fcn)) meth.mark_as_external (cls.get_name ()); return meth; } cdef_method cdef_manager::make_method (const cdef_class& cls, const std::string& name, octave_builtin::fcn ff, const std::string& m_access, bool is_static) { octave_value fcn (new octave_builtin (ff, name)); return make_method (cls, name, fcn, m_access, is_static); } cdef_method cdef_manager::make_method (const cdef_class& cls, const std::string& name, octave_builtin::meth mm, const std::string& m_access, bool is_static) { octave_value fcn (new octave_builtin (mm, name)); return make_method (cls, name, fcn, m_access, is_static); } cdef_package cdef_manager::make_package (const std::string& nm, const std::string& parent) { cdef_package pack (nm); pack.set_class (meta_package ()); if (parent.empty ()) pack.put ("ContainingPackage", Matrix ()); else pack.put ("ContainingPackage", to_ov (find_package (parent))); if (! nm.empty ()) register_package (pack); return pack; } octave_value cdef_manager::find_method (const std::string& class_name, const std::string& name) const { cdef_class cls = lookup_class (class_name); return cls.get_method (name); } }