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