GNU Octave  8.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-2023 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 
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 
193  void visit_cell (tree_cell&) { }
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
264  = a.get_constructor_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
316  cdef_method>& meths,
317  bool only_inherited,
318  bool include_ctor)
319 {
320  load_all_methods ();
321 
323 
324  for (it = m_method_map.begin (); it != m_method_map.end (); ++it)
325  {
326  if (include_ctor || ! it->second.is_constructor ())
327  {
328  std::string nm = it->second.get_name ();
329 
330  if (meths.find (nm) == meths.end ())
331  {
332  if (only_inherited)
333  {
334  octave_value acc = it->second.get ("Access");
335 
336  if (! acc.is_string ()
337  || acc.string_value () == "private")
338  continue;
339  }
340 
341  meths[nm] = it->second;
342  }
343  }
344  }
345 
346  // Look into superclasses
347 
348  Cell super_classes = get ("SuperClasses").cell_value ();
349 
350  for (int i = 0; i < super_classes.numel (); i++)
351  {
352  cdef_class cls = lookup_class (super_classes(i));
353 
354  cls.get_rep ()->find_methods (meths, true, false);
355  }
356 }
357 
360 {
361  auto it = m_property_map.find (nm);
362 
363  if (it != m_property_map.end ())
364  {
365  cdef_property& prop = it->second;
366 
367  if (prop.ok ())
368  return prop;
369  }
370 
371  // Look into superclasses
372 
373  Cell super_classes = get ("SuperClasses").cell_value ();
374 
375  for (int i = 0; i < super_classes.numel (); i++)
376  {
377  cdef_class cls = lookup_class (super_classes(i));
378 
379  cdef_property prop = cls.find_property (nm);
380 
381  if (prop.ok ())
382  return prop;
383  }
384 
385  return cdef_property ();
386 }
387 
388 void
390 {
391  m_property_map[prop.get_name ()] = prop;
392 
393  m_member_count++;
394 }
395 
396 Cell
398 {
399  std::map<std::string, cdef_property> props;
400 
401  props = get_property_map (mode);
402 
403  Cell c (props.size (), 1);
404 
405  int idx = 0;
406 
407  for (const auto& pname_prop : props)
408  c(idx++, 0) = to_ov (pname_prop.second);
409 
410  return c;
411 }
412 
413 std::map<std::string, cdef_property>
415 {
416  std::map<std::string, cdef_property> props;
417 
418  find_properties (props, mode);
419 
420  return props;
421 }
422 
423 void
425  cdef_property>& props,
426  int mode)
427 {
429 
430  for (it = m_property_map.begin (); it != m_property_map.end (); ++it)
431  {
432  std::string nm = it->second.get_name ();
433 
434  if (props.find (nm) == props.end ())
435  {
436  if (mode == property_inherited)
437  {
438  octave_value acc = it->second.get ("GetAccess");
439 
440  if (! acc.is_string ()
441  || acc.string_value () == "private")
442  continue;
443  }
444 
445  props[nm] = it->second;
446  }
447  }
448 
449  // Look into superclasses
450 
451  Cell super_classes = get ("SuperClasses").cell_value ();
452 
453  for (int i = 0; i < super_classes.numel (); i++)
454  {
455  cdef_class cls = lookup_class (super_classes(i));
456 
457  cls.get_rep ()->find_properties (props,
458  (mode == property_all
459  ? property_all
460  : property_inherited));
461  }
462 }
463 
464 void
465 cdef_class::cdef_class_rep::find_names (std::set<std::string>& names,
466  bool all)
467 {
468  load_all_methods ();
469 
470  for (const auto& cls_fnmap : m_method_map)
471  {
472  if (! cls_fnmap.second.is_constructor ())
473  {
474  std::string nm = cls_fnmap.second.get_name ();
475 
476  if (! all)
477  {
478  octave_value acc = cls_fnmap.second.get ("Access");
479 
480  if (! acc.is_string()
481  || acc.string_value () != "public")
482  continue;
483  }
484 
485  names.insert (nm);
486  }
487  }
488 
489  for (const auto& pname_prop : m_property_map)
490  {
491  std::string nm = pname_prop.second.get_name ();
492 
493  if (! all)
494  {
495  octave_value acc = pname_prop.second.get ("GetAccess");
496 
497  if (! acc.is_string()
498  || acc.string_value () != "public")
499  continue;
500  }
501 
502  names.insert (nm);
503  }
504 
505  // Look into superclasses
506 
507  Cell super_classes = get ("SuperClasses").cell_value ();
508 
509  for (int i = 0; i < super_classes.numel (); i++)
510  {
511  cdef_class cls = lookup_class (super_classes(i));
512 
513  cls.get_rep ()->find_names (names, all);
514  }
515 }
516 
519 {
520  std::set<std::string> names;
521 
522  find_names (names, false);
523 
524  string_vector v (names);
525 
526  return v.sort (true);
527 }
528 
529 void
531 {
532  cdef_method dtor = find_method ("delete");
533 
534  // FIXME: would it be better to tell find_method above to not find
535  // overloaded functions?
536 
537  if (dtor.ok () && dtor.is_defined_in_class (get_name ()))
538  dtor.execute (obj, octave_value_list (), 0, true, "destructor");
539 
540  // FIXME: should we destroy corresponding properties here?
541 
542  // Call "delete" in super classes
543 
544  Cell super_classes = get ("SuperClasses").cell_value ();
545 
546  for (int i = 0; i < super_classes.numel (); i++)
547  {
548  cdef_class cls = lookup_class (super_classes(i));
549 
550  if (cls.get_name () != "handle")
551  cls.delete_object (obj);
552  }
553 }
554 
557  const std::list<octave_value_list>& idx,
558  int nargout)
559 {
560  std::size_t skip = 1;
561 
562  octave_value_list retval;
563 
564  switch (type[0])
565  {
566  case '(':
567  // Constructor call
568 
569 #if DEBUG_TRACE
570  std::cerr << "constructor" << std::endl;
571 #endif
572 
573  retval(0) = construct (idx.front ());
574  break;
575 
576  case '.':
577  {
578  // Static method, constant (or property?)
579 
580 #if DEBUG_TRACE
581  std::cerr << "static method/property" << std::endl;
582 #endif
583 
584  if (idx.front ().length () != 1)
585  error ("invalid meta.class indexing");
586 
587  std::string nm = idx.front ()(
588  0).xstring_value ("invalid meta.class indexing, expected a method or property name");
589 
590  cdef_method meth = find_method (nm);
591 
592  if (meth.ok ())
593  {
594  if (! meth.is_static ())
595  error ("method '%s' is not static", nm.c_str ());
596 
597  octave_value_list args;
598 
599  if (type.length () > 1 && idx.size () > 1 && type[1] == '(')
600  {
601  args = *(++(idx.begin ()));
602  skip++;
603  }
604 
605  retval = meth.execute (args, (type.length () > skip
606  ? 1 : nargout), true,
607  "meta.class");
608  }
609  else
610  {
611  cdef_property prop = find_property (nm);
612 
613  if (! prop.ok ())
614  error ("no such method or property '%s'", nm.c_str ());
615 
616  if (! prop.is_constant ())
617  error ("property '%s' is not constant", nm.c_str ());
618 
619  retval(0) = prop.get_value (true, "meta.class");
620  }
621  }
622  break;
623 
624  default:
625  error ("invalid meta.class indexing");
626  break;
627  }
628 
629  if (type.length () > skip && idx.size () > skip && ! retval.empty ())
630  retval = retval(0).next_subsref (nargout, type, idx, skip);
631 
632  return retval;
633 }
634 
635 void
637 {
639 
640  cdm.unregister_class (wrap ());
641 }
642 
643 void
645 {
646  // Populate the object with default property values
647 
648  std::list<cdef_class> super_classes
649  = lookup_classes (get ("SuperClasses").cell_value ());
650 
651  for (auto& cls : super_classes)
652  cls.initialize_object (obj);
653 
654  for (const auto& pname_prop : m_property_map)
655  {
656  if (! pname_prop.second.get ("Dependent").bool_value ())
657  {
658  octave_value pvalue = pname_prop.second.get ("DefaultValue");
659 
660  if (pvalue.is_defined ())
661  obj.put (pname_prop.first, pvalue);
662  else
663  obj.put (pname_prop.first, octave_value (Matrix ()));
664  }
665  }
666 
667  m_count++;
668  obj.mark_for_construction (cdef_class (this));
669 }
670 
671 void
673  const octave_value_list& args)
674 {
675  octave_value_list empty_args;
676 
677  for (const auto& cls : m_implicit_ctor_list)
678  {
679  cdef_class supcls = lookup_class (cls);
680 
681  supcls.run_constructor (obj, empty_args);
682  }
683 
684  std::string cls_name = get_name ();
685  std::string ctor_name = get_base_name (cls_name);
686 
687  cdef_method ctor = find_method (ctor_name);
688 
689  if (ctor.ok ())
690  {
691  octave_value_list ctor_args (args);
692  octave_value_list ctor_retval;
693 
694  ctor_args.prepend (to_ov (obj));
695  ctor_retval = ctor.execute (ctor_args, 1, true, "constructor");
696 
697  if (ctor_retval.length () != 1)
698  error ("%s: invalid number of output arguments for classdef constructor",
699  ctor_name.c_str ());
700 
701  obj = to_cdef (ctor_retval(0));
702  }
703 
704  obj.mark_as_constructed (wrap ());
705 }
706 
708 cdef_class::cdef_class_rep::get_method (const std::string& name) const
709 {
710  auto p = m_method_map.find (name);
711 
712  if (p == m_method_map.end ())
713  return octave_value ();
714 
715  return p->second.get_function ();
716 }
717 
718 
721 {
722  cdef_object obj = construct_object (args);
723 
724  if (obj.ok ())
725  return to_ov (obj);
726 
727  return octave_value ();
728 }
729 
732 {
733  if (is_abstract ())
734  error ("cannot instantiate object for abstract class '%s'",
735  get_name ().c_str ());
736 
737  cdef_object obj;
738 
739  if (is_meta_class ())
740  {
741  // This code path is only used to create empty meta objects
742  // as filler for the empty values within a meta object array.
743 
744  cdef_class this_cls = wrap ();
745 
746  static cdef_object empty_class;
747 
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
785  panic_impossible ();
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);
870  unwind_action pop_scope (&tree_evaluator::pop_scope, &tw);
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 
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
1024  // looks in the @-folder containing the original classdef file.
1025  // However, 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
1056  // CLASSNAME symbol should be added to the scope before
1057  // evaluating default 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
1131  // assigning the property accessors so we can do validation
1132  // by using 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
1139  // can detect which ones are invalid and do not correspond
1140  // to a 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_END_NAMESPACE(octave)
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
static octave_value compute_attribute_value(tree_evaluator &tw, tree_classdef_attribute *t)
Definition: cdef-class.cc:808
cdef_object to_cdef(const octave_value &val)
Definition: cdef-utils.cc:143
std::list< cdef_class > lookup_classes(const Cell &cls_list)
Definition: cdef-utils.cc:113
cdef_class lookup_class(const std::string &name, bool error_if_not_found, bool load_if_not_found)
Definition: cdef-utils.cc:80
std::string get_base_name(const std::string &nm)
Definition: cdef-utils.cc:44
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
void make_function_of_class(const std::string &class_name, const octave_value &fcn)
Definition: cdef-utils.cc:55
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
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-base.cc:2240
Definition: Cell.h:43
Definition: dMatrix.h:42
std::size_t size(void) const
Definition: base-list.h:52
elt_type & front(void)
Definition: base-list.h:79
OCTINTERP_API void delete_object(const cdef_object &obj)
Definition: cdef-class.cc:530
OCTINTERP_API std::map< std::string, cdef_property > get_property_map(int mode)
Definition: cdef-class.cc:414
OCTINTERP_API void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.cc:672
OCTINTERP_API octave_value_list meta_subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
Definition: cdef-class.cc:556
OCTINTERP_API void install_property(const cdef_property &prop)
Definition: cdef-class.cc:389
OCTINTERP_API std::map< std::string, cdef_method > get_method_map(bool only_inherited, bool include_ctor)
Definition: cdef-class.cc:304
OCTINTERP_API cdef_property find_property(const std::string &nm)
Definition: cdef-class.cc:359
std::list< cdef_class > m_implicit_ctor_list
Definition: cdef-class.h:220
OCTINTERP_API string_vector get_names(void)
Definition: cdef-class.cc:518
OCTINTERP_API void install_method(const cdef_method &meth)
Definition: cdef-class.cc:232
OCTINTERP_API void meta_release(void)
Definition: cdef-class.cc:636
OCTINTERP_API octave_value construct(const octave_value_list &args)
Definition: cdef-class.cc:720
std::map< std::string, cdef_property >::const_iterator property_const_iterator
Definition: cdef-class.h:231
std::map< std::string, cdef_method >::const_iterator method_const_iterator
Definition: cdef-class.h:229
OCTINTERP_API void load_all_methods(void)
Definition: cdef-class.cc:281
OCTINTERP_API void find_names(std::set< std::string > &names, bool all)
Definition: cdef-class.cc:465
OCTINTERP_API Cell get_properties(int mode)
Definition: cdef-class.cc:397
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:708
OCTINTERP_API cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.cc:92
OCTINTERP_API void initialize_object(cdef_object &obj)
Definition: cdef-class.cc:644
OCTINTERP_API void find_properties(std::map< std::string, cdef_property > &props, int mode=0)
Definition: cdef-class.cc:424
OCTINTERP_API Cell get_methods(bool include_ctor)
Definition: cdef-class.cc:287
OCTINTERP_API cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.cc:731
OCTINTERP_API cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.h:460
octave_value construct(const octave_value_list &args)
Definition: cdef-class.h:367
void install_property(const cdef_property &prop)
Definition: cdef-class.h:290
std::string get_name(void) const
Definition: cdef-class.h:322
void install_method(const cdef_method &meth)
Definition: cdef-class.h:272
void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.h:382
cdef_class_rep * get_rep(void)
Definition: cdef-class.h:420
bool is_meta_class(void) const
Definition: cdef-class.h:399
std::map< std::string, cdef_property > get_property_map(int mode=property_normal)
Definition: cdef-class.h:301
cdef_class & operator=(const cdef_class &cls)
Definition: cdef-class.h:260
bool is_abstract(void) const
Definition: cdef-class.h:308
void file_name(const std::string &nm)
Definition: cdef-class.h:405
@ property_inherited
Definition: cdef-class.h:414
void initialize_object(cdef_object &obj)
Definition: cdef-class.h:377
void delete_object(const cdef_object &obj)
Definition: cdef-class.h:326
void doc_string(const std::string &txt)
Definition: cdef-class.h:401
OCTINTERP_API octave_value get_method_function(const std::string &nm)
Definition: cdef-class.cc:1170
OCTINTERP_API cdef_property find_property(const std::string &nm)
Definition: cdef-class.h:466
bool is_handle_class(void) const
Definition: cdef-class.h:392
cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.h:372
Cell get_methods(bool include_ctor=false)
Definition: cdef-class.h:277
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
OCTINTERP_API cdef_class make_class(const std::string &name, const std::list< cdef_class > &super_list=std::list< cdef_class >())
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
const cdef_class & meta_property(void) const
Definition: cdef-manager.h:94
OCTINTERP_API cdef_package make_package(const std::string &nm, const std::string &parent="")
OCTINTERP_API cdef_package find_package(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
void unregister_class(const cdef_class &cls)
Definition: cdef-manager.h:78
const cdef_class & meta_package(void) const
Definition: cdef-manager.h:96
const cdef_class & meta_class(void) const
Definition: cdef-manager.h:93
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)
bool is_constructor(void) const
Definition: cdef-method.h:201
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_defined_in_class(const std::string &cname) const
Definition: cdef-method.h:206
bool is_static(void) const
Definition: cdef-method.h:184
octave_value get_function(void) const
Definition: cdef-method.h:191
std::string get_name(void) const
Definition: cdef-method.h:182
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:475
void mark_for_construction(const cdef_class &cls)
Definition: cdef-object.h:314
void mark_as_constructed(void)
Definition: cdef-object.h:331
bool ok(void) const
Definition: cdef-object.h:312
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:263
void set_class(const cdef_class &cls)
Definition: cdef-object.h:232
cdef_object(void)
Definition: cdef-object.h:208
std::string class_name(void) const
Definition: cdef-object.h:234
octave_value get(const std::string &pname) const
Definition: cdef-object.h:268
std::string get_name(void) const
bool is_constant(void) const
octave_value get_value(const cdef_object &obj, bool do_check_access=true, const std::string &who="") const
std::string m_obj_name
Definition: cdef-class.cc:225
void visit_cell(tree_cell &)
Definition: cdef-class.cc:193
std::list< cdef_class > m_ctor_list
Definition: cdef-class.cc:228
void visit_if_command_list(tree_if_command_list &)
Definition: cdef-class.cc:188
void visit_index_expression(tree_index_expression &t)
Definition: cdef-class.cc:161
void visit_while_command(tree_while_command &)
Definition: cdef-class.cc:203
void visit_if_clause(tree_if_clause &)
Definition: cdef-class.cc:186
ctor_analyzer(void)=delete
void visit_octave_user_script(octave_user_script &)
Definition: cdef-class.cc:182
void visit_decl_init_list(tree_decl_init_list &)
Definition: cdef-class.cc:178
void visit_constant(tree_constant &)
Definition: cdef-class.cc:195
void visit_parameter_list(tree_parameter_list &)
Definition: cdef-class.cc:197
void visit_binary_expression(tree_binary_expression &)
Definition: cdef-class.cc:173
void visit_statement(tree_statement &t)
Definition: cdef-class.cc:145
void visit_break_command(tree_break_command &)
Definition: cdef-class.cc:174
void visit_anon_fcn_handle(tree_anon_fcn_handle &)
Definition: cdef-class.cc:171
void visit_multi_assignment(tree_multi_assignment &t)
Definition: cdef-class.cc:156
void visit_unwind_protect_command(tree_unwind_protect_command &)
Definition: cdef-class.cc:202
void visit_no_op_command(tree_no_op_command &)
Definition: cdef-class.cc:194
void visit_decl_command(tree_decl_command &)
Definition: cdef-class.cc:177
void visit_argument_list(tree_argument_list &)
Definition: cdef-class.cc:172
void visit_switch_case_list(tree_switch_case_list &)
Definition: cdef-class.cc:190
void visit_octave_user_function(octave_user_function &)
Definition: cdef-class.cc:183
ctor_analyzer(const std::string &ctor, const std::string &obj)
Definition: cdef-class.cc:136
void visit_fcn_handle(tree_fcn_handle &)
Definition: cdef-class.cc:196
void visit_simple_for_command(tree_simple_for_command &)
Definition: cdef-class.cc:180
std::list< cdef_class > get_constructor_list(void) const
Definition: cdef-class.cc:166
std::string m_who
Definition: cdef-class.cc:222
void visit_postfix_expression(tree_postfix_expression &)
Definition: cdef-class.cc:198
void visit_continue_command(tree_continue_command &)
Definition: cdef-class.cc:176
void visit_if_command(tree_if_command &)
Definition: cdef-class.cc:187
ctor_analyzer(const ctor_analyzer &)=delete
void visit_switch_case(tree_switch_case &)
Definition: cdef-class.cc:189
void visit_identifier(tree_identifier &)
Definition: cdef-class.cc:185
void visit_superclass_ref(tree_superclass_ref &t)
Definition: cdef-class.cc:206
void visit_switch_command(tree_switch_command &)
Definition: cdef-class.cc:191
void visit_do_until_command(tree_do_until_command &)
Definition: cdef-class.cc:204
void visit_decl_elt(tree_decl_elt &)
Definition: cdef-class.cc:179
void visit_complex_for_command(tree_complex_for_command &)
Definition: cdef-class.cc:181
void visit_matrix(tree_matrix &)
Definition: cdef-class.cc:192
~ctor_analyzer(void)=default
void visit_return_command(tree_return_command &)
Definition: cdef-class.cc:200
void visit_simple_assignment(tree_simple_assignment &t)
Definition: cdef-class.cc:151
void visit_prefix_expression(tree_prefix_expression &)
Definition: cdef-class.cc:199
void visit_function_def(tree_function_def &)
Definition: cdef-class.cc:184
void visit_colon_expression(tree_colon_expression &)
Definition: cdef-class.cc:175
void visit_try_catch_command(tree_try_catch_command &)
Definition: cdef-class.cc:201
tree_evaluator & get_evaluator(void)
load_path & get_load_path(void)
Definition: interpreter.h:283
std::list< std::string > methods(const std::string &class_name, const std::string &pack_name="")
Definition: load-path.h:95
std::string name(void) const
Definition: ov-fcn.h:208
octave::tree_statement_list * body(void)
Definition: ov-usr-fcn.h:120
void stash_function_name(const std::string &s)
Definition: ov-usr-fcn.h:311
octave::tree_parameter_list * return_list(void)
Definition: ov-usr-fcn.h:396
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
OCTINTERP_API octave_function * function_value(bool silent=false) const
bool bool_value(bool warn=false) const
Definition: ov.h:930
bool is_string(void) const
Definition: ov.h:682
bool is_defined(void) const
Definition: ov.h:637
Cell cell_value(void) const
OCTINTERP_API octave_user_function * user_function_value(bool silent=false) 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
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
tree_classdef_body * body(void)
Definition: pt-classdef.h:803
tree_classdef_superclass_list * superclass_list(void)
Definition: pt-classdef.h:801
tree_classdef_attribute_list * attribute_list(void)
Definition: pt-classdef.h:796
std::string file_name(void) const
Definition: pt-classdef.h:810
std::string doc_string(void) const
Definition: pt-classdef.h:815
tree_identifier * ident(void)
Definition: pt-classdef.h:798
std::string package_name(void) const
Definition: pt-classdef.h:808
std::string name(void) const
Definition: pt-decl.h:90
void push_dummy_scope(const std::string &name)
Definition: pt-eval.cc:2640
void pop_scope(void)
Definition: pt-eval.cc:2647
virtual octave_value evaluate(tree_evaluator &tw, int nargout=1)=0
virtual std::string name(void) const
Definition: pt-exp.h:106
virtual bool is_identifier(void) const
Definition: pt-exp.h:70
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
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void error(const char *fmt,...)
Definition: error.cc:979
#define panic_impossible()
Definition: error.h:508
cdef_manager & __get_cdef_manager__(void)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))