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 (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include "cdef-manager.h"
31 #include "cdef-utils.h"
32 #include "interpreter.h"
33 #include "ov-classdef.h"
34 
35 namespace octave
36 {
37   static octave_value
make_fcn_handle(octave_builtin::fcn ff,const std::string & nm)38   make_fcn_handle (octave_builtin::fcn ff, const std::string& nm)
39   {
40     octave_value fcn (new octave_builtin (ff, nm));
41 
42     return octave_value (new octave_fcn_handle (fcn));
43   }
44 
45   static octave_value_list
class_get_properties(const octave_value_list & args,int)46   class_get_properties (const octave_value_list& args, int /* nargout */)
47   {
48     octave_value_list retval;
49 
50     if (args.length () == 1 && args(0).type_name () == "object")
51       {
52         cdef_class cls (to_cdef (args(0)));
53 
54         retval(0) = cls.get_properties ();
55       }
56 
57     return retval;
58   }
59 
60   static octave_value_list
class_get_methods(const octave_value_list & args,int)61   class_get_methods (const octave_value_list& args, int /* nargout */)
62   {
63     octave_value_list retval;
64 
65     if (args.length () == 1 && args(0).type_name () == "object")
66       {
67         cdef_class cls (to_cdef (args(0)));
68 
69         retval(0) = cls.get_methods ();
70       }
71 
72     return retval;
73   }
74 
75   static octave_value_list
class_get_superclasses(const octave_value_list & args,int)76   class_get_superclasses (const octave_value_list& args, int /* nargout */)
77   {
78     octave_value_list retval;
79 
80     if (args.length () == 1 && args(0).type_name () == "object"
81         && args(0).class_name () == "meta.class")
82       {
83         cdef_class cls (to_cdef (args(0)));
84 
85         Cell classes = cls.get ("SuperClasses").cell_value ();
86 
87         retval(0) = to_ov (lookup_classes (classes));
88       }
89 
90     return retval;
91   }
92 
93   static octave_value_list
class_get_inferiorclasses(const octave_value_list & args,int)94   class_get_inferiorclasses (const octave_value_list& args, int /* nargout */)
95   {
96     octave_value_list retval;
97 
98     if (args.length () == 1 && args(0).type_name () == "object"
99         && args(0).class_name () == "meta.class")
100       {
101         cdef_class cls (to_cdef (args(0)));
102 
103         Cell classes = cls.get ("InferiorClasses").cell_value ();
104 
105         retval(0) = to_ov (lookup_classes (classes));
106       }
107 
108     return retval;
109   }
110 
111   static octave_value_list
class_fromName(const octave_value_list & args,int)112   class_fromName (const octave_value_list& args, int /* nargout */)
113   {
114     octave_value_list retval;
115 
116     if (args.length () != 1)
117       error ("fromName: invalid number of parameters");
118 
119     std::string name = args(0).xstring_value ("fromName: CLASS_NAME must be a string");
120 
121     retval(0) = to_ov (lookup_class (name, false));
122 
123     return retval;
124   }
125 
126   static octave_value_list
class_fevalStatic(const octave_value_list & args,int nargout)127   class_fevalStatic (const octave_value_list& args, int nargout)
128   {
129     if (args.length () <= 1 || args(0).type_name () != "object")
130       error ("fevalStatic: first argument must be a meta.class object");
131 
132     cdef_class cls (to_cdef (args(0)));
133 
134     std::string meth_name = args(1).xstring_value ("fevalStatic: method name must be a string");
135 
136     cdef_method meth = cls.find_method (meth_name);
137 
138     if (! meth.ok ())
139       error ("fevalStatic: method not found: %s", meth_name.c_str ());
140 
141     if (! meth.is_static ())
142       error ("fevalStatic: method '%s' is not static", meth_name.c_str ());
143 
144     return meth.execute (args.splice (0, 2), nargout, true, "fevalStatic");
145   }
146 
147   static octave_value_list
class_getConstant(const octave_value_list & args,int)148   class_getConstant (const octave_value_list& args, int /* nargout */)
149   {
150     octave_value_list retval;
151 
152     if (args.length () != 2 || args(0).type_name () != "object"
153         || args(0).class_name () != "meta.class")
154       error ("getConstant: first argument must be a meta.class object");
155 
156     cdef_class cls = to_cdef (args(0));
157 
158     std::string prop_name = args(1).xstring_value ("getConstant: property name must be a string");
159 
160     cdef_property prop = cls.find_property (prop_name);
161 
162     if (! prop.ok ())
163       error ("getConstant: property not found: %s",
164              prop_name.c_str ());
165 
166     if (! prop.is_constant ())
167       error ("getConstant: property '%s' is not constant",
168              prop_name.c_str ());
169 
170     retval(0) = prop.get_value (true, "getConstant");
171 
172     return retval;
173   }
174 
175 #define META_CLASS_CMP(OP, CLSA, CLSB, FUN)                             \
176   static octave_value_list                                              \
177   class_ ## OP (const octave_value_list& args, int /* nargout */)       \
178   {                                                                     \
179     octave_value_list retval;                                           \
180                                                                         \
181     if (args.length () != 2                                             \
182         || args(0).type_name () != "object"                             \
183         || args(1).type_name () != "object"                             \
184         || args(0).class_name () != "meta.class"                        \
185         || args(1).class_name () != "meta.class")                       \
186       error (#OP ": invalid arguments");                                \
187                                                                         \
188     cdef_class clsa = to_cdef (args(0));                                \
189                                                                         \
190     cdef_class clsb = to_cdef (args(1));                                \
191                                                                         \
192     retval(0) = FUN (CLSA, CLSB);                                       \
193                                                                         \
194     return retval;                                                      \
195   }
196 
META_CLASS_CMP(lt,clsb,clsa,is_strict_superclass)197   META_CLASS_CMP (lt, clsb, clsa, is_strict_superclass)
198   META_CLASS_CMP (le, clsb, clsa, is_superclass)
199   META_CLASS_CMP (gt, clsa, clsb, is_strict_superclass)
200   META_CLASS_CMP (ge, clsa, clsb, is_superclass)
201   META_CLASS_CMP (eq, clsa, clsb, operator==)
202   META_CLASS_CMP (ne, clsa, clsb, operator!=)
203 
204   static octave_value_list
205   property_get_defaultvalue (const octave_value_list& args, int /* nargout */)
206   {
207     octave_value_list retval;
208 
209     if (args.length () == 1 && args(0).type_name () == "object")
210       {
211         cdef_property prop (to_cdef (args(0)));
212 
213         retval(0) = prop.get ("DefaultValue");
214 
215         if (! retval(0).is_defined ())
216           error_with_id ("Octave:class:NoDefaultDefined",
217                          "no default value for property '%s'",
218                          prop.get_name ().c_str ());
219       }
220 
221     return retval;
222   }
223 
224   static octave_value_list
handle_delete(const octave_value_list &,int)225   handle_delete (const octave_value_list& /* args */, int /* nargout */)
226   {
227     octave_value_list retval;
228 
229     // FIXME: implement this.  Wait, what is this supposed to do?
230 
231     return retval;
232   }
233 
234   static octave_value_list
package_get_classes(const octave_value_list & args,int)235   package_get_classes (const octave_value_list& args, int /* nargout */)
236   {
237     octave_value_list retval (1, Matrix ());
238 
239     if (args.length () == 1 && args(0).type_name () == "object"
240         && args(0).class_name () == "meta.package")
241       {
242         cdef_package pack (to_cdef (args(0)));
243 
244         retval(0) = pack.get_classes ();
245       }
246 
247     return retval;
248   }
249 
250   static octave_value_list
package_get_functions(const octave_value_list & args,int)251   package_get_functions (const octave_value_list& args, int /* nargout */)
252   {
253     octave_value_list retval (1, Matrix ());
254 
255     if (args.length () == 0 && args(0).type_name () == "object"
256         && args(0).class_name () == "meta.package")
257       {
258         cdef_package pack (to_cdef (args(0)));
259 
260         retval(0) = pack.get_functions ();
261       }
262 
263     return retval;
264   }
265 
266   static octave_value_list
package_get_packages(const octave_value_list & args,int)267   package_get_packages (const octave_value_list& args, int /* nargout */)
268   {
269     octave_value_list retval (1, Matrix ());
270 
271     if (args.length () == 0 && args(0).type_name () == "object"
272         && args(0).class_name () == "meta.package")
273       {
274         cdef_package pack (to_cdef (args(0)));
275 
276         retval(0) = pack.get_packages ();
277       }
278 
279     return retval;
280   }
281 
282   static octave_value_list
package_getAllPackages(interpreter & interp,const octave_value_list &,int)283   package_getAllPackages (interpreter& interp,
284                           const octave_value_list& /* args */, int /* nargout */)
285   {
286     std::map<std::string, cdef_package> toplevel_packages;
287 
288     load_path& lp = interp.get_load_path ();
289 
290     std::list<std::string> names = lp.get_all_package_names ();
291 
292     cdef_manager& cdm = interp.get_cdef_manager ();
293 
294     toplevel_packages["meta"] = cdm.find_package ("meta", false, false);
295 
296     for (const auto& nm : names)
297       toplevel_packages[nm] = cdm.find_package (nm, false, true);
298 
299     Cell c (toplevel_packages.size (), 1);
300 
301     int i = 0;
302 
303     for (const auto& nm_pkg : toplevel_packages)
304       c(i++,0) = to_ov (nm_pkg.second);
305 
306     return octave_value_list (octave_value (c));
307   }
308 
309   static octave_value_list
package_fromName(const octave_value_list & args,int)310   package_fromName (const octave_value_list& args, int /* nargout */)
311   {
312     octave_value_list retval;
313 
314     if (args.length () != 1)
315       error ("fromName: invalid number of parameters");
316 
317     std::string name = args(0).xstring_value ("fromName: PACKAGE_NAME must be a string");
318 
319     retval(0) = to_ov (lookup_package (name, false));
320 
321     return retval;
322   }
323 
cdef_manager(interpreter & interp)324   cdef_manager::cdef_manager (interpreter& interp)
325     : m_interpreter (interp), m_all_classes (), m_all_packages (),
326       m_meta_class (), m_meta_property (), m_meta_method (),
327       m_meta_package (), m_meta ()
328   {
329     type_info& ti = m_interpreter.get_type_info ();
330 
331     octave_classdef::register_type (ti);
332 
333     // bootstrap
334     cdef_class tmp_handle = make_class ("handle");
335 
336     m_meta_class = make_meta_class ("meta.class", tmp_handle);
337 
338     tmp_handle.set_class (m_meta_class);
339     m_meta_class.set_class (m_meta_class);
340 
341     // meta classes
342     m_meta_property = make_meta_class ("meta.property", tmp_handle);
343 
344     m_meta_method = make_meta_class ("meta.method", tmp_handle);
345 
346     m_meta_package = make_meta_class ("meta.package", tmp_handle);
347 
348     cdef_class tmp_meta_event
349       = make_meta_class ("meta.event", tmp_handle);
350 
351     cdef_class tmp_meta_dynproperty
352       = make_meta_class ("meta.dynamicproperty", tmp_handle);
353 
354     // meta.class properties
355     m_meta_class.install_property
356       (make_attribute (m_meta_class, "Abstract"));
357 
358     m_meta_class.install_property
359       (make_attribute (m_meta_class, "ConstructOnLoad"));
360 
361     m_meta_class.install_property
362       (make_property (m_meta_class, "ContainingPackage"));
363 
364     m_meta_class.install_property
365       (make_property (m_meta_class, "Description"));
366 
367     m_meta_class.install_property
368       (make_property (m_meta_class, "DetailedDescription"));
369 
370     m_meta_class.install_property
371       (make_property (m_meta_class, "Events"));
372 
373     m_meta_class.install_property
374       (make_attribute (m_meta_class, "HandleCompatible"));
375 
376     m_meta_class.install_property
377       (make_attribute (m_meta_class, "Hidden"));
378 
379     m_meta_class.install_property
380       (make_property (m_meta_class, "InferiorClasses",
381                       make_fcn_handle (class_get_inferiorclasses,
382                                        "meta.class>get.InferiorClasses"),
383                       "public", Matrix (), "private"));
384 
385     m_meta_class.install_property
386       (make_property (m_meta_class, "Methods",
387                       make_fcn_handle (class_get_methods,
388                                        "meta.class>get.Methods"),
389                       "public", Matrix (), "private"));
390 
391     m_meta_class.install_property
392       (make_property (m_meta_class, "MethodList",
393                       make_fcn_handle (class_get_methods,
394                                        "meta.class>get.MethodList"),
395                       "public", Matrix (), "private"));
396 
397     m_meta_class.install_property (make_attribute (m_meta_class, "Name"));
398 
399     m_meta_class.install_property
400       (make_property (m_meta_class, "Properties",
401                       make_fcn_handle (class_get_properties,
402                                        "meta.class>get.Properties"),
403                       "public", Matrix (), "private"));
404 
405     m_meta_class.install_property
406       (make_property (m_meta_class, "PropertyList",
407                       make_fcn_handle (class_get_properties,
408                                        "meta.class>get.PropertyList"),
409                       "public", Matrix (), "private"));
410 
411     m_meta_class.install_property (make_attribute (m_meta_class, "Sealed"));
412 
413     m_meta_class.install_property
414       (make_property (m_meta_class, "SuperClasses",
415                       make_fcn_handle (class_get_superclasses,
416                                        "meta.class>get.SuperClasses"),
417                       "public", Matrix (), "private"));
418 
419     m_meta_class.install_property
420       (make_property (m_meta_class, "SuperclassList",
421                       make_fcn_handle (class_get_superclasses,
422                                        "meta.class>get.SuperclassList"),
423                       "public", Matrix (), "private"));
424 
425     // FIXME: Matlab supports this property under "SuperclassList".
426     //        Octave, however, has supported this under "SuperClassList".
427     //        Alias the property.  Remove in Octave version 8.1.
428     m_meta_class.install_property
429       (make_property (m_meta_class, "SuperClassList",
430                       make_fcn_handle (class_get_superclasses,
431                                        "meta.class>get.SuperclassList"),
432                       "public", Matrix (), "private"));
433 
434     // meta.class methods
435     m_meta_class.install_method
436       (make_method (m_meta_class, "fromName", class_fromName, "public", true));
437 
438     m_meta_class.install_method
439       (make_method (m_meta_class, "fevalStatic", class_fevalStatic, "public",
440                     false));
441 
442     m_meta_class.install_method
443       (make_method (m_meta_class, "getConstant", class_getConstant, "public",
444                     false));
445 
446     m_meta_class.install_method (make_method (m_meta_class, "eq", class_eq));
447     m_meta_class.install_method (make_method (m_meta_class, "ne", class_ne));
448     m_meta_class.install_method (make_method (m_meta_class, "lt", class_lt));
449     m_meta_class.install_method (make_method (m_meta_class, "le", class_le));
450     m_meta_class.install_method (make_method (m_meta_class, "gt", class_gt));
451     m_meta_class.install_method (make_method (m_meta_class, "ge", class_ge));
452 
453     // meta.method properties
454     m_meta_method.install_property
455       (make_attribute (m_meta_method, "Abstract"));
456 
457     m_meta_method.install_property
458       (make_attribute (m_meta_method, "Access"));
459 
460     m_meta_method.install_property
461       (make_attribute (m_meta_method, "DefiningClass"));
462 
463     m_meta_method.install_property
464       (make_attribute (m_meta_method, "Description"));
465 
466     m_meta_method.install_property
467       (make_attribute (m_meta_method, "DetailedDescription"));
468 
469     m_meta_method.install_property
470       (make_attribute (m_meta_method, "Hidden"));
471 
472     m_meta_method.install_property
473       (make_attribute (m_meta_method, "Name"));
474 
475     m_meta_method.install_property
476       (make_attribute (m_meta_method, "Sealed"));
477 
478     m_meta_method.install_property
479       (make_attribute (m_meta_method, "Static"));
480 
481     // meta.property properties
482     m_meta_property.install_property
483       (make_attribute (m_meta_property, "Name"));
484 
485     m_meta_property.install_property
486       (make_attribute (m_meta_property, "Description"));
487 
488     m_meta_property.install_property
489       (make_attribute (m_meta_property, "DetailedDescription"));
490 
491     m_meta_property.install_property
492       (make_attribute (m_meta_property, "Abstract"));
493 
494     m_meta_property.install_property
495       (make_attribute (m_meta_property, "Constant"));
496 
497     m_meta_property.install_property
498       (make_attribute (m_meta_property, "GetAccess"));
499 
500     m_meta_property.install_property
501       (make_attribute (m_meta_property, "SetAccess"));
502 
503     m_meta_property.install_property
504       (make_attribute (m_meta_property, "Dependent"));
505 
506     m_meta_property.install_property
507       (make_attribute (m_meta_property, "Transient"));
508 
509     m_meta_property.install_property
510       (make_attribute (m_meta_property, "Hidden"));
511 
512     m_meta_property.install_property
513       (make_attribute (m_meta_property, "GetObservable"));
514 
515     m_meta_property.install_property
516       (make_attribute (m_meta_property, "SetObservable"));
517 
518     m_meta_property.install_property
519       (make_attribute (m_meta_property, "GetMethod"));
520 
521     m_meta_property.install_property
522       (make_attribute (m_meta_property, "SetMethod"));
523 
524     m_meta_property.install_property
525       (make_attribute (m_meta_property, "DefiningClass"));
526 
527     m_meta_property.install_property
528       (make_property (m_meta_property, "DefaultValue",
529                       make_fcn_handle (property_get_defaultvalue,
530                                        "meta.property>get.DefaultValue"),
531                       "public", Matrix (), "private"));
532 
533     m_meta_property.install_property
534       (make_attribute (m_meta_property, "HasDefault"));
535 
536     // meta.property events
537     // FIXME: add events
538 
539     // handle methods
540 
541     tmp_handle.install_method
542       (make_method (tmp_handle, "delete", handle_delete));
543 
544     // meta.package properties
545 
546     m_meta_package.install_property
547       (make_attribute (m_meta_package, "Name"));
548 
549     m_meta_package.install_property
550       (make_property (m_meta_package, "ContainingPackage"));
551 
552     m_meta_package.install_property
553       (make_property (m_meta_package, "ClassList",
554                       make_fcn_handle (package_get_classes,
555                                        "meta.package>get.ClassList"),
556                       "public", Matrix (), "private"));
557 
558     m_meta_package.install_property
559       (make_property (m_meta_package, "Classes",
560                       make_fcn_handle (package_get_classes,
561                                        "meta.package>get.Classes"),
562                       "public", Matrix (), "private"));
563 
564     m_meta_package.install_property
565       (make_property (m_meta_package, "FunctionList",
566                       make_fcn_handle (package_get_functions,
567                                        "meta.package>get.FunctionList"),
568                       "public", Matrix (), "private"));
569 
570     m_meta_package.install_property
571       (make_property (m_meta_package, "Functions",
572                       make_fcn_handle (package_get_functions,
573                                        "meta.package>get.Functions"),
574                       "public", Matrix (), "private"));
575 
576     m_meta_package.install_property
577       (make_property (m_meta_package, "PackageList",
578                       make_fcn_handle (package_get_packages,
579                                        "meta.package>get.PackageList"),
580                       "public", Matrix (), "private"));
581 
582     m_meta_package.install_property
583       (make_property (m_meta_package, "Packages",
584                       make_fcn_handle (package_get_packages,
585                                        "meta.package>get.Packages"),
586                       "public", Matrix (), "private"));
587 
588     m_meta_package.install_method
589       (make_method (m_meta_package, "fromName", package_fromName,
590                     "public", true));
591 
592     m_meta_package.install_method
593       (make_method (m_meta_package, "getAllPackages", package_getAllPackages,
594                     "public", true));
595 
596     // create "meta" package
597     cdef_package package_meta
598       = m_meta
599       = make_package ("meta");
600 
601     package_meta.install_class (m_meta_class, "class");
602     package_meta.install_class (m_meta_property, "property");
603     package_meta.install_class (m_meta_method, "method");
604     package_meta.install_class (m_meta_package, "package");
605     package_meta.install_class (tmp_meta_event, "event");
606     package_meta.install_class (tmp_meta_dynproperty, "dynproperty");
607 
608     symbol_table& symtab = m_interpreter.get_symbol_table ();
609 
610     // install built-in classes into the symbol table
611     symtab.install_built_in_function
612       ("meta.class", m_meta_class.get_constructor_function ());
613 
614     symtab.install_built_in_function
615       ("meta.method", m_meta_method.get_constructor_function ());
616 
617     symtab.install_built_in_function
618       ("meta.property", m_meta_property.get_constructor_function ());
619 
620     symtab.install_built_in_function
621       ("meta.package", m_meta_package.get_constructor_function ());
622 
623     // FIXME: meta.event and meta.dynproperty are not implemented
624     //        and should not be installed into symbol table.
625 
626     //  symtab.install_built_in_function
627     //    ("meta.event", tmp_meta_event.get_constructor_function ());
628 
629     //  symtab.install_built_in_function
630     //    ("meta.dynproperty", tmp_meta_dynproperty.get_constructor_function ());
631   }
632 
633   cdef_class
find_class(const std::string & name,bool error_if_not_found,bool load_if_not_found)634   cdef_manager::find_class (const std::string& name, bool error_if_not_found,
635                             bool load_if_not_found)
636   {
637     auto it = m_all_classes.find (name);
638 
639     if (it == m_all_classes.end ())
640       {
641         if (load_if_not_found)
642           {
643             octave_value ov_cls;
644 
645             std::size_t pos = name.rfind ('.');
646 
647             if (pos == std::string::npos)
648               ov_cls = m_interpreter.find (name);
649             else
650               {
651                 std::string pack_name = name.substr (0, pos);
652 
653                 cdef_package pack = find_package (pack_name, false, true);
654 
655                 if (pack.ok ())
656                   ov_cls = pack.find (name.substr (pos+1));
657               }
658 
659             if (ov_cls.is_defined ())
660               it = m_all_classes.find (name);
661           }
662       }
663 
664     if (it == m_all_classes.end ())
665       {
666         if (error_if_not_found)
667           error ("class not found: %s", name.c_str ());
668       }
669     else
670       {
671         cdef_class cls = it->second;
672 
673         if (! cls.is_builtin ())
674           cls = lookup_class (cls);
675 
676         if (cls.ok ())
677           return cls;
678         else
679           m_all_classes.erase (it);
680       }
681 
682     return cdef_class ();
683   }
684 
685   octave_value
find_method_symbol(const std::string & method_name,const std::string & class_name)686   cdef_manager::find_method_symbol (const std::string& method_name,
687                                     const std::string& class_name)
688   {
689     cdef_class cls = find_class (class_name, false, false);
690 
691     if (cls.ok ())
692       {
693         cdef_method meth = cls.find_method (method_name);
694 
695         if (meth.ok ())
696           return octave_value (new octave_classdef_meta (meth));
697       }
698 
699     return octave_value ();
700   }
701 
702   cdef_package
find_package(const std::string & name,bool error_if_not_found,bool load_if_not_found)703   cdef_manager::find_package (const std::string& name, bool error_if_not_found,
704                               bool load_if_not_found)
705   {
706     cdef_package retval;
707 
708     std::map<std::string, cdef_package>::const_iterator it
709       = m_all_packages.find (name);
710 
711     if (it != m_all_packages.end ())
712       {
713         retval = it->second;
714 
715         if (! retval.ok ())
716           error ("invalid package '%s'", name.c_str ());
717       }
718     else
719       {
720         load_path& lp = m_interpreter.get_load_path ();
721 
722         if (load_if_not_found && lp.find_package (name))
723           {
724             std::size_t pos = name.rfind ('.');
725 
726             if (pos == std::string::npos)
727               retval = make_package (name, "");
728             else
729               {
730                 std::string parent_name = name.substr (0, pos);
731 
732                 retval = make_package (name, parent_name);
733               }
734           }
735         else if (error_if_not_found)
736           error ("unknown package '%s'", name.c_str ());
737       }
738 
739     return retval;
740   }
741 
742   octave_value
find_package_symbol(const std::string & pack_name)743   cdef_manager::find_package_symbol (const std::string& pack_name)
744   {
745     cdef_package pack = find_package (pack_name, false);
746 
747     if (pack.ok ())
748       return octave_value (new octave_classdef_meta (pack));
749 
750     return octave_value ();
751   }
752 
753   cdef_class
make_class(const std::string & name,const std::list<cdef_class> & super_list)754   cdef_manager::make_class (const std::string& name,
755                             const std::list<cdef_class>& super_list)
756   {
757     cdef_class cls (name, super_list);
758 
759     cls.set_class (meta_class ());
760 
761     cls.put ("Abstract", false);
762     cls.put ("ConstructOnLoad", false);
763     cls.put ("ContainingPackage", Matrix ());
764     cls.put ("Description", "");
765     cls.put ("DetailedDescription", "");
766     cls.put ("Events", Cell ());
767     cls.put ("Hidden", false);
768     cls.put ("InferiorClasses", Cell ());
769     cls.put ("Methods", Cell ());
770     cls.put ("Properties", Cell ());
771     cls.put ("Sealed", false);
772 
773     if (name == "handle")
774       {
775         cls.put ("HandleCompatible", true);
776         cls.mark_as_handle_class ();
777       }
778     else if (super_list.empty ())
779       {
780         cls.put ("HandleCompatible", false);
781       }
782     else
783       {
784         bool all_handle_compatible = true;
785         bool has_handle_class = false;
786 
787         for (const auto& cl : super_list)
788           {
789             all_handle_compatible = all_handle_compatible
790               && cl.get ("HandleCompatible").bool_value ();
791 
792             has_handle_class = has_handle_class || cl.is_handle_class ();
793           }
794 
795         if (has_handle_class && ! all_handle_compatible)
796           error ("%s: cannot mix handle and non-HandleCompatible classes",
797                  name.c_str ());
798 
799         cls.put ("HandleCompatible", all_handle_compatible);
800         if (has_handle_class)
801           cls.mark_as_handle_class ();
802       }
803 
804     if (! name.empty ())
805       register_class (cls);
806 
807     return cls;
808   }
809 
810   cdef_class
make_class(const std::string & name,const cdef_class & super)811   cdef_manager::make_class (const std::string& name,
812                             const cdef_class& super)
813   {
814     return make_class (name, std::list<cdef_class> (1, super));
815   }
816 
817   cdef_class
make_meta_class(const std::string & name,const cdef_class & super)818   cdef_manager::make_meta_class (const std::string& name,
819                                  const cdef_class& super)
820   {
821     cdef_class cls = make_class (name, super);
822 
823     cls.put ("Sealed", true);
824     cls.mark_as_meta_class ();
825 
826     return cls;
827   }
828 
829   cdef_property
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)830   cdef_manager::make_property (const cdef_class& cls, const std::string& name,
831                                const octave_value& get_method,
832                                const std::string& get_access,
833                                const octave_value& set_method,
834                                const std::string& set_access)
835   {
836     cdef_property prop (name);
837 
838     prop.set_class (meta_property ());
839 
840     prop.put ("Description", "");
841     prop.put ("DetailedDescription", "");
842     prop.put ("Abstract", false);
843     prop.put ("Constant", false);
844     prop.put ("GetAccess", get_access);
845     prop.put ("SetAccess", set_access);
846     prop.put ("Dependent", false);
847     prop.put ("Transient", false);
848     prop.put ("Hidden", false);
849     prop.put ("GetObservable", false);
850     prop.put ("SetObservable", false);
851     prop.put ("GetMethod", get_method);
852     prop.put ("SetMethod", set_method);
853     prop.put ("DefiningClass", to_ov (cls));
854     prop.put ("DefaultValue", octave_value ());
855     prop.put ("HasDefault", false);
856 
857     std::string class_name = cls.get_name ();
858 
859     if (! get_method.isempty ())
860       make_function_of_class (class_name, get_method);
861     if (! set_method.isempty ())
862       make_function_of_class (class_name, set_method);
863 
864     return prop;
865   }
866 
867   cdef_property
make_attribute(const cdef_class & cls,const std::string & name)868   cdef_manager::make_attribute (const cdef_class& cls, const std::string& name)
869   {
870     return make_property (cls, name, Matrix (), "public", Matrix (), "private");
871   }
872 
873   cdef_method
make_method(const cdef_class & cls,const std::string & name,const octave_value & fcn,const std::string & m_access,bool is_static)874   cdef_manager::make_method (const cdef_class& cls, const std::string& name,
875                              const octave_value& fcn,
876                              const std::string& m_access, bool is_static)
877   {
878     cdef_method meth (name);
879 
880     meth.set_class (meta_method ());
881 
882     meth.put ("Abstract", false);
883     meth.put ("Access", m_access);
884     meth.put ("DefiningClass", to_ov (cls));
885     meth.put ("Description", "");
886     meth.put ("DetailedDescription", "");
887     meth.put ("Hidden", false);
888     meth.put ("Sealed", true);
889     meth.put ("Static", is_static);
890 
891     if (fcn.is_defined ())
892       make_function_of_class (cls, fcn);
893 
894     meth.set_function (fcn);
895 
896     if (is_dummy_method (fcn))
897       meth.mark_as_external (cls.get_name ());
898 
899     return meth;
900   }
901 
902   cdef_method
make_method(const cdef_class & cls,const std::string & name,octave_builtin::fcn ff,const std::string & m_access,bool is_static)903   cdef_manager::make_method (const cdef_class& cls, const std::string& name,
904                              octave_builtin::fcn ff,
905                              const std::string& m_access, bool is_static)
906   {
907     octave_value fcn (new octave_builtin (ff, name));
908 
909     return make_method (cls, name, fcn, m_access, is_static);
910   }
911 
912   cdef_method
make_method(const cdef_class & cls,const std::string & name,octave_builtin::meth mm,const std::string & m_access,bool is_static)913   cdef_manager::make_method (const cdef_class& cls, const std::string& name,
914                              octave_builtin::meth mm,
915                              const std::string& m_access, bool is_static)
916   {
917     octave_value fcn (new octave_builtin (mm, name));
918 
919     return make_method (cls, name, fcn, m_access, is_static);
920   }
921 
922   cdef_package
make_package(const std::string & nm,const std::string & parent)923   cdef_manager::make_package (const std::string& nm, const std::string& parent)
924   {
925     cdef_package pack (nm);
926 
927     pack.set_class (meta_package ());
928 
929     if (parent.empty ())
930       pack.put ("ContainingPackage", Matrix ());
931     else
932       pack.put ("ContainingPackage", to_ov (find_package (parent)));
933 
934     if (! nm.empty ())
935       register_package (pack);
936 
937     return pack;
938   }
939 
940   octave_value
find_method(const std::string & class_name,const std::string & name) const941   cdef_manager::find_method (const std::string& class_name,
942                              const std::string& name) const
943   {
944     cdef_class cls = lookup_class (class_name);
945 
946     return cls.get_method (name);
947   }
948 }
949