Mercurial > octave
view libinterp/octave-value/cdef-class.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
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 <algorithm> #include <iomanip> #include "cdef-class.h" #include "cdef-manager.h" #include "cdef-method.h" #include "cdef-package.h" #include "cdef-property.h" #include "cdef-utils.h" #include "errwarn.h" #include "interpreter-private.h" #include "interpreter.h" #include "load-path.h" #include "ov-builtin.h" #include "ov-classdef.h" #include "ov-fcn-handle.h" #include "ov-usr-fcn.h" #include "parse.h" #include "pt-assign.h" #include "pt-classdef.h" #include "pt-eval.h" #include "pt-idx.h" #include "pt-misc.h" #include "pt-stmt.h" #include "pt-walk.h" #include "unwind-prot.h" // Define to 1 to enable debugging statements. #define DEBUG_TRACE 0 #if DEBUG_TRACE # include <iostream> #endif OCTAVE_BEGIN_NAMESPACE(octave) static octave_value make_fcn_handle (const octave_value& fcn, const std::string& meth_name, const std::string& class_name) { octave_value retval; if (fcn.is_defined ()) { // FCN_HANDLE: METHOD octave_fcn_handle *fh = new octave_fcn_handle (fcn, class_name, meth_name); retval = octave_value (fh); } return retval; } cdef_class::cdef_class_rep::cdef_class_rep (const std::list<cdef_class>& superclasses) : cdef_meta_object_rep (), m_member_count (0), m_handle_class (false), m_meta (false) { put ("SuperClasses", to_ov (superclasses)); m_implicit_ctor_list = superclasses; } cdef_method cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local) { auto it = m_method_map.find (nm); if (it == m_method_map.end ()) { // FIXME: look into class directory } else { cdef_method& meth = it->second; // FIXME: check if method reload needed if (meth.ok ()) return meth; } if (! local) { // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); cdef_method meth = cls.find_method (nm); if (meth.ok ()) return meth; } } return cdef_method (); } class ctor_analyzer : public tree_walker { public: ctor_analyzer (void) = delete; ctor_analyzer (const std::string& ctor, const std::string& obj) : tree_walker (), m_who (ctor), m_obj_name (obj) { } ctor_analyzer (const ctor_analyzer&) = delete; ctor_analyzer& operator = (const ctor_analyzer&) = delete; ~ctor_analyzer (void) = default; void visit_statement (tree_statement& t) { if (t.is_expression ()) t.expression ()->accept (*this); } void visit_simple_assignment (tree_simple_assignment& t) { t.right_hand_side ()->accept (*this); } void visit_multi_assignment (tree_multi_assignment& t) { t.right_hand_side ()->accept (*this); } void visit_index_expression (tree_index_expression& t) { t.expression ()->accept (*this); } std::list<cdef_class> get_constructor_list (void) const { return m_ctor_list; } // NO-OP void visit_anon_fcn_handle (tree_anon_fcn_handle&) { } void visit_argument_list (tree_argument_list&) { } void visit_binary_expression (tree_binary_expression&) { } void visit_break_command (tree_break_command&) { } void visit_colon_expression (tree_colon_expression&) { } void visit_continue_command (tree_continue_command&) { } void visit_decl_command (tree_decl_command&) { } void visit_decl_init_list (tree_decl_init_list&) { } void visit_decl_elt (tree_decl_elt&) { } void visit_simple_for_command (tree_simple_for_command&) { } void visit_complex_for_command (tree_complex_for_command&) { } void visit_octave_user_script (octave_user_script&) { } void visit_octave_user_function (octave_user_function&) { } void visit_function_def (tree_function_def&) { } void visit_identifier (tree_identifier&) { } void visit_if_clause (tree_if_clause&) { } void visit_if_command (tree_if_command&) { } void visit_if_command_list (tree_if_command_list&) { } void visit_switch_case (tree_switch_case&) { } void visit_switch_case_list (tree_switch_case_list&) { } void visit_switch_command (tree_switch_command&) { } void visit_matrix (tree_matrix&) { } void visit_cell (tree_cell&) { } void visit_no_op_command (tree_no_op_command&) { } void visit_constant (tree_constant&) { } void visit_fcn_handle (tree_fcn_handle&) { } void visit_parameter_list (tree_parameter_list&) { } void visit_postfix_expression (tree_postfix_expression&) { } void visit_prefix_expression (tree_prefix_expression&) { } void visit_return_command (tree_return_command&) { } void visit_try_catch_command (tree_try_catch_command&) { } void visit_unwind_protect_command (tree_unwind_protect_command&) { } void visit_while_command (tree_while_command&) { } void visit_do_until_command (tree_do_until_command&) { } void visit_superclass_ref (tree_superclass_ref& t) { if (t.method_name () == m_obj_name) { std::string class_name = t.class_name (); cdef_class cls = lookup_class (class_name, false); if (cls.ok ()) m_ctor_list.push_back (cls); } } private: // The name of the constructor being analyzed. std::string m_who; // The name of the first output argument of the constructor. std::string m_obj_name; // The list of superclass constructors that are explicitly called. std::list<cdef_class> m_ctor_list; }; void cdef_class::cdef_class_rep::install_method (const cdef_method& meth) { m_method_map[meth.get_name ()] = meth; m_member_count++; if (meth.is_constructor ()) { // Analyze the constructor code to determine what superclass // constructors are called explicitly. octave_value ov_fcn = meth.get_function (); if (ov_fcn.is_defined ()) { octave_user_function *uf = ov_fcn.user_function_value (true); if (uf) { tree_parameter_list *ret_list = uf->return_list (); tree_statement_list *body = uf->body (); if (! ret_list || ret_list->size () != 1) error ("%s: invalid constructor output arguments", meth.get_name ().c_str ()); std::string m_obj_name = ret_list->front ()->name (); ctor_analyzer a (meth.get_name (), m_obj_name); body->accept (a); std::list<cdef_class> explicit_ctor_list = a.get_constructor_list (); for (const auto& cdef_cls : explicit_ctor_list) { #if DEBUG_TRACE std::cerr << "explicit superclass constructor: " << cdef_cls.get_name () << std::endl; #endif m_implicit_ctor_list.remove (cdef_cls); } } } } } void cdef_class::cdef_class_rep::load_all_methods (void) { // FIXME: re-scan class directory } Cell cdef_class::cdef_class_rep::get_methods (bool include_ctor) { std::map<std::string, cdef_method> meths; find_methods (meths, false, include_ctor); Cell c (meths.size (), 1); int idx = 0; for (const auto& nm_mthd : meths) c(idx++, 0) = to_ov (nm_mthd.second); return c; } std::map<std::string, cdef_method> cdef_class::cdef_class_rep::get_method_map (bool only_inherited, bool include_ctor) { std::map<std::string, cdef_method> methods; find_methods (methods, only_inherited, include_ctor); return methods; } void cdef_class::cdef_class_rep::find_methods (std::map<std::string, cdef_method>& meths, bool only_inherited, bool include_ctor) { load_all_methods (); method_const_iterator it; for (it = m_method_map.begin (); it != m_method_map.end (); ++it) { if (include_ctor || ! it->second.is_constructor ()) { std::string nm = it->second.get_name (); if (meths.find (nm) == meths.end ()) { if (only_inherited) { octave_value acc = it->second.get ("Access"); if (! acc.is_string () || acc.string_value () == "private") continue; } meths[nm] = it->second; } } } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); cls.get_rep ()->find_methods (meths, true, false); } } cdef_property cdef_class::cdef_class_rep::find_property (const std::string& nm) { auto it = m_property_map.find (nm); if (it != m_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)); 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) { m_property_map[prop.get_name ()] = prop; m_member_count++; } Cell cdef_class::cdef_class_rep::get_properties (int mode) { std::map<std::string, cdef_property> props; props = get_property_map (mode); Cell c (props.size (), 1); int idx = 0; for (const auto& pname_prop : props) c(idx++, 0) = to_ov (pname_prop.second); return c; } std::map<std::string, cdef_property> cdef_class::cdef_class_rep::get_property_map (int mode) { std::map<std::string, cdef_property> props; find_properties (props, mode); return props; } void cdef_class::cdef_class_rep::find_properties (std::map<std::string, cdef_property>& props, int mode) { property_const_iterator it; for (it = m_property_map.begin (); it != m_property_map.end (); ++it) { std::string nm = it->second.get_name (); if (props.find (nm) == props.end ()) { if (mode == property_inherited) { octave_value acc = it->second.get ("GetAccess"); if (! acc.is_string () || acc.string_value () == "private") continue; } props[nm] = it->second; } } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); cls.get_rep ()->find_properties (props, (mode == property_all ? property_all : property_inherited)); } } void cdef_class::cdef_class_rep::find_names (std::set<std::string>& names, bool all) { load_all_methods (); for (const auto& cls_fnmap : m_method_map) { if (! cls_fnmap.second.is_constructor ()) { std::string nm = cls_fnmap.second.get_name (); if (! all) { octave_value acc = cls_fnmap.second.get ("Access"); if (! acc.is_string() || acc.string_value () != "public") continue; } names.insert (nm); } } for (const auto& pname_prop : m_property_map) { std::string nm = pname_prop.second.get_name (); if (! all) { octave_value acc = pname_prop.second.get ("GetAccess"); if (! acc.is_string() || acc.string_value () != "public") continue; } names.insert (nm); } // Look into superclasses Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); cls.get_rep ()->find_names (names, all); } } string_vector cdef_class::cdef_class_rep::get_names (void) { std::set<std::string> names; find_names (names, false); string_vector v (names); return v.sort (true); } void cdef_class::cdef_class_rep::delete_object (const cdef_object& obj) { cdef_method dtor = find_method ("delete"); // FIXME: would it be better to tell find_method above to not find // overloaded functions? if (dtor.ok () && dtor.is_defined_in_class (get_name ())) dtor.execute (obj, octave_value_list (), 0, true, "destructor"); // FIXME: should we destroy corresponding properties here? // Call "delete" in super classes Cell super_classes = get ("SuperClasses").cell_value (); for (int i = 0; i < super_classes.numel (); i++) { cdef_class cls = lookup_class (super_classes(i)); if (cls.get_name () != "handle") cls.delete_object (obj); } } octave_value_list cdef_class::cdef_class_rep::meta_subsref (const std::string& type, const std::list<octave_value_list>& idx, int nargout) { std::size_t skip = 1; octave_value_list retval; switch (type[0]) { case '(': // Constructor call #if DEBUG_TRACE std::cerr << "constructor" << std::endl; #endif retval(0) = construct (idx.front ()); break; case '.': { // Static method, constant (or property?) #if DEBUG_TRACE std::cerr << "static method/property" << std::endl; #endif if (idx.front ().length () != 1) error ("invalid meta.class indexing"); std::string nm = idx.front ()( 0).xstring_value ("invalid meta.class indexing, expected a method or property name"); cdef_method meth = find_method (nm); if (meth.ok ()) { if (! meth.is_static ()) error ("method '%s' is not static", nm.c_str ()); octave_value_list args; if (type.length () > 1 && idx.size () > 1 && type[1] == '(') { args = *(++(idx.begin ())); skip++; } retval = meth.execute (args, (type.length () > skip ? 1 : nargout), true, "meta.class"); } else { cdef_property prop = find_property (nm); if (! prop.ok ()) error ("no such method or property '%s'", nm.c_str ()); if (! prop.is_constant ()) error ("property '%s' is not constant", nm.c_str ()); retval(0) = prop.get_value (true, "meta.class"); } } break; default: error ("invalid meta.class indexing"); break; } if (type.length () > skip && idx.size () > skip && ! retval.empty ()) retval = retval(0).next_subsref (nargout, type, idx, skip); return retval; } void cdef_class::cdef_class_rep::meta_release (void) { cdef_manager& cdm = __get_cdef_manager__ (); cdm.unregister_class (wrap ()); } void cdef_class::cdef_class_rep::initialize_object (cdef_object& obj) { // Populate the object with default property values std::list<cdef_class> super_classes = lookup_classes (get ("SuperClasses").cell_value ()); for (auto& cls : super_classes) cls.initialize_object (obj); for (const auto& pname_prop : m_property_map) { if (! pname_prop.second.get ("Dependent").bool_value ()) { octave_value pvalue = pname_prop.second.get ("DefaultValue"); if (pvalue.is_defined ()) obj.put (pname_prop.first, pvalue); else obj.put (pname_prop.first, octave_value (Matrix ())); } } m_count++; obj.mark_for_construction (cdef_class (this)); } void cdef_class::cdef_class_rep::run_constructor (cdef_object& obj, const octave_value_list& args) { octave_value_list empty_args; for (const auto& cls : m_implicit_ctor_list) { cdef_class supcls = lookup_class (cls); supcls.run_constructor (obj, empty_args); } std::string cls_name = get_name (); std::string ctor_name = get_base_name (cls_name); cdef_method ctor = find_method (ctor_name); if (ctor.ok ()) { octave_value_list ctor_args (args); octave_value_list ctor_retval; ctor_args.prepend (to_ov (obj)); ctor_retval = ctor.execute (ctor_args, 1, true, "constructor"); if (ctor_retval.length () != 1) error ("%s: invalid number of output arguments for classdef constructor", ctor_name.c_str ()); obj = to_cdef (ctor_retval(0)); } obj.mark_as_constructed (wrap ()); } octave_value cdef_class::cdef_class_rep::get_method (const std::string& name) const { auto p = m_method_map.find (name); if (p == m_method_map.end ()) return octave_value (); return p->second.get_function (); } octave_value cdef_class::cdef_class_rep::construct (const octave_value_list& args) { cdef_object obj = construct_object (args); if (obj.ok ()) return to_ov (obj); return octave_value (); } cdef_object cdef_class::cdef_class_rep::construct_object (const octave_value_list& args) { if (is_abstract ()) error ("cannot instantiate object for abstract class '%s'", get_name ().c_str ()); cdef_object obj; if (is_meta_class ()) { // This code path is only used to create empty meta objects // as filler for the empty values within a meta object array. cdef_class this_cls = wrap (); static cdef_object empty_class; cdef_manager& cdm = __get_cdef_manager__ (); if (this_cls == cdm.meta_class ()) { if (! empty_class.ok ()) empty_class = cdm.make_class ("", std::list<cdef_class> ()); obj = empty_class; } else if (this_cls == cdm.meta_property ()) { static cdef_property empty_property; if (! empty_class.ok ()) empty_class = cdm.make_class ("", std::list<cdef_class> ()); if (! empty_property.ok ()) empty_property = cdm.make_property (empty_class, ""); obj = empty_property; } else if (this_cls == cdm.meta_method ()) { static cdef_method empty_method; if (! empty_class.ok ()) empty_class = cdm.make_class ("", std::list<cdef_class> ()); if (! empty_method.ok ()) empty_method = cdm.make_method (empty_class, "", octave_value ()); obj = empty_method; } else if (this_cls == cdm.meta_package ()) { static cdef_package empty_package; if (! empty_package.ok ()) empty_package = cdm.make_package (""); obj = empty_package; } else panic_impossible (); return obj; } else { if (is_handle_class ()) obj = cdef_object (new handle_cdef_object ()); else obj = cdef_object (new value_cdef_object ()); obj.set_class (wrap ()); initialize_object (obj); run_constructor (obj, args); return obj; } return cdef_object (); } static octave_value compute_attribute_value (tree_evaluator& tw, tree_classdef_attribute *t) { tree_expression *expr = t->expression (); if (expr) { if (expr->is_identifier ()) { std::string s = expr->name (); if (s == "public") return std::string ("public"); else if (s == "protected") return std::string ("protected"); else if (s == "private") return std::string ("private"); } return expr->evaluate (tw); } else return octave_value (true); } template <typename T> static std::string attribute_value_to_string (T *t, octave_value v) { if (v.is_string ()) return v.string_value (); else if (t->expression ()) return t->expression ()->original_text (); else return "true"; } cdef_class cdef_class::make_meta_class (interpreter& interp, tree_classdef *t, bool is_at_folder) { cdef_class retval; // Class creation std::string class_name = t->ident ()->name (); std::string full_class_name = class_name; if (! t->package_name ().empty ()) full_class_name = t->package_name () + '.' + full_class_name; #if DEBUG_TRACE std::cerr << "class: " << full_class_name << std::endl; #endif // Push a dummy scope frame on the call stack that corresponds to // the scope that was used when parsing classdef object. Without // this, we may pick up stray values from the current scope when // evaluating expressions found in things like attribute lists. tree_evaluator& tw = interp.get_evaluator (); tw.push_dummy_scope (full_class_name); unwind_action pop_scope (&tree_evaluator::pop_scope, &tw); std::list<cdef_class> slist; if (t->superclass_list ()) { for (auto& scls : (*t->superclass_list ())) { std::string sclass_name = (scls)->class_name (); #if DEBUG_TRACE std::cerr << "superclass: " << sclass_name << std::endl; #endif cdef_class sclass = lookup_class (sclass_name); if (sclass.get ("Sealed").bool_value ()) error ("'%s' cannot inherit from '%s', because it is sealed", full_class_name.c_str (), sclass_name.c_str ()); slist.push_back (sclass); } } cdef_manager& cdm = __get_cdef_manager__ (); retval = cdm.make_class (full_class_name, slist); retval.doc_string (t->doc_string ()); retval.file_name (t->file_name ()); // Package owning this class if (! t->package_name ().empty ()) { cdef_package pack = cdm.find_package (t->package_name ()); if (pack.ok ()) retval.put ("ContainingPackage", to_ov (pack)); } // FIXME: instead of attaching attributes here, pass them to // cdef_manager::make_method. The classdef manager contains a meta // object with a list of all valid properties that can be used to // validate the attribute list (see bug #60593). // Class attributes if (t->attribute_list ()) { for (const auto& attr : (*t->attribute_list ())) { std::string aname = attr->ident ()->name (); octave_value avalue = compute_attribute_value (tw, attr); #if DEBUG_TRACE std::cerr << "class attribute: " << aname << " = " << attribute_value_to_string (attr, avalue) << std::endl; #endif retval.put (aname, avalue); } } tree_classdef_body *b = t->body (); if (b) { // Keep track of the get/set accessor methods. They will be used // later on when creating properties. std::map<std::string, octave_value> get_methods; std::map<std::string, octave_value> set_methods; // Method blocks std::list<tree_classdef_methods_block *> mb_list = b->methods_list (); load_path& lp = interp.get_load_path (); for (auto& mb_p : mb_list) { std::map<std::string, octave_value> amap; #if DEBUG_TRACE std::cerr << "method block" << std::endl; #endif // Method attributes if (mb_p->attribute_list ()) { for (auto& attr_p : *mb_p->attribute_list ()) { std::string aname = attr_p->ident ()->name (); octave_value avalue = compute_attribute_value (tw, attr_p); #if DEBUG_TRACE std::cerr << "method attribute: " << aname << " = " << attribute_value_to_string (attr_p, avalue) << std::endl; #endif amap[aname] = avalue; } } // Methods if (mb_p->element_list ()) { for (auto& mtd : *mb_p->element_list ()) { std::string mname = mtd.function_value ()->name (); std::string mprefix = mname.substr (0, 4); if (mprefix == "get.") get_methods[mname.substr (4)] = make_fcn_handle (mtd, mname, full_class_name); else if (mprefix == "set.") set_methods[mname.substr (4)] = make_fcn_handle (mtd, mname, full_class_name); else { cdef_method meth = cdm.make_method (retval, mname, mtd); #if DEBUG_TRACE std::cerr << (mname == class_name ? "constructor" : "method") << ": " << mname << std::endl; #endif // FIXME: instead of attaching attributes here, // pass them to cdef_manager::make_method. The // classdef manager contains a meta object with // a list of all valid properties that can be // used to validate the attribute list (see bug // #60593). for (auto& attrnm_val : amap) meth.put (attrnm_val.first, attrnm_val.second); retval.install_method (meth); } } } } if (is_at_folder) { // Look for all external methods visible on octave path at the // time of loading of the class. // // FIXME: This is an "extension" to Matlab behavior, which only // looks in the @-folder containing the original classdef file. // However, this is easier to implement it that way at the moment. std::list<std::string> external_methods = lp.methods (full_class_name); for (const auto& mtdnm : external_methods) { // FIXME: should we issue a warning if the method is already // defined in the classdef file? if (mtdnm != class_name && ! retval.find_method (mtdnm, true).ok ()) { // Create a dummy method that is used until the actual // method is loaded. octave_user_function *fcn = new octave_user_function (); fcn->stash_function_name (mtdnm); cdef_method meth = cdm.make_method (retval, mtdnm, octave_value (fcn)); retval.install_method (meth); } } } // Property blocks // FIXME: default property expression should be able to call static // methods of the class being constructed. A restricted // CLASSNAME symbol should be added to the scope before // evaluating default value expressions. std::list<tree_classdef_properties_block *> pb_list = b->properties_list (); for (auto& pb_p : pb_list) { std::map<std::string, octave_value> amap; #if DEBUG_TRACE std::cerr << "property block" << std::endl; #endif // Property attributes if (pb_p->attribute_list ()) { for (auto& attr_p : *pb_p->attribute_list ()) { std::string aname = attr_p->ident ()->name (); octave_value avalue = compute_attribute_value (tw, attr_p); #if DEBUG_TRACE std::cerr << "property attribute: " << aname << " = " << attribute_value_to_string (attr_p, avalue) << std::endl; #endif if (aname == "Access") { amap["GetAccess"] = avalue; amap["SetAccess"] = avalue; } else amap[aname] = avalue; } } // Properties if (pb_p->element_list ()) { for (auto& prop_p : *pb_p->element_list ()) { std::string prop_name = prop_p->ident ()->name (); cdef_property prop = cdm.make_property (retval, prop_name); #if DEBUG_TRACE std::cerr << "property: " << prop_p->ident ()->name () << std::endl; #endif tree_expression *expr = prop_p->expression (); if (expr) { octave_value pvalue = expr->evaluate (tw); #if DEBUG_TRACE std::cerr << "property default: " << attribute_value_to_string (prop_p, pvalue) << std::endl; #endif prop.put ("DefaultValue", pvalue); } // FIXME: instead of attaching attributes here, pass // them to cdef_manager::make_property. The // classdef manager contains a meta object with a // list of all valid properties that can be used to // validate the attribute list (see bug #60593). // Install property attributes. This is done before // assigning the property accessors so we can do validation // by using cdef_property methods. for (auto& attrnm_val : amap) prop.put (attrnm_val.first, attrnm_val.second); // Install property access methods, if any. Remove the // accessor methods from the temporary storage map, so we // can detect which ones are invalid and do not correspond // to a defined property. auto git = get_methods.find (prop_name); if (git != get_methods.end ()) { make_function_of_class (retval, git->second); prop.put ("GetMethod", git->second); get_methods.erase (git); } auto sit = set_methods.find (prop_name); if (sit != set_methods.end ()) { make_function_of_class (retval, sit->second); prop.put ("SetMethod", sit->second); set_methods.erase (sit); } retval.install_property (prop); } } } } return retval; } octave_value cdef_class::get_method_function (const std::string& /* nm */) { return octave_value (new octave_classdef_meta (*this)); } OCTAVE_END_NAMESPACE(octave)