1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 2012-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if ! defined (octave_cdef_class_h) 27 #define octave_cdef_class_h 1 28 29 #include "octave-config.h" 30 31 #include <map> 32 #include <set> 33 #include <string> 34 35 #include "oct-refcount.h" 36 37 #include "cdef-method.h" 38 #include "cdef-object.h" 39 #include "cdef-package.h" 40 #include "cdef-property.h" 41 #include "error.h" 42 #include "ov.h" 43 #include "ovl.h" 44 45 namespace octave 46 { 47 class interpreter; 48 class tree_classdef; 49 50 class 51 cdef_class : public cdef_meta_object 52 { 53 private: 54 55 class 56 cdef_class_rep : public cdef_meta_object_rep 57 { 58 public: cdef_class_rep(void)59 cdef_class_rep (void) 60 : cdef_meta_object_rep (), member_count (0), handle_class (false), 61 meta (false) 62 { } 63 64 cdef_class_rep (const std::list<cdef_class>& superclasses); 65 66 cdef_class_rep& operator = (const cdef_class_rep&) = delete; 67 68 ~cdef_class_rep (void) = default; 69 copy(void)70 cdef_object_rep * copy (void) const { return new cdef_class_rep (*this); } 71 is_class(void)72 bool is_class (void) const { return true; } 73 get_name(void)74 std::string get_name (void) const 75 { return get ("Name").string_value (); } 76 set_name(const std::string & nm)77 void set_name (const std::string& nm) { put ("Name", nm); } 78 is_abstract(void)79 bool is_abstract (void) const { return get ("Abstract").bool_value (); } 80 is_sealed(void)81 bool is_sealed (void) const { return get ("Sealed").bool_value (); } 82 83 cdef_method find_method (const std::string& nm, bool local = false); 84 85 void install_method (const cdef_method& meth); 86 87 Cell get_methods (bool include_ctor); 88 89 std::map<std::string, cdef_method> 90 get_method_map (bool only_inherited, bool include_ctor); 91 92 cdef_property find_property (const std::string& nm); 93 94 void install_property (const cdef_property& prop); 95 96 Cell get_properties (int mode); 97 98 std::map<std::string, cdef_property> get_property_map (int mode); 99 100 string_vector get_names (void); 101 set_directory(const std::string & dir)102 void set_directory (const std::string& dir) { directory = dir; } 103 get_directory(void)104 std::string get_directory (void) const { return directory; } 105 106 void delete_object (const cdef_object& obj); 107 108 octave_value_list 109 meta_subsref (const std::string& type, 110 const std::list<octave_value_list>& idx, int nargout); 111 112 void meta_release (void); 113 meta_accepts_postfix_index(char type)114 bool meta_accepts_postfix_index (char type) const 115 { 116 return (type == '(' || type == '.'); 117 } 118 119 octave_value get_method (const std::string& name) const; 120 121 octave_value construct (const octave_value_list& args); 122 123 cdef_object construct_object (const octave_value_list& args); 124 125 void initialize_object (cdef_object& obj); 126 127 void run_constructor (cdef_object& obj, const octave_value_list& args); 128 mark_as_handle_class(void)129 void mark_as_handle_class (void) { handle_class = true; } 130 is_handle_class(void)131 bool is_handle_class (void) const { return handle_class; } 132 static_count(void)133 octave_idx_type static_count (void) const { return member_count; } 134 destroy(void)135 void destroy (void) 136 { 137 if (member_count) 138 { 139 m_count++; 140 cdef_class lock (this); 141 142 member_count = 0; 143 method_map.clear (); 144 property_map.clear (); 145 } 146 else 147 delete this; 148 } 149 mark_as_meta_class(void)150 void mark_as_meta_class (void) { meta = true; } 151 is_meta_class(void)152 bool is_meta_class (void) const { return meta; } 153 doc_string(const std::string & txt)154 void doc_string (const std::string& txt) { m_doc_string = txt; } 155 doc_string(void)156 std::string doc_string (void) const { return m_doc_string; } 157 158 private: 159 160 void load_all_methods (void); 161 162 void find_names (std::set<std::string>& names, bool all); 163 164 void find_properties (std::map<std::string,cdef_property>& props, 165 int mode = 0); 166 167 void find_methods (std::map<std::string, cdef_method>& meths, 168 bool only_inherited, bool include_ctor = false); 169 wrap(void)170 cdef_class wrap (void) 171 { 172 m_count++; 173 return cdef_class (this); 174 } 175 176 // The @-directory were this class is loaded from. 177 // (not used yet) 178 179 std::string directory; 180 181 std::string m_doc_string; 182 183 // The methods defined by this class. 184 185 std::map<std::string,cdef_method> method_map; 186 187 // The properties defined by this class. 188 189 std::map<std::string,cdef_property> property_map; 190 191 // The number of members in this class (methods, properties...) 192 193 octave_idx_type member_count; 194 195 // TRUE if this class is a handle class. A class is a handle 196 // class when the abstract "handle" class is one of its superclasses. 197 198 bool handle_class; 199 200 // The list of super-class constructors that are called implicitly by the 201 // the classdef engine when creating an object. These constructors are not 202 // called explicitly by the class constructor. 203 204 std::list<cdef_class> implicit_ctor_list; 205 206 // TRUE if this class is a built-in meta class. 207 208 bool meta; 209 210 // Utility iterator typedefs. 211 212 typedef std::map<std::string,cdef_method>::iterator method_iterator; 213 typedef std::map<std::string,cdef_method>::const_iterator method_const_iterator; 214 typedef std::map<std::string,cdef_property>::iterator property_iterator; 215 typedef std::map<std::string,cdef_property>::const_iterator property_const_iterator; 216 217 cdef_class_rep (const cdef_class_rep& c) = default; 218 }; 219 220 public: 221 222 // Create an invalid class object. 223 cdef_class(void)224 cdef_class (void) : cdef_meta_object () { } 225 cdef_class(const std::string & nm,const std::list<cdef_class> & superclasses)226 cdef_class (const std::string& nm, const std::list<cdef_class>& superclasses) 227 : cdef_meta_object (new cdef_class_rep (superclasses)) 228 { 229 get_rep ()->set_name (nm); 230 } 231 cdef_class(const cdef_class & cls)232 cdef_class (const cdef_class& cls) : cdef_meta_object (cls) { } 233 cdef_class(const cdef_object & obj)234 cdef_class (const cdef_object& obj) 235 : cdef_meta_object (obj) 236 { 237 // This should never happen... 238 if (! is_class ()) 239 error ("internal error: invalid assignment from %s to meta.class object", 240 class_name ().c_str ()); 241 } 242 243 cdef_class& operator = (const cdef_class& cls) 244 { 245 cdef_object::operator = (cls); 246 247 return *this; 248 } 249 250 ~cdef_class (void) = default; 251 252 cdef_method find_method (const std::string& nm, bool local = false); 253 install_method(const cdef_method & meth)254 void install_method (const cdef_method& meth) 255 { 256 get_rep ()->install_method (meth); 257 } 258 259 Cell get_methods (bool include_ctor = false) 260 { 261 return get_rep ()->get_methods (include_ctor); 262 } 263 264 std::map<std::string, cdef_method> 265 get_method_map (bool only_inherited = false, bool include_ctor = false) 266 { 267 return get_rep ()->get_method_map (only_inherited, include_ctor); 268 } 269 270 cdef_property find_property (const std::string& nm); 271 install_property(const cdef_property & prop)272 void install_property (const cdef_property& prop) 273 { 274 get_rep ()->install_property (prop); 275 } 276 277 Cell get_properties (int mode = property_normal) 278 { 279 return get_rep ()->get_properties (mode); 280 } 281 282 std::map<std::string, cdef_property> 283 get_property_map (int mode = property_normal) 284 { 285 return get_rep ()->get_property_map (mode); 286 } 287 get_names(void)288 string_vector get_names (void) { return get_rep ()->get_names (); } 289 is_abstract(void)290 bool is_abstract (void) const { return get_rep ()->is_abstract (); } 291 is_sealed(void)292 bool is_sealed (void) const { return get_rep ()->is_sealed (); } 293 set_directory(const std::string & dir)294 void set_directory (const std::string& dir) 295 { 296 get_rep ()->set_directory (dir); 297 } 298 get_directory(void)299 std::string get_directory (void) const 300 { 301 return get_rep ()->get_directory (); 302 } 303 get_name(void)304 std::string get_name (void) const { return get_rep ()->get_name (); } 305 is_builtin(void)306 bool is_builtin (void) const { return get_directory ().empty (); } 307 delete_object(const cdef_object & obj)308 void delete_object (const cdef_object& obj) 309 { 310 get_rep ()->delete_object (obj); 311 } 312 313 //! Analyze the tree_classdef tree and transform it to a cdef_class 314 //! 315 //! <b>All attribute validation should occur here.</b> 316 //! 317 //! Classdef attribute values can be given in the form of 318 //! expressions. These expressions must be evaluated before 319 //! assigning them as attribute values. Evaluating them as they are 320 //! parsed causes trouble with possible recursion in the parser so we 321 //! do it here. For example 322 //! 323 //! @code 324 //! classdef recursion_class 325 //! methods (Access = ?recursion_class) 326 //! endmethods 327 //! endclassdef 328 //! @endcode 329 //! 330 //! will fail because each attempt to compute the metaclass of 331 //! recursion_class will cause recursion_class to be parsed again. 332 333 static cdef_class 334 make_meta_class (interpreter& interp, tree_classdef *t, 335 bool is_at_folder = false); 336 get_method(const std::string & nm)337 octave_value get_method (const std::string& nm) const 338 { 339 return get_rep ()->get_method (nm); 340 } 341 342 octave_value get_method_function (const std::string& nm); 343 get_constructor_function(void)344 octave_value get_constructor_function (void) 345 { 346 return get_method_function (get_name ()); 347 } 348 construct(const octave_value_list & args)349 octave_value construct (const octave_value_list& args) 350 { 351 return get_rep ()->construct (args); 352 } 353 construct_object(const octave_value_list & args)354 cdef_object construct_object (const octave_value_list& args) 355 { 356 return get_rep ()->construct_object (args); 357 } 358 initialize_object(cdef_object & obj)359 void initialize_object (cdef_object& obj) 360 { 361 get_rep ()->initialize_object (obj); 362 } 363 run_constructor(cdef_object & obj,const octave_value_list & args)364 void run_constructor (cdef_object& obj, const octave_value_list& args) 365 { 366 get_rep ()->run_constructor (obj, args); 367 } 368 mark_as_handle_class(void)369 void mark_as_handle_class (void) 370 { 371 get_rep ()->mark_as_handle_class (); 372 } 373 is_handle_class(void)374 bool is_handle_class (void) const 375 { 376 return get_rep ()->is_handle_class (); 377 } 378 mark_as_meta_class(void)379 void mark_as_meta_class (void) { get_rep ()->mark_as_meta_class (); } 380 is_meta_class(void)381 bool is_meta_class (void) const { return get_rep ()->is_meta_class (); } 382 doc_string(const std::string & txt)383 void doc_string (const std::string& txt) { get_rep ()->doc_string (txt); } 384 doc_string(void)385 std::string doc_string (void) const { return get_rep ()->doc_string (); } 386 387 public: 388 389 enum 390 { 391 property_normal, 392 property_inherited, 393 property_all 394 }; 395 396 private: 397 get_rep(void)398 cdef_class_rep * get_rep (void) 399 { 400 return dynamic_cast<cdef_class_rep *> (cdef_object::get_rep ()); 401 } 402 get_rep(void)403 const cdef_class_rep * get_rep (void) const 404 { 405 return dynamic_cast<const cdef_class_rep *> (cdef_object::get_rep ()); 406 } 407 408 friend bool operator == (const cdef_class&, const cdef_class&); 409 friend bool operator != (const cdef_class&, const cdef_class&); 410 friend bool operator < (const cdef_class&, const cdef_class&); 411 412 friend void install_classdef (interpreter& interp); 413 }; 414 415 inline bool 416 operator == (const cdef_class& clsa, const cdef_class& clsb) 417 { 418 // FIXME: is this really the right way to check class equality? 419 420 return (clsa.get_rep () == clsb.get_rep ()); 421 } 422 423 inline bool 424 operator != (const cdef_class& clsa, const cdef_class& clsb) 425 { 426 return ! (clsa == clsb); 427 } 428 429 // This is only to be able to use cdef_class as map keys. 430 431 inline bool 432 operator < (const cdef_class& clsa, const cdef_class& clsb) 433 { 434 return clsa.get_rep () < clsb.get_rep (); 435 } 436 437 inline cdef_method find_method(const std::string & nm,bool local)438 cdef_class::find_method (const std::string& nm, bool local) 439 { 440 return get_rep ()->find_method (nm, local); 441 } 442 443 inline cdef_property find_property(const std::string & nm)444 cdef_class::find_property (const std::string& nm) 445 { 446 return get_rep ()->find_property (nm); 447 } 448 } 449 450 #endif 451