GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
cdef-property.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2012-2024 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-utils.h"
36 #include "errwarn.h"
37 #include "interpreter-private.h"
38 #include "interpreter.h"
39 #include "load-path.h"
40 #include "ov-builtin.h"
41 #include "ov-classdef.h"
42 #include "ov-fcn-handle.h"
43 #include "ov-usr-fcn.h"
44 #include "pt-assign.h"
45 #include "pt-classdef.h"
46 #include "pt-eval.h"
47 #include "pt-idx.h"
48 #include "pt-misc.h"
49 #include "pt-stmt.h"
50 #include "pt-walk.h"
51 
53 
54 static bool
55 is_method_executing (const octave_value& ov, const cdef_object& obj)
56 {
58 
59  octave_function *stack_fcn = tw.current_function ();
60 
61  octave_function *method_fcn = ov.function_value (true);
62 
63  // Does the top of the call stack match our target function?
64 
65  if (stack_fcn && stack_fcn == method_fcn)
66  {
67  octave_user_function *uf = method_fcn->user_function_value (true);
68 
69  // We can only check the context object for user-function (not builtin),
70  // where we have access to the parameters (arguments and return values).
71  // That's ok as there's no need to call this function for builtin
72  // methods.
73 
74  if (uf)
75  {
76  // At this point, the method is executing, but we still need to
77  // check the context object for which the method is executing. For
78  // methods, it's the first argument of the function; for ctors, it
79  // is the first return value.
80 
82  ? uf->return_list ()
83  : uf->parameter_list ();
84 
85  if (pl && pl->size () > 0)
86  {
87  tree_decl_elt *elt = pl->front ();
88 
89  octave_value arg0 = tw.evaluate (elt);
90 
91  if (arg0.is_defined () && arg0.type_name () == "object")
92  {
93  cdef_object arg0_obj = to_cdef (arg0);
94 
95  return obj.is (arg0_obj);
96  }
97  }
98  }
99  }
100 
101  return false;
102 }
103 
105 cdef_property::cdef_property_rep::get_value (const cdef_object& obj,
106  bool do_check_access,
107  const std::string& who) const
108 {
109  octave_value retval;
110 
111  if (do_check_access && ! check_get_access ())
112  err_property_access (who, false);
113 
114  if (! obj.is_constructed ())
115  {
116  cdef_class cls (to_cdef (get ("DefiningClass")));
117 
118  if (! obj.is_partially_constructed_for (cls))
119  error ("cannot reference properties of class '%s' for non-constructed object",
120  cls.get_name ().c_str ());
121  }
122 
123  octave_value get_fcn = get ("GetMethod");
124 
125  // FIXME: should check whether we're already in get accessor method
126 
127  if (get_fcn.isempty () || is_method_executing (get_fcn, obj))
128  retval = obj.get (get ("Name").string_value ());
129  else
130  {
131  octave_value_list args;
132 
133  args(0) = to_ov (obj);
134 
135  interpreter& interp = __get_interpreter__ ();
136 
137  args = interp.feval (get_fcn, args, 1);
138 
139  retval = args(0);
140  }
141 
142  return retval;
143 }
144 
146 cdef_property::cdef_property_rep::get_value (bool do_check_access,
147  const std::string& who) const
148 {
149  if (do_check_access && ! check_get_access ())
150  err_property_access (who, false);
151 
152  return get ("DefaultValue");
153 }
154 
155 bool
156 cdef_property::cdef_property_rep::is_recursive_set (const cdef_object& /* obj */) const
157 {
158  // FIXME: implement
159  return false;
160 }
161 
162 OCTAVE_NORETURN void
163 cdef_property::cdef_property_rep::err_property_access
164 (const std::string& from, bool is_set) const
165 {
166  octave_value acc = get (is_set ? "SetAccess" : "GetAccess");
167  std::string acc_s;
168 
169  if (acc.is_string ())
170  acc_s = acc.string_value ();
171  else
172  acc_s = "class-restricted";
173 
174  if (is_set)
175  error ("%s: property '%s' has %s access and cannot be set in this context",
176  from.c_str (), get_name ().c_str (), acc_s.c_str ());
177  else
178  error ("%s: property '%s' has %s access and cannot be obtained in this context",
179  from.c_str (), get_name ().c_str (), acc_s.c_str ());
180 }
181 
182 void
183 cdef_property::cdef_property_rep::set_value (cdef_object& obj,
184  const octave_value& val,
185  bool do_check_access,
186  const std::string& who)
187 {
188  if (do_check_access && ! check_set_access ())
189  err_property_access (who, true);
190 
191  if (! obj.is_constructed ())
192  {
193  cdef_class cls (to_cdef (get ("DefiningClass")));
194 
195  if (! obj.is_partially_constructed_for (cls))
196  error ("cannot reference properties of class '%s' for non-constructed object",
197  cls.get_name ().c_str ());
198  }
199 
200  octave_value set_fcn = get ("SetMethod");
201 
202  if (set_fcn.isempty () || is_method_executing (set_fcn, obj))
203  obj.put (get ("Name").string_value (), val);
204  else
205  {
206  octave_value_list args;
207 
208  args(0) = to_ov (obj);
209  args(1) = val;
210 
211  interpreter& interp = __get_interpreter__ ();
212 
213  if (obj.is_handle_object ())
214  interp.feval (set_fcn, args, 0);
215  else
216  {
217  args = interp.feval (set_fcn, args, 1);
218 
219  if (args.length () > 0 && args(0).is_defined ())
220  {
221  if (args(0).is_classdef_object ())
222  {
223  cdef_object new_obj = to_cdef (args(0));
224 
225  obj = new_obj;
226  }
227  else
228  ::warning ("set-method of property '%s' returned a non-classdef object",
229  get_name ().c_str ());
230  }
231  }
232  }
233 }
234 
235 bool
236 cdef_property::cdef_property_rep::check_get_access () const
237 {
238  cdef_class cls (to_cdef (get ("DefiningClass")));
239 
240  return check_access (cls, get ("GetAccess"), "", get_name (), false);
241 
242  return false;
243 }
244 
245 bool
246 cdef_property::cdef_property_rep::check_set_access () const
247 {
248  cdef_class cls (to_cdef (get ("DefiningClass")));
249 
250  return check_access (cls, get ("SetAccess"), "", get_name (), true);
251 
252  return false;
253 }
254 
255 OCTAVE_END_NAMESPACE(octave)
bool check_access(const cdef_class &cls, const octave_value &acc, const std::string &meth_name, const std::string &prop_name, bool is_prop_set)
Definition: cdef-utils.cc:294
cdef_object to_cdef(const octave_value &val)
Definition: cdef-utils.cc:143
octave_value to_ov(const cdef_object &obj)
Definition: cdef-utils.cc:128
elt_type & front()
Definition: base-list.h:79
std::size_t size() const
Definition: base-list.h:52
bool is_constructed() const
Definition: cdef-object.h:319
bool is_partially_constructed_for(const cdef_class &cls) const
Definition: cdef-object.h:326
bool is_handle_object() const
Definition: cdef-object.h:256
void put(const std::string &pname, const octave_value &val)
Definition: cdef-object.h:263
bool is(const cdef_object &obj) const
Definition: cdef-object.h:336
octave_value get(const std::string &pname) const
Definition: cdef-object.h:268
octave_value_list feval(const char *name, const octave_value_list &args=octave_value_list(), int nargout=0)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
virtual octave_user_function * user_function_value(bool silent=false)
Definition: ov-base.cc:949
bool is_classdef_constructor(const std::string &cname="") const
Definition: ov-usr-fcn.h:349
octave::tree_parameter_list * parameter_list()
Definition: ov-usr-fcn.h:384
octave::tree_parameter_list * return_list()
Definition: ov-usr-fcn.h:386
octave_idx_type length() const
Definition: ovl.h:113
bool is_string() const
Definition: ov.h:637
bool is_defined() const
Definition: ov.h:592
bool isempty() const
Definition: ov.h:601
octave_function * function_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:974
std::string type_name() const
Definition: ov.h:1345
octave_value evaluate(tree_decl_elt *)
Definition: pt-eval.cc:1850
octave_function * current_function(bool skip_first=false) const
Definition: pt-eval.cc:2561
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void warning(const char *fmt,...)
Definition: error.cc:1063
void() error(const char *fmt,...)
Definition: error.cc:988
interpreter & __get_interpreter__()
tree_evaluator & __get_evaluator__()