GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
cdef-class.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2012-2022 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 <algorithm>
31#include <iomanip>
32
33#include "cdef-class.h"
34#include "cdef-manager.h"
35#include "cdef-method.h"
36#include "cdef-package.h"
37#include "cdef-property.h"
38#include "cdef-utils.h"
39#include "errwarn.h"
40#include "interpreter-private.h"
41#include "interpreter.h"
42#include "load-path.h"
43#include "ov-builtin.h"
44#include "ov-classdef.h"
45#include "ov-fcn-handle.h"
46#include "ov-usr-fcn.h"
47#include "parse.h"
48#include "pt-assign.h"
49#include "pt-classdef.h"
50#include "pt-eval.h"
51#include "pt-idx.h"
52#include "pt-misc.h"
53#include "pt-stmt.h"
54#include "pt-walk.h"
55#include "unwind-prot.h"
56
57// Define to 1 to enable debugging statements.
58#define DEBUG_TRACE 0
59#if DEBUG_TRACE
60# include <iostream>
61#endif
62
63namespace octave
64{
65 static octave_value
66 make_fcn_handle (const octave_value& fcn, const std::string& meth_name,
67 const std::string& class_name)
68 {
69 octave_value retval;
70
71 if (fcn.is_defined ())
72 {
73 // FCN_HANDLE: METHOD
75 = new octave_fcn_handle (fcn, class_name, meth_name);
76
77 retval = octave_value (fh);
78 }
79
80 return retval;
81 }
82
83 cdef_class::cdef_class_rep::cdef_class_rep (const std::list<cdef_class>& superclasses)
84 : cdef_meta_object_rep (), m_member_count (0), m_handle_class (false),
85 m_meta (false)
86 {
87 put ("SuperClasses", to_ov (superclasses));
88 m_implicit_ctor_list = superclasses;
89 }
90
92 cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local)
93 {
94 auto it = m_method_map.find (nm);
95
96 if (it == m_method_map.end ())
97 {
98 // FIXME: look into class directory
99 }
100 else
101 {
102 cdef_method& meth = it->second;
103
104 // FIXME: check if method reload needed
105
106 if (meth.ok ())
107 return meth;
108 }
109
110 if (! local)
111 {
112 // Look into superclasses
113
114 Cell super_classes = get ("SuperClasses").cell_value ();
115
116 for (int i = 0; i < super_classes.numel (); i++)
117 {
118 cdef_class cls = lookup_class (super_classes(i));
119
120 cdef_method meth = cls.find_method (nm);
121
122 if (meth.ok ())
123 return meth;
124 }
125 }
126
127 return cdef_method ();
128 }
129
131 {
132 public:
133
134 ctor_analyzer (void) = delete;
135
136 ctor_analyzer (const std::string& ctor, const std::string& obj)
137 : tree_walker (), m_who (ctor), m_obj_name (obj) { }
138
139 ctor_analyzer (const ctor_analyzer&) = delete;
140
142
143 ~ctor_analyzer (void) = default;
144
146 {
147 if (t.is_expression ())
148 t.expression ()->accept (*this);
149 }
150
152 {
153 t.right_hand_side ()->accept (*this);
154 }
155
157 {
158 t.right_hand_side ()->accept (*this);
159 }
160
162 {
163 t.expression ()->accept (*this);
164 }
165
166 std::list<cdef_class> get_constructor_list (void) const
167 { return m_ctor_list; }
168
169 // NO-OP
170
205
207 {
208 if (t.method_name () == m_obj_name)
209 {
210 std::string class_name = t.class_name ();
211
212 cdef_class cls = lookup_class (class_name, false);
213
214 if (cls.ok ())
215 m_ctor_list.push_back (cls);
216 }
217 }
218
219 private:
220
221 // The name of the constructor being analyzed.
222 std::string m_who;
223
224 // The name of the first output argument of the constructor.
225 std::string m_obj_name;
226
227 // The list of superclass constructors that are explicitly called.
228 std::list<cdef_class> m_ctor_list;
229 };
230
231 void
233 {
234 m_method_map[meth.get_name ()] = meth;
235
236 m_member_count++;
237
238 if (meth.is_constructor ())
239 {
240 // Analyze the constructor code to determine what superclass
241 // constructors are called explicitly.
242
243 octave_value ov_fcn = meth.get_function ();
244
245 if (ov_fcn.is_defined ())
246 {
247 octave_user_function *uf = ov_fcn.user_function_value (true);
248
249 if (uf)
250 {
251 tree_parameter_list *ret_list = uf->return_list ();
252 tree_statement_list *body = uf->body ();
253
254 if (! ret_list || ret_list->size () != 1)
255 error ("%s: invalid constructor output arguments",
256 meth.get_name ().c_str ());
257
258 std::string m_obj_name = ret_list->front ()->name ();
259 ctor_analyzer a (meth.get_name (), m_obj_name);
260
261 body->accept (a);
262
263 std::list<cdef_class> explicit_ctor_list
265
266 for (const auto& cdef_cls : explicit_ctor_list)
267 {
268#if DEBUG_TRACE
269 std::cerr << "explicit superclass constructor: "
270 << cdef_cls.get_name () << std::endl;
271#endif
272
273 m_implicit_ctor_list.remove (cdef_cls);
274 }
275 }
276 }
277 }
278 }
279
280 void
282 {
283 // FIXME: re-scan class directory
284 }
285
286 Cell
288 {
289 std::map<std::string, cdef_method> meths;
290
291 find_methods (meths, false, include_ctor);
292
293 Cell c (meths.size (), 1);
294
295 int idx = 0;
296
297 for (const auto& nm_mthd : meths)
298 c(idx++, 0) = to_ov (nm_mthd.second);
299
300 return c;
301 }
302
303 std::map<std::string, cdef_method>
305 bool include_ctor)
306 {
307 std::map<std::string, cdef_method> methods;
308
309 find_methods (methods, only_inherited, include_ctor);
310
311 return methods;
312 }
313
314 void
315 cdef_class::cdef_class_rep::find_methods (std::map<std::string, cdef_method>& meths,
316 bool only_inherited,
317 bool include_ctor)
318 {
319 load_all_methods ();
320
322
323 for (it = m_method_map.begin (); it != m_method_map.end (); ++it)
324 {
325 if (include_ctor || ! it->second.is_constructor ())
326 {
327 std::string nm = it->second.get_name ();
328
329 if (meths.find (nm) == meths.end ())
330 {
331 if (only_inherited)
332 {
333 octave_value acc = it->second.get ("Access");
334
335 if (! acc.is_string ()
336 || acc.string_value () == "private")
337 continue;
338 }
339
340 meths[nm] = it->second;
341 }
342 }
343 }
344
345 // Look into superclasses
346
347 Cell super_classes = get ("SuperClasses").cell_value ();
348
349 for (int i = 0; i < super_classes.numel (); i++)
350 {
351 cdef_class cls = lookup_class (super_classes(i));
352
353 cls.get_rep ()->find_methods (meths, true, false);
354 }
355 }
356
359 {
360 auto it = m_property_map.find (nm);
361
362 if (it != m_property_map.end ())
363 {
364 cdef_property& prop = it->second;
365
366 if (prop.ok ())
367 return prop;
368 }
369
370 // Look into superclasses
371
372 Cell super_classes = get ("SuperClasses").cell_value ();
373
374 for (int i = 0; i < super_classes.numel (); i++)
375 {
376 cdef_class cls = lookup_class (super_classes(i));
377
378 cdef_property prop = cls.find_property (nm);
379
380 if (prop.ok ())
381 return prop;
382 }
383
384 return cdef_property ();
385 }
386
387 void
389 {
390 m_property_map[prop.get_name ()] = prop;
391
392 m_member_count++;
393 }
394
395 Cell
397 {
398 std::map<std::string, cdef_property> props;
399
400 props = get_property_map (mode);
401
402 Cell c (props.size (), 1);
403
404 int idx = 0;
405
406 for (const auto& pname_prop : props)
407 c(idx++, 0) = to_ov (pname_prop.second);
408
409 return c;
410 }
411
412 std::map<std::string, cdef_property>
414 {
415 std::map<std::string, cdef_property> props;
416
417 find_properties (props, mode);
418
419 return props;
420 }
421
422 void
424 cdef_property>& props,
425 int mode)
426 {
428
429 for (it = m_property_map.begin (); it != m_property_map.end (); ++it)
430 {
431 std::string nm = it->second.get_name ();
432
433 if (props.find (nm) == props.end ())
434 {
435 if (mode == property_inherited)
436 {
437 octave_value acc = it->second.get ("GetAccess");
438
439 if (! acc.is_string ()
440 || acc.string_value () == "private")
441 continue;
442 }
443
444 props[nm] = it->second;
445 }
446 }
447
448 // Look into superclasses
449
450 Cell super_classes = get ("SuperClasses").cell_value ();
451
452 for (int i = 0; i < super_classes.numel (); i++)
453 {
454 cdef_class cls = lookup_class (super_classes(i));
455
456 cls.get_rep ()->find_properties (props,
457 (mode == property_all
460 }
461 }
462
463 void
464 cdef_class::cdef_class_rep::find_names (std::set<std::string>& names,
465 bool all)
466 {
467 load_all_methods ();
468
469 for (const auto& cls_fnmap : m_method_map)
470 {
471 if (! cls_fnmap.second.is_constructor ())
472 {
473 std::string nm = cls_fnmap.second.get_name ();
474
475 if (! all)
476 {
477 octave_value acc = cls_fnmap.second.get ("Access");
478
479 if (! acc.is_string()
480 || acc.string_value () != "public")
481 continue;
482 }
483
484 names.insert (nm);
485 }
486 }
487
488 for (const auto& pname_prop : m_property_map)
489 {
490 std::string nm = pname_prop.second.get_name ();
491
492 if (! all)
493 {
494 octave_value acc = pname_prop.second.get ("GetAccess");
495
496 if (! acc.is_string()
497 || acc.string_value () != "public")
498 continue;
499 }
500
501 names.insert (nm);
502 }
503
504 // Look into superclasses
505
506 Cell super_classes = get ("SuperClasses").cell_value ();
507
508 for (int i = 0; i < super_classes.numel (); i++)
509 {
510 cdef_class cls = lookup_class (super_classes(i));
511
512 cls.get_rep ()->find_names (names, all);
513 }
514 }
515
518 {
519 std::set<std::string> names;
520
521 find_names (names, false);
522
523 string_vector v (names);
524
525 return v.sort (true);
526 }
527
528 void
530 {
531 cdef_method dtor = find_method ("delete");
532
533 // FIXME: would it be better to tell find_method above to not find
534 // overloaded functions?
535
536 if (dtor.ok () && dtor.is_defined_in_class (get_name ()))
537 dtor.execute (obj, octave_value_list (), 0, true, "destructor");
538
539 // FIXME: should we destroy corresponding properties here?
540
541 // Call "delete" in super classes
542
543 Cell super_classes = get ("SuperClasses").cell_value ();
544
545 for (int i = 0; i < super_classes.numel (); i++)
546 {
547 cdef_class cls = lookup_class (super_classes(i));
548
549 if (cls.get_name () != "handle")
550 cls.delete_object (obj);
551 }
552 }
553
556 const std::list<octave_value_list>& idx,
557 int nargout)
558 {
559 std::size_t skip = 1;
560
561 octave_value_list retval;
562
563 switch (type[0])
564 {
565 case '(':
566 // Constructor call
567
568#if DEBUG_TRACE
569 std::cerr << "constructor" << std::endl;
570#endif
571
572 retval(0) = construct (idx.front ());
573 break;
574
575 case '.':
576 {
577 // Static method, constant (or property?)
578
579#if DEBUG_TRACE
580 std::cerr << "static method/property" << std::endl;
581#endif
582
583 if (idx.front ().length () != 1)
584 error ("invalid meta.class indexing");
585
586 std::string nm = idx.front ()(0).xstring_value ("invalid meta.class indexing, expected a method or property name");
587
588 cdef_method meth = find_method (nm);
589
590 if (meth.ok ())
591 {
592 if (! meth.is_static ())
593 error ("method '%s' is not static", nm.c_str ());
594
596
597 if (type.length () > 1 && idx.size () > 1 && type[1] == '(')
598 {
599 args = *(++(idx.begin ()));
600 skip++;
601 }
602
603 retval = meth.execute (args, (type.length () > skip
604 ? 1 : nargout), true,
605 "meta.class");
606 }
607 else
608 {
609 cdef_property prop = find_property (nm);
610
611 if (! prop.ok ())
612 error ("no such method or property '%s'", nm.c_str ());
613
614 if (! prop.is_constant ())
615 error ("property '%s' is not constant", nm.c_str ());
616
617 retval(0) = prop.get_value (true, "meta.class");
618 }
619 }
620 break;
621
622 default:
623 error ("invalid meta.class indexing");
624 break;
625 }
626
627 if (type.length () > skip && idx.size () > skip && ! retval.empty ())
628 retval = retval(0).next_subsref (nargout, type, idx, skip);
629
630 return retval;
631 }
632
633 void
635 {
636 cdef_manager& cdm
637 = __get_cdef_manager__ ("cdef_class::cdef_class_rep::meta_release");
638
639 cdm.unregister_class (wrap ());
640 }
641
642 void
644 {
645 // Populate the object with default property values
646
647 std::list<cdef_class> super_classes
648 = lookup_classes (get ("SuperClasses").cell_value ());
649
650 for (auto& cls : super_classes)
651 cls.initialize_object (obj);
652
653 for (const auto& pname_prop : m_property_map)
654 {
655 if (! pname_prop.second.get ("Dependent").bool_value ())
656 {
657 octave_value pvalue = pname_prop.second.get ("DefaultValue");
658
659 if (pvalue.is_defined ())
660 obj.put (pname_prop.first, pvalue);
661 else
662 obj.put (pname_prop.first, octave_value (Matrix ()));
663 }
664 }
665
666 m_count++;
668 }
669
670 void
672 const octave_value_list& args)
673 {
674 octave_value_list empty_args;
675
676 for (const auto& cls : m_implicit_ctor_list)
677 {
678 cdef_class supcls = lookup_class (cls);
679
680 supcls.run_constructor (obj, empty_args);
681 }
682
683 std::string cls_name = get_name ();
684 std::string ctor_name = get_base_name (cls_name);
685
686 cdef_method ctor = find_method (ctor_name);
687
688 if (ctor.ok ())
689 {
690 octave_value_list ctor_args (args);
691 octave_value_list ctor_retval;
692
693 ctor_args.prepend (to_ov (obj));
694 ctor_retval = ctor.execute (ctor_args, 1, true, "constructor");
695
696 if (ctor_retval.length () != 1)
697 error ("%s: invalid number of output arguments for classdef constructor",
698 ctor_name.c_str ());
699
700 obj = to_cdef (ctor_retval(0));
701 }
702
703 obj.mark_as_constructed (wrap ());
704 }
705
708 {
709 auto p = m_method_map.find (name);
710
711 if (p == m_method_map.end ())
712 return octave_value ();
713
714 return p->second.get_function ();
715 }
716
717
720 {
721 cdef_object obj = construct_object (args);
722
723 if (obj.ok ())
724 return to_ov (obj);
725
726 return octave_value ();
727 }
728
731 {
732 if (is_abstract ())
733 error ("cannot instantiate object for abstract class '%s'",
734 get_name ().c_str ());
735
736 cdef_object obj;
737
738 if (is_meta_class ())
739 {
740 // This code path is only used to create empty meta objects
741 // as filler for the empty values within a meta object array.
742
743 cdef_class this_cls = wrap ();
744
745 static cdef_object empty_class;
746
747 cdef_manager& cdm
748 = __get_cdef_manager__ ("cdef_class::cdef_class_rep::construct_object");
749
750 if (this_cls == cdm.meta_class ())
751 {
752 if (! empty_class.ok ())
753 empty_class = cdm.make_class ("", std::list<cdef_class> ());
754 obj = empty_class;
755 }
756 else if (this_cls == cdm.meta_property ())
757 {
758 static cdef_property empty_property;
759
760 if (! empty_class.ok ())
761 empty_class = cdm.make_class ("", std::list<cdef_class> ());
762 if (! empty_property.ok ())
763 empty_property = cdm.make_property (empty_class, "");
764 obj = empty_property;
765 }
766 else if (this_cls == cdm.meta_method ())
767 {
768 static cdef_method empty_method;
769
770 if (! empty_class.ok ())
771 empty_class = cdm.make_class ("", std::list<cdef_class> ());
772 if (! empty_method.ok ())
773 empty_method = cdm.make_method (empty_class, "", octave_value ());
774 obj = empty_method;
775 }
776 else if (this_cls == cdm.meta_package ())
777 {
778 static cdef_package empty_package;
779
780 if (! empty_package.ok ())
781 empty_package = cdm.make_package ("");
782 obj = empty_package;
783 }
784 else
786
787 return obj;
788 }
789 else
790 {
791 if (is_handle_class ())
792 obj = cdef_object (new handle_cdef_object ());
793 else
794 obj = cdef_object (new value_cdef_object ());
795 obj.set_class (wrap ());
796
797 initialize_object (obj);
798
799 run_constructor (obj, args);
800
801 return obj;
802 }
803
804 return cdef_object ();
805 }
806
807 static octave_value
810 {
811 tree_expression *expr = t->expression ();
812
813 if (expr)
814 {
815 if (expr->is_identifier ())
816 {
817 std::string s = expr->name ();
818
819 if (s == "public")
820 return std::string ("public");
821 else if (s == "protected")
822 return std::string ("protected");
823 else if (s == "private")
824 return std::string ("private");
825 }
826
827 return expr->evaluate (tw);
828 }
829 else
830 return octave_value (true);
831 }
832
833 template <typename T>
834 static std::string
836 {
837 if (v.is_string ())
838 return v.string_value ();
839 else if (t->expression ())
840 return t->expression ()->original_text ();
841 else
842 return "true";
843 }
844
847 tree_classdef *t, bool is_at_folder)
848 {
849 cdef_class retval;
850
851 // Class creation
852
853 std::string class_name = t->ident ()->name ();
854 std::string full_class_name = class_name;
855 if (! t->package_name ().empty ())
856 full_class_name = t->package_name () + '.' + full_class_name;
857
858#if DEBUG_TRACE
859 std::cerr << "class: " << full_class_name << std::endl;
860#endif
861
862 // Push a dummy scope frame on the call stack that corresponds to
863 // the scope that was used when parsing classdef object. Without
864 // this, we may pick up stray values from the current scope when
865 // evaluating expressions found in things like attribute lists.
866
867 tree_evaluator& tw = interp.get_evaluator ();
868
869 tw.push_dummy_scope (full_class_name);
871
872 std::list<cdef_class> slist;
873
874 if (t->superclass_list ())
875 {
876 for (auto& scls : (*t->superclass_list ()))
877 {
878 std::string sclass_name = (scls)->class_name ();
879
880#if DEBUG_TRACE
881 std::cerr << "superclass: " << sclass_name << std::endl;
882#endif
883
884 cdef_class sclass = lookup_class (sclass_name);
885
886 if (sclass.get ("Sealed").bool_value ())
887 error ("'%s' cannot inherit from '%s', because it is sealed",
888 full_class_name.c_str (), sclass_name.c_str ());
889
890 slist.push_back (sclass);
891 }
892 }
893
894 cdef_manager& cdm = __get_cdef_manager__ ("cdef_class::make_meta_class");
895
896 retval = cdm.make_class (full_class_name, slist);
897
898 retval.doc_string (t->doc_string ());
899 retval.file_name (t->file_name ());
900
901 // Package owning this class
902
903 if (! t->package_name ().empty ())
904 {
905 cdef_package pack = cdm.find_package (t->package_name ());
906
907 if (pack.ok ())
908 retval.put ("ContainingPackage", to_ov (pack));
909 }
910
911 // FIXME: instead of attaching attributes here, pass them to
912 // cdef_manager::make_method. The classdef manager contains a meta
913 // object with a list of all valid properties that can be used to
914 // validate the attribute list (see bug #60593).
915
916 // Class attributes
917
918 if (t->attribute_list ())
919 {
920 for (const auto& attr : (*t->attribute_list ()))
921 {
922 std::string aname = attr->ident ()->name ();
923 octave_value avalue = compute_attribute_value (tw, attr);
924
925#if DEBUG_TRACE
926 std::cerr << "class attribute: " << aname << " = "
927 << attribute_value_to_string (attr, avalue) << std::endl;
928#endif
929
930 retval.put (aname, avalue);
931 }
932 }
933
934 tree_classdef_body *b = t->body ();
935
936 if (b)
937 {
938 // Keep track of the get/set accessor methods. They will be used
939 // later on when creating properties.
940
941 std::map<std::string, octave_value> get_methods;
942 std::map<std::string, octave_value> set_methods;
943
944 // Method blocks
945
946 std::list<tree_classdef_methods_block *> mb_list = b->methods_list ();
947
948 load_path& lp = interp.get_load_path ();
949
950 for (auto& mb_p : mb_list)
951 {
952 std::map<std::string, octave_value> amap;
953
954#if DEBUG_TRACE
955 std::cerr << "method block" << std::endl;
956#endif
957
958 // Method attributes
959
960 if (mb_p->attribute_list ())
961 {
962 for (auto& attr_p : *mb_p->attribute_list ())
963 {
964 std::string aname = attr_p->ident ()->name ();
965 octave_value avalue = compute_attribute_value (tw, attr_p);
966
967#if DEBUG_TRACE
968 std::cerr << "method attribute: " << aname << " = "
969 << attribute_value_to_string (attr_p, avalue)
970 << std::endl;
971#endif
972
973 amap[aname] = avalue;
974 }
975 }
976
977 // Methods
978
979 if (mb_p->element_list ())
980 {
981 for (auto& mtd : *mb_p->element_list ())
982 {
983 std::string mname = mtd.function_value ()->name ();
984 std::string mprefix = mname.substr (0, 4);
985
986 if (mprefix == "get.")
987 get_methods[mname.substr (4)]
988 = make_fcn_handle (mtd, mname, full_class_name);
989 else if (mprefix == "set.")
990 set_methods[mname.substr (4)]
991 = make_fcn_handle (mtd, mname, full_class_name);
992 else
993 {
994 cdef_method meth = cdm.make_method (retval, mname, mtd);
995
996#if DEBUG_TRACE
997 std::cerr << (mname == class_name ? "constructor"
998 : "method")
999 << ": " << mname << std::endl;
1000#endif
1001
1002 // FIXME: instead of attaching attributes here,
1003 // pass them to cdef_manager::make_method. The
1004 // classdef manager contains a meta object with
1005 // a list of all valid properties that can be
1006 // used to validate the attribute list (see bug
1007 // #60593).
1008
1009 for (auto& attrnm_val : amap)
1010 meth.put (attrnm_val.first, attrnm_val.second);
1011
1012 retval.install_method (meth);
1013 }
1014 }
1015 }
1016 }
1017
1018 if (is_at_folder)
1019 {
1020 // Look for all external methods visible on octave path at the
1021 // time of loading of the class.
1022 //
1023 // FIXME: This is an "extension" to Matlab behavior, which only looks
1024 // in the @-folder containing the original classdef file. However,
1025 // this is easier to implement it that way at the moment.
1026
1027 std::list<std::string> external_methods
1028 = lp.methods (full_class_name);
1029
1030 for (const auto& mtdnm : external_methods)
1031 {
1032 // FIXME: should we issue a warning if the method is already
1033 // defined in the classdef file?
1034
1035 if (mtdnm != class_name
1036 && ! retval.find_method (mtdnm, true).ok ())
1037 {
1038 // Create a dummy method that is used until the actual
1039 // method is loaded.
1041
1042 fcn->stash_function_name (mtdnm);
1043
1044 cdef_method meth
1045 = cdm.make_method (retval, mtdnm, octave_value (fcn));
1046
1047 retval.install_method (meth);
1048 }
1049 }
1050 }
1051
1052 // Property blocks
1053
1054 // FIXME: default property expression should be able to call static
1055 // methods of the class being constructed. A restricted CLASSNAME
1056 // symbol should be added to the scope before evaluating default
1057 // value expressions.
1058
1059 std::list<tree_classdef_properties_block *> pb_list
1060 = b->properties_list ();
1061
1062 for (auto& pb_p : pb_list)
1063 {
1064 std::map<std::string, octave_value> amap;
1065
1066#if DEBUG_TRACE
1067 std::cerr << "property block" << std::endl;
1068#endif
1069
1070 // Property attributes
1071
1072 if (pb_p->attribute_list ())
1073 {
1074 for (auto& attr_p : *pb_p->attribute_list ())
1075 {
1076 std::string aname = attr_p->ident ()->name ();
1077 octave_value avalue = compute_attribute_value (tw, attr_p);
1078
1079#if DEBUG_TRACE
1080 std::cerr << "property attribute: " << aname << " = "
1081 << attribute_value_to_string (attr_p, avalue)
1082 << std::endl;
1083#endif
1084
1085 if (aname == "Access")
1086 {
1087 amap["GetAccess"] = avalue;
1088 amap["SetAccess"] = avalue;
1089 }
1090 else
1091 amap[aname] = avalue;
1092 }
1093 }
1094
1095 // Properties
1096
1097 if (pb_p->element_list ())
1098 {
1099 for (auto& prop_p : *pb_p->element_list ())
1100 {
1101 std::string prop_name = prop_p->ident ()->name ();
1102
1103 cdef_property prop = cdm.make_property (retval, prop_name);
1104
1105#if DEBUG_TRACE
1106 std::cerr << "property: " << prop_p->ident ()->name ()
1107 << std::endl;
1108#endif
1109
1110 tree_expression *expr = prop_p->expression ();
1111 if (expr)
1112 {
1113 octave_value pvalue = expr->evaluate (tw);
1114
1115#if DEBUG_TRACE
1116 std::cerr << "property default: "
1117 << attribute_value_to_string (prop_p, pvalue)
1118 << std::endl;
1119#endif
1120
1121 prop.put ("DefaultValue", pvalue);
1122 }
1123
1124 // FIXME: instead of attaching attributes here, pass
1125 // them to cdef_manager::make_property. The
1126 // classdef manager contains a meta object with a
1127 // list of all valid properties that can be used to
1128 // validate the attribute list (see bug #60593).
1129
1130 // Install property attributes. This is done before assigning
1131 // the property accessors so we can do validation by using
1132 // cdef_property methods.
1133
1134 for (auto& attrnm_val : amap)
1135 prop.put (attrnm_val.first, attrnm_val.second);
1136
1137 // Install property access methods, if any. Remove the
1138 // accessor methods from the temporary storage map, so we can
1139 // detect which ones are invalid and do not correspond to a
1140 // defined property.
1141
1142 auto git = get_methods.find (prop_name);
1143
1144 if (git != get_methods.end ())
1145 {
1146 make_function_of_class (retval, git->second);
1147 prop.put ("GetMethod", git->second);
1148 get_methods.erase (git);
1149 }
1150
1151 auto sit = set_methods.find (prop_name);
1152
1153 if (sit != set_methods.end ())
1154 {
1155 make_function_of_class (retval, sit->second);
1156 prop.put ("SetMethod", sit->second);
1157 set_methods.erase (sit);
1158 }
1159
1160 retval.install_property (prop);
1161 }
1162 }
1163 }
1164 }
1165
1166 return retval;
1167 }
1168
1170 cdef_class::get_method_function (const std::string& /* nm */)
1171 {
1172 return octave_value (new octave_classdef_meta (*this));
1173 }
1174}
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
OCTARRAY_API Array< octave_idx_type > find(octave_idx_type n=-1, bool backward=false) const
Find indices of (at most n) nonzero elements.
Definition: Array.cc:2218
Definition: Cell.h:43
Definition: dMatrix.h:42
load_path & get_load_path(void)
Definition: interpreter.h:281
tree_evaluator & get_evaluator(void)
std::list< std::string > methods(const std::string &class_name, const std::string &pack_name="")
Definition: load-path.h:95
std::size_t size(void) const
Definition: base-list.h:52
elt_type & front(void)
Definition: base-list.h:79
OCTINTERP_API std::map< std::string, cdef_property > get_property_map(int mode)
Definition: cdef-class.cc:413
OCTINTERP_API std::map< std::string, cdef_method > get_method_map(bool only_inherited, bool include_ctor)
Definition: cdef-class.cc:304
OCTINTERP_API void meta_release(void)
Definition: cdef-class.cc:634
OCTINTERP_API void delete_object(const cdef_object &obj)
Definition: cdef-class.cc:529
std::list< cdef_class > m_implicit_ctor_list
Definition: cdef-class.h:220
OCTINTERP_API cdef_property find_property(const std::string &nm)
Definition: cdef-class.cc:358
OCTINTERP_API void find_methods(std::map< std::string, cdef_method > &meths, bool only_inherited, bool include_ctor=false)
Definition: cdef-class.cc:315
OCTINTERP_API octave_value get_method(const std::string &name) const
Definition: cdef-class.cc:707
OCTINTERP_API void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.cc:671
OCTINTERP_API void find_names(std::set< std::string > &names, bool all)
Definition: cdef-class.cc:464
OCTINTERP_API void install_property(const cdef_property &prop)
Definition: cdef-class.cc:388
OCTINTERP_API void install_method(const cdef_method &meth)
Definition: cdef-class.cc:232
OCTINTERP_API Cell get_methods(bool include_ctor)
Definition: cdef-class.cc:287
OCTINTERP_API void load_all_methods(void)
Definition: cdef-class.cc:281
std::map< std::string, cdef_method >::const_iterator method_const_iterator
Definition: cdef-class.h:229
OCTINTERP_API octave_value_list meta_subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
Definition: cdef-class.cc:555
OCTINTERP_API void find_properties(std::map< std::string, cdef_property > &props, int mode=0)
Definition: cdef-class.cc:423
std::map< std::string, cdef_property >::const_iterator property_const_iterator
Definition: cdef-class.h:231
OCTINTERP_API string_vector get_names(void)
Definition: cdef-class.cc:517
OCTINTERP_API cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.cc:92
OCTINTERP_API Cell get_properties(int mode)
Definition: cdef-class.cc:396
OCTINTERP_API void initialize_object(cdef_object &obj)
Definition: cdef-class.cc:643
OCTINTERP_API octave_value construct(const octave_value_list &args)
Definition: cdef-class.cc:719
OCTINTERP_API cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.cc:730
OCTINTERP_API octave_value get_method_function(const std::string &nm)
Definition: cdef-class.cc:1170
Cell get_methods(bool include_ctor=false)
Definition: cdef-class.h:276
std::map< std::string, cdef_property > get_property_map(int mode=property_normal)
Definition: cdef-class.h:300
void delete_object(const cdef_object &obj)
Definition: cdef-class.h:325
void install_property(const cdef_property &prop)
Definition: cdef-class.h:289
void doc_string(const std::string &txt)
Definition: cdef-class.h:400
static OCTINTERP_API cdef_class make_meta_class(interpreter &interp, tree_classdef *t, bool is_at_folder=false)
Analyze the tree_classdef tree and transform it to a cdef_class.
Definition: cdef-class.cc:846
void install_method(const cdef_method &meth)
Definition: cdef-class.h:271
bool is_meta_class(void) const
Definition: cdef-class.h:398
bool is_abstract(void) const
Definition: cdef-class.h:307
OCTINTERP_API cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.h:459
cdef_class & operator=(const cdef_class &cls)
Definition: cdef-class.h:259
OCTINTERP_API cdef_property find_property(const std::string &nm)
Definition: cdef-class.h:465
void initialize_object(cdef_object &obj)
Definition: cdef-class.h:376
octave_value construct(const octave_value_list &args)
Definition: cdef-class.h:366
bool is_handle_class(void) const
Definition: cdef-class.h:391
void file_name(const std::string &nm)
Definition: cdef-class.h:404
std::string get_name(void) const
Definition: cdef-class.h:321
cdef_class_rep * get_rep(void)
Definition: cdef-class.h:419
void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.h:381
cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.h:371
OCTINTERP_API cdef_property make_property(const cdef_class &cls, const std::string &name, const octave_value &get_method=Matrix(), const std::string &get_access="public", const octave_value &set_method=Matrix(), const std::string &set_access="public")
const cdef_class & meta_method(void) const
Definition: cdef-manager.h:95
void unregister_class(const cdef_class &cls)
Definition: cdef-manager.h:78
OCTINTERP_API cdef_package make_package(const std::string &nm, const std::string &parent="")
const cdef_class & meta_property(void) const
Definition: cdef-manager.h:94
OCTINTERP_API cdef_method make_method(const cdef_class &cls, const std::string &name, const octave_value &fcn, const std::string &m_access="public", bool is_static=false)
OCTINTERP_API cdef_class make_class(const std::string &name, const std::list< cdef_class > &super_list=std::list< cdef_class >())
const cdef_class & meta_class(void) const
Definition: cdef-manager.h:93
OCTINTERP_API cdef_package find_package(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
const cdef_class & meta_package(void) const
Definition: cdef-manager.h:96
bool is_defined_in_class(const std::string &cname) const
Definition: cdef-method.h:206
std::string get_name(void) const
Definition: cdef-method.h:182
octave_value_list execute(const octave_value_list &args, int nargout, bool do_check_access=true, const std::string &who="")
Definition: cdef-method.h:164
bool is_constructor(void) const
Definition: cdef-method.h:201
bool is_static(void) const
Definition: cdef-method.h:184
octave_value get_function(void) const
Definition: cdef-method.h:191
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:473
void mark_for_construction(const cdef_class &cls)
Definition: cdef-object.h:312
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:261
void set_class(const cdef_class &cls)
Definition: cdef-object.h:231
bool ok(void) const
Definition: cdef-object.h:310
std::string class_name(void) const
Definition: cdef-object.h:233
octave_value get(const std::string &pname) const
Definition: cdef-object.h:266
void mark_as_constructed(void)
Definition: cdef-object.h:329
octave_value get_value(const cdef_object &obj, bool do_check_access=true, const std::string &who="") const
bool is_constant(void) const
std::string get_name(void) const
std::string m_obj_name
Definition: cdef-class.cc:225
void visit_decl_command(tree_decl_command &)
Definition: cdef-class.cc:177
void visit_switch_case_list(tree_switch_case_list &)
Definition: cdef-class.cc:190
void visit_simple_assignment(tree_simple_assignment &t)
Definition: cdef-class.cc:151
void visit_simple_for_command(tree_simple_for_command &)
Definition: cdef-class.cc:180
void visit_postfix_expression(tree_postfix_expression &)
Definition: cdef-class.cc:198
void visit_if_command_list(tree_if_command_list &)
Definition: cdef-class.cc:188
void visit_superclass_ref(tree_superclass_ref &t)
Definition: cdef-class.cc:206
void visit_try_catch_command(tree_try_catch_command &)
Definition: cdef-class.cc:201
void visit_octave_user_script(octave_user_script &)
Definition: cdef-class.cc:182
void visit_statement(tree_statement &t)
Definition: cdef-class.cc:145
ctor_analyzer(const std::string &ctor, const std::string &obj)
Definition: cdef-class.cc:136
void visit_parameter_list(tree_parameter_list &)
Definition: cdef-class.cc:197
void visit_do_until_command(tree_do_until_command &)
Definition: cdef-class.cc:204
void visit_binary_expression(tree_binary_expression &)
Definition: cdef-class.cc:173
void visit_octave_user_function(octave_user_function &)
Definition: cdef-class.cc:183
void visit_complex_for_command(tree_complex_for_command &)
Definition: cdef-class.cc:181
void visit_multi_assignment(tree_multi_assignment &t)
Definition: cdef-class.cc:156
void visit_identifier(tree_identifier &)
Definition: cdef-class.cc:185
void visit_prefix_expression(tree_prefix_expression &)
Definition: cdef-class.cc:199
void visit_matrix(tree_matrix &)
Definition: cdef-class.cc:192
void visit_anon_fcn_handle(tree_anon_fcn_handle &)
Definition: cdef-class.cc:171
~ctor_analyzer(void)=default
void visit_return_command(tree_return_command &)
Definition: cdef-class.cc:200
void visit_argument_list(tree_argument_list &)
Definition: cdef-class.cc:172
void visit_fcn_handle(tree_fcn_handle &)
Definition: cdef-class.cc:196
void visit_continue_command(tree_continue_command &)
Definition: cdef-class.cc:176
void visit_while_command(tree_while_command &)
Definition: cdef-class.cc:203
ctor_analyzer(void)=delete
void visit_no_op_command(tree_no_op_command &)
Definition: cdef-class.cc:194
void visit_colon_expression(tree_colon_expression &)
Definition: cdef-class.cc:175
void visit_break_command(tree_break_command &)
Definition: cdef-class.cc:174
void visit_switch_command(tree_switch_command &)
Definition: cdef-class.cc:191
std::list< cdef_class > m_ctor_list
Definition: cdef-class.cc:228
void visit_unwind_protect_command(tree_unwind_protect_command &)
Definition: cdef-class.cc:202
void visit_constant(tree_constant &)
Definition: cdef-class.cc:195
void visit_function_def(tree_function_def &)
Definition: cdef-class.cc:184
void visit_if_clause(tree_if_clause &)
Definition: cdef-class.cc:186
void visit_decl_elt(tree_decl_elt &)
Definition: cdef-class.cc:179
void visit_cell(tree_cell &)
Definition: cdef-class.cc:193
ctor_analyzer(const ctor_analyzer &)=delete
void visit_index_expression(tree_index_expression &t)
Definition: cdef-class.cc:161
void visit_if_command(tree_if_command &)
Definition: cdef-class.cc:187
void visit_decl_init_list(tree_decl_init_list &)
Definition: cdef-class.cc:178
void visit_switch_case(tree_switch_case &)
Definition: cdef-class.cc:189
std::list< cdef_class > get_constructor_list(void) const
Definition: cdef-class.cc:166
tree_expression * expression(void)
Definition: pt-classdef.h:164
std::list< tree_classdef_properties_block * > properties_list(void)
Definition: pt-classdef.h:714
std::list< tree_classdef_methods_block * > methods_list(void)
Definition: pt-classdef.h:719
std::string file_name(void) const
Definition: pt-classdef.h:810
tree_identifier * ident(void)
Definition: pt-classdef.h:798
tree_classdef_body * body(void)
Definition: pt-classdef.h:803
tree_classdef_attribute_list * attribute_list(void)
Definition: pt-classdef.h:796
std::string package_name(void) const
Definition: pt-classdef.h:808
tree_classdef_superclass_list * superclass_list(void)
Definition: pt-classdef.h:801
std::string doc_string(void) const
Definition: pt-classdef.h:815
std::string name(void) const
Definition: pt-decl.h:90
virtual bool is_identifier(void) const
Definition: pt-exp.h:70
virtual std::string name(void) const
Definition: pt-exp.h:105
virtual octave_value evaluate(tree_evaluator &tw, int nargout=1)=0
std::string name(void) const
Definition: pt-id.h:73
tree_expression * expression(void)
Definition: pt-idx.h:84
tree_expression * right_hand_side(void)
Definition: pt-assign.h:150
tree_expression * right_hand_side(void)
Definition: pt-assign.h:79
void accept(tree_walker &tw)
Definition: pt-stmt.h:199
bool is_expression(void) const
Definition: pt-stmt.h:80
tree_expression * expression(void)
Definition: pt-stmt.h:101
std::string method_name(void) const
Definition: pt-classdef.h:66
std::string class_name(void) const
Definition: pt-classdef.h:71
virtual void accept(tree_walker &tw)=0
std::string name(void) const
Definition: ov-fcn.h:207
octave::tree_statement_list * body(void)
Definition: ov-usr-fcn.h:119
void stash_function_name(const std::string &s)
Definition: ov-usr-fcn.h:310
octave::tree_parameter_list * return_list(void)
Definition: ov-usr-fcn.h:395
bool empty(void) const
Definition: ovl.h:115
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value_list & prepend(const octave_value &val)
Definition: ovl.cc:80
bool bool_value(bool warn=false) const
Definition: ov.h:930
OCTINTERP_API octave_function * function_value(bool silent=false) const
OCTINTERP_API octave_user_function * user_function_value(bool silent=false) const
bool is_string(void) const
Definition: ov.h:682
bool is_defined(void) const
Definition: ov.h:637
Cell cell_value(void) const
std::string string_value(bool force=false) const
Definition: ov.h:1019
string_vector & sort(bool make_uniq=false)
Definition: str-vec.cc:77
void push_dummy_scope(const std::string &name)
Definition: pt-eval.cc:2639
void pop_scope(void)
Definition: pt-eval.cc:2646
void error(const char *fmt,...)
Definition: error.cc:980
#define panic_impossible()
Definition: error.h:411
QString name
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
std::list< cdef_class > lookup_classes(const Cell &cls_list)
Definition: cdef-utils.cc:113
void make_function_of_class(const std::string &class_name, const octave_value &fcn)
Definition: cdef-utils.cc:55
cdef_manager & __get_cdef_manager__(const std::string &who)
static octave_value compute_attribute_value(tree_evaluator &tw, tree_classdef_attribute *t)
Definition: cdef-class.cc:808
std::string get_base_name(const std::string &nm)
Definition: cdef-utils.cc:44
cdef_object to_cdef(const octave_value &val)
Definition: cdef-utils.cc:143
cdef_class lookup_class(const std::string &name, bool error_if_not_found, bool load_if_not_found)
Definition: cdef-utils.cc:80
static octave_value make_fcn_handle(const octave_value &fcn, const std::string &meth_name, const std::string &class_name)
Definition: cdef-class.cc:66
static std::string attribute_value_to_string(T *t, octave_value v)
Definition: cdef-class.cc:835
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))