GNU Octave  6.2.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-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 <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 
63 namespace 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  {
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 (), member_count (0), handle_class (false),
85  meta (false)
86  {
87  put ("SuperClasses", to_ov (superclasses));
88  implicit_ctor_list = superclasses;
89  }
90 
92  cdef_class::cdef_class_rep::find_method (const std::string& nm, bool local)
93  {
94  auto it = method_map.find (nm);
95 
96  if (it == 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 
130  class ctor_analyzer : public tree_walker
131  {
132  public:
133 
134  ctor_analyzer (void) = delete;
135 
136  ctor_analyzer (const std::string& ctor, const std::string& obj)
137  : tree_walker (), who (ctor), 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 ctor_list; }
168 
169  // NO-OP
170 
193  void visit_cell (tree_cell&) { }
205 
207  {
208  if (t.method_name () == 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  ctor_list.push_back (cls);
216  }
217  }
218 
219  private:
220 
221  // The name of the constructor being analyzed.
222  std::string who;
223 
224  // The name of the first output argument of the constructor.
225  std::string obj_name;
226 
227  // The list of superclass constructors that are explicitly called.
228  std::list<cdef_class> ctor_list;
229  };
230 
231  void
233  {
234  method_map[meth.get_name ()] = meth;
235 
236  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 obj_name = ret_list->front ()->name ();
259  ctor_analyzer a (meth.get_name (), 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  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 = method_map.begin (); it != 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 = property_map.find (nm);
361 
362  if (it != 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  property_map[prop.get_name ()] = prop;
391 
392  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 = property_map.begin (); it != 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
458  ? property_all
459  : property_inherited));
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 : 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 : 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  size_t skip = 1;
560 
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 
595  octave_value_list args;
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 : 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++;
667  obj.mark_for_construction (cdef_class (this));
668  }
669 
670  void
672  const octave_value_list& args)
673  {
674  octave_value_list empty_args;
675 
676  for (const auto& cls : 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 
707  cdef_class::cdef_class_rep::get_method (const std::string& name) const
708  {
709  auto p = method_map.find (name);
710 
711  if (p == 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
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 
845  cdef_class
847  tree_classdef *t, bool is_at_folder)
848  {
850  std::string class_name, full_class_name;
851 
852  // Class creation
853 
854  class_name = full_class_name = t->ident ()->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  unwind_protect frame;
868 
869  tree_evaluator& tw = interp.get_evaluator ();
870 
871  tw.push_dummy_scope (full_class_name);
873 
874  std::list<cdef_class> slist;
875 
876  if (t->superclass_list ())
877  {
878  for (auto& scls : (*t->superclass_list ()))
879  {
880  std::string sclass_name = (scls)->class_name ();
881 
882 #if DEBUG_TRACE
883  std::cerr << "superclass: " << sclass_name << std::endl;
884 #endif
885 
886  cdef_class sclass = lookup_class (sclass_name);
887 
888  if (sclass.get ("Sealed").bool_value ())
889  error ("'%s' cannot inherit from '%s', because it is sealed",
890  full_class_name.c_str (), sclass_name.c_str ());
891 
892  slist.push_back (sclass);
893  }
894  }
895 
896  cdef_manager& cdm = __get_cdef_manager__ ("cdef_class::make_meta_class");
897 
898  retval = cdm.make_class (full_class_name, slist);
899 
900  retval.doc_string (t->doc_string ());
901 
902  // Package owning this class
903 
904  if (! t->package_name ().empty ())
905  {
906  cdef_package pack = cdm.find_package (t->package_name ());
907 
908  if (pack.ok ())
909  retval.put ("ContainingPackage", to_ov (pack));
910  }
911 
912  // Class attributes
913 
914  if (t->attribute_list ())
915  {
916  for (const auto& attr : (*t->attribute_list ()))
917  {
918  std::string aname = attr->ident ()->name ();
919  octave_value avalue = compute_attribute_value (tw, attr);
920 
921 #if DEBUG_TRACE
922  std::cerr << "class attribute: " << aname << " = "
923  << attribute_value_to_string (attr, avalue) << std::endl;
924 #endif
925 
926  retval.put (aname, avalue);
927  }
928  }
929 
930  tree_classdef_body *b = t->body ();
931 
932  if (b)
933  {
934  // Keep track of the get/set accessor methods. They will be used
935  // later on when creating properties.
936 
937  std::map<std::string, octave_value> get_methods;
938  std::map<std::string, octave_value> set_methods;
939 
940  // Method blocks
941 
942  std::list<tree_classdef_methods_block *> mb_list = b->methods_list ();
943 
944  load_path& lp = interp.get_load_path ();
945 
946  for (auto& mb_p : mb_list)
947  {
948  std::map<std::string, octave_value> amap;
949 
950 #if DEBUG_TRACE
951  std::cerr << "method block" << std::endl;
952 #endif
953 
954  // Method attributes
955 
956  if (mb_p->attribute_list ())
957  {
958  for (auto& attr_p : *mb_p->attribute_list ())
959  {
960  std::string aname = attr_p->ident ()->name ();
961  octave_value avalue = compute_attribute_value (tw, attr_p);
962 
963 #if DEBUG_TRACE
964  std::cerr << "method attribute: " << aname << " = "
965  << attribute_value_to_string (attr_p, avalue)
966  << std::endl;
967 #endif
968 
969  amap[aname] = avalue;
970  }
971  }
972 
973  // Methods
974 
975  if (mb_p->element_list ())
976  {
977  for (auto& mtd : *mb_p->element_list ())
978  {
979  std::string mname = mtd.function_value ()->name ();
980  std::string mprefix = mname.substr (0, 4);
981 
982  if (mprefix == "get.")
983  get_methods[mname.substr (4)]
984  = make_fcn_handle (mtd, mname, full_class_name);
985  else if (mprefix == "set.")
986  set_methods[mname.substr (4)]
987  = make_fcn_handle (mtd, mname, full_class_name);
988  else
989  {
990  cdef_method meth = cdm.make_method (retval, mname, mtd);
991 
992 #if DEBUG_TRACE
993  std::cerr << (mname == class_name ? "constructor"
994  : "method")
995  << ": " << mname << std::endl;
996 #endif
997 
998  for (auto& attrnm_val : amap)
999  meth.put (attrnm_val.first, attrnm_val.second);
1000 
1001  retval.install_method (meth);
1002  }
1003  }
1004  }
1005  }
1006 
1007  if (is_at_folder)
1008  {
1009  // Look for all external methods visible on octave path at the
1010  // time of loading of the class.
1011  //
1012  // FIXME: This is an "extension" to Matlab behavior, which only looks
1013  // in the @-folder containing the original classdef file. However,
1014  // this is easier to implement it that way at the moment.
1015 
1016  std::list<std::string> external_methods
1017  = lp.methods (full_class_name);
1018 
1019  for (const auto& mtdnm : external_methods)
1020  {
1021  // FIXME: should we issue a warning if the method is already
1022  // defined in the classdef file?
1023 
1024  if (mtdnm != class_name
1025  && ! retval.find_method (mtdnm, true).ok ())
1026  {
1027  // Create a dummy method that is used until the actual
1028  // method is loaded.
1030 
1031  fcn->stash_function_name (mtdnm);
1032 
1033  cdef_method meth
1034  = cdm.make_method (retval, mtdnm, octave_value (fcn));
1035 
1036  retval.install_method (meth);
1037  }
1038  }
1039  }
1040 
1041  // Property blocks
1042 
1043  // FIXME: default property expression should be able to call static
1044  // methods of the class being constructed. A restricted CLASSNAME
1045  // symbol should be added to the scope before evaluating default
1046  // value expressions.
1047 
1048  std::list<tree_classdef_properties_block *> pb_list
1049  = b->properties_list ();
1050 
1051  for (auto& pb_p : pb_list)
1052  {
1053  std::map<std::string, octave_value> amap;
1054 
1055 #if DEBUG_TRACE
1056  std::cerr << "property block" << std::endl;
1057 #endif
1058 
1059  // Property attributes
1060 
1061  if (pb_p->attribute_list ())
1062  {
1063  for (auto& attr_p : *pb_p->attribute_list ())
1064  {
1065  std::string aname = attr_p->ident ()->name ();
1066  octave_value avalue = compute_attribute_value (tw, attr_p);
1067 
1068 #if DEBUG_TRACE
1069  std::cerr << "property attribute: " << aname << " = "
1070  << attribute_value_to_string (attr_p, avalue)
1071  << std::endl;
1072 #endif
1073 
1074  if (aname == "Access")
1075  {
1076  amap["GetAccess"] = avalue;
1077  amap["SetAccess"] = avalue;
1078  }
1079  else
1080  amap[aname] = avalue;
1081  }
1082  }
1083 
1084  // Properties
1085 
1086  if (pb_p->element_list ())
1087  {
1088  for (auto& prop_p : *pb_p->element_list ())
1089  {
1090  std::string prop_name = prop_p->ident ()->name ();
1091 
1092  cdef_property prop = cdm.make_property (retval, prop_name);
1093 
1094 #if DEBUG_TRACE
1095  std::cerr << "property: " << prop_p->ident ()->name ()
1096  << std::endl;
1097 #endif
1098 
1099  tree_expression *expr = prop_p->expression ();
1100  if (expr)
1101  {
1102  octave_value pvalue = expr->evaluate (tw);
1103 
1104 #if DEBUG_TRACE
1105  std::cerr << "property default: "
1106  << attribute_value_to_string (prop_p, pvalue)
1107  << std::endl;
1108 #endif
1109 
1110  prop.put ("DefaultValue", pvalue);
1111  }
1112 
1113  // Install property attributes. This is done before assigning
1114  // the property accessors so we can do validation by using
1115  // cdef_property methods.
1116 
1117  for (auto& attrnm_val : amap)
1118  prop.put (attrnm_val.first, attrnm_val.second);
1119 
1120  // Install property access methods, if any. Remove the
1121  // accessor methods from the temporary storage map, so we can
1122  // detect which ones are invalid and do not correspond to a
1123  // defined property.
1124 
1125  auto git = get_methods.find (prop_name);
1126 
1127  if (git != get_methods.end ())
1128  {
1129  make_function_of_class (retval, git->second);
1130  prop.put ("GetMethod", git->second);
1131  get_methods.erase (git);
1132  }
1133 
1134  auto sit = set_methods.find (prop_name);
1135 
1136  if (sit != set_methods.end ())
1137  {
1138  make_function_of_class (retval, sit->second);
1139  prop.put ("SetMethod", sit->second);
1140  set_methods.erase (sit);
1141  }
1142 
1143  retval.install_property (prop);
1144  }
1145  }
1146  }
1147  }
1148 
1149  return retval;
1150  }
1151 
1152  octave_value
1153  cdef_class::get_method_function (const std::string& /* nm */)
1154  {
1155  return octave_value (new octave_classdef_meta (*this));
1156  }
1157 }
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
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:2225
Definition: Cell.h:43
Definition: dMatrix.h:42
void add_method(T *obj, void(T::*method)(Params...), Args &&... args)
elt_type & front(void)
Definition: base-list.h:79
size_t size(void) const
Definition: base-list.h:52
std::map< std::string, cdef_property > get_property_map(int mode)
Definition: cdef-class.cc:413
std::map< std::string, cdef_method > get_method_map(bool only_inherited, bool include_ctor)
Definition: cdef-class.cc:304
void delete_object(const cdef_object &obj)
Definition: cdef-class.cc:529
cdef_property find_property(const std::string &nm)
Definition: cdef-class.cc:358
void find_methods(std::map< std::string, cdef_method > &meths, bool only_inherited, bool include_ctor=false)
Definition: cdef-class.cc:315
octave_value get_method(const std::string &name) const
Definition: cdef-class.cc:707
void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.cc:671
void find_names(std::set< std::string > &names, bool all)
Definition: cdef-class.cc:464
void install_property(const cdef_property &prop)
Definition: cdef-class.cc:388
void install_method(const cdef_method &meth)
Definition: cdef-class.cc:232
Cell get_methods(bool include_ctor)
Definition: cdef-class.cc:287
std::map< std::string, cdef_method >::const_iterator method_const_iterator
Definition: cdef-class.h:213
octave_value_list meta_subsref(const std::string &type, const std::list< octave_value_list > &idx, int nargout)
Definition: cdef-class.cc:555
std::list< cdef_class > implicit_ctor_list
Definition: cdef-class.h:204
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:215
cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.cc:92
void initialize_object(cdef_object &obj)
Definition: cdef-class.cc:643
octave_value construct(const octave_value_list &args)
Definition: cdef-class.cc:719
cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.cc:730
octave_value get_method_function(const std::string &nm)
Definition: cdef-class.cc:1153
Cell get_methods(bool include_ctor=false)
Definition: cdef-class.h:259
cdef_class & operator=(const cdef_class &cls)
Definition: cdef-class.h:243
void delete_object(const cdef_object &obj)
Definition: cdef-class.h:308
static 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
bool is_meta_class(void) const
Definition: cdef-class.h:381
bool is_abstract(void) const
Definition: cdef-class.h:290
cdef_method find_method(const std::string &nm, bool local=false)
Definition: cdef-class.h:438
cdef_property find_property(const std::string &nm)
Definition: cdef-class.h:444
void initialize_object(cdef_object &obj)
Definition: cdef-class.h:359
octave_value construct(const octave_value_list &args)
Definition: cdef-class.h:349
std::map< std::string, cdef_property > get_property_map(int mode=property_normal)
Definition: cdef-class.h:283
cdef_class_rep * get_rep(void)
Definition: cdef-class.h:398
bool is_handle_class(void) const
Definition: cdef-class.h:374
std::string get_name(void) const
Definition: cdef-class.h:304
void run_constructor(cdef_object &obj, const octave_value_list &args)
Definition: cdef-class.h:364
cdef_object construct_object(const octave_value_list &args)
Definition: cdef-class.h:354
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_package(void) const
Definition: cdef-manager.h:91
void unregister_class(const cdef_class &cls)
Definition: cdef-manager.h:73
cdef_package make_package(const std::string &nm, const std::string &parent="")
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)
const cdef_class & meta_property(void) const
Definition: cdef-manager.h:89
const cdef_class & meta_method(void) const
Definition: cdef-manager.h:90
cdef_class make_class(const std::string &name, const std::list< cdef_class > &super_list=std::list< cdef_class >())
cdef_package find_package(const std::string &name, bool error_if_not_found=true, bool load_if_not_found=true)
const cdef_class & meta_class(void) const
Definition: cdef-manager.h:88
bool is_defined_in_class(const std::string &cname) const
Definition: cdef-method.h:205
std::string get_name(void) const
Definition: cdef-method.h:181
octave_value_list execute(const octave_value_list &args, int nargout, bool do_check_access=true, const std::string &who="")
Definition: cdef-method.h:163
bool is_constructor(void) const
Definition: cdef-method.h:200
bool is_static(void) const
Definition: cdef-method.h:183
octave_value get_function(void) const
Definition: cdef-method.h:190
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:458
void mark_for_construction(const cdef_class &cls)
Definition: cdef-object.h:302
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:256
void set_class(const cdef_class &cls)
Definition: cdef-object.h:226
bool ok(void) const
Definition: cdef-object.h:300
std::string class_name(void) const
Definition: cdef-object.h:228
octave_value get(const std::string &pname) const
Definition: cdef-object.h:261
void mark_as_constructed(void)
Definition: cdef-object.h:319
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
void visit_decl_command(tree_decl_command &)
Definition: cdef-class.cc:177
std::string obj_name
Definition: cdef-class.cc:225
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
std::list< cdef_class > get_constructor_list(void) const
Definition: cdef-class.cc:166
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 > 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
load_path & get_load_path(void)
Definition: interpreter.h:243
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
tree_expression * expression(void)
Definition: pt-classdef.h:162
std::list< tree_classdef_methods_block * > methods_list(void)
Definition: pt-classdef.h:724
std::list< tree_classdef_properties_block * > properties_list(void)
Definition: pt-classdef.h:719
tree_classdef_superclass_list * superclass_list(void)
Definition: pt-classdef.h:806
tree_identifier * ident(void)
Definition: pt-classdef.h:803
tree_classdef_body * body(void)
Definition: pt-classdef.h:808
tree_classdef_attribute_list * attribute_list(void)
Definition: pt-classdef.h:801
std::string package_name(void) const
Definition: pt-classdef.h:813
std::string doc_string(void) const
Definition: pt-classdef.h:818
std::string name(void) const
Definition: pt-decl.h:90
void pop_scope(void)
Definition: pt-eval.cc:2035
void push_dummy_scope(const std::string &name)
Definition: pt-eval.cc:2028
virtual bool is_identifier(void) const
Definition: pt-exp.h:70
virtual std::string name(void) const
Definition: pt-exp.h:103
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:83
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:64
std::string class_name(void) const
Definition: pt-classdef.h:69
virtual void accept(tree_walker &tw)=0
std::string name(void) const
Definition: ov-fcn.h:214
octave::tree_statement_list * body(void)
Definition: ov-usr-fcn.h:123
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
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:838
octave_user_function * user_function_value(bool silent=false) const
bool is_string(void) const
Definition: ov.h:593
bool is_defined(void) const
Definition: ov.h:551
Cell cell_value(void) const
octave_function * function_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:927
string_vector & sort(bool make_uniq=false)
Definition: str-vec.cc:77
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
QString name
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
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
cdef_object to_cdef(const octave_value &val)
Definition: cdef-utils.cc:143
static octave_value compute_attribute_value(tree_evaluator &tw, tree_classdef_attribute *t)
Definition: cdef-class.cc:808
cdef_class lookup_class(const std::string &name, bool error_if_not_found, bool load_if_not_found)
Definition: cdef-utils.cc:80
cdef_manager & __get_cdef_manager__(const std::string &who)
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
std::string get_base_name(const std::string &nm)
Definition: cdef-utils.cc:44
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811