GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
pt-idx.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-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 "Cell.h"
31 #include "error.h"
32 #include "interpreter-private.h"
33 #include "oct-map.h"
34 #include "ovl.h"
35 #include "oct-lvalue.h"
36 #include "ov.h"
37 #include "pt-arg-list.h"
38 #include "pt-eval.h"
39 #include "pt-id.h"
40 #include "pt-idx.h"
41 #include "utils.h"
42 #include "variables.h"
43 #include "errwarn.h"
44 
45 namespace octave
46 {
47  // Index expressions.
48 
50  : tree_expression (l, c), m_expr (nullptr), m_args (0), m_type (),
51  m_arg_nm (), m_dyn_field (), m_word_list_cmd (false) { }
52 
54  tree_argument_list *lst,
55  int l, int c, char t)
56  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
57  m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
58  {
59  append (lst, t);
60  }
61 
63  const std::string& n,
64  int l, int c)
65  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
66  m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
67  {
68  append (n);
69  }
70 
72  tree_expression *df,
73  int l, int c)
74  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
75  m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
76  {
77  append (df);
78  }
79 
80  void
82  {
83  m_args.push_back (lst);
84  m_type.append (1, t);
85  m_arg_nm.push_back (lst ? lst->get_arg_names () : string_vector ());
86  m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
87 
88  if (lst && lst->has_magic_tilde ())
89  error ("invalid use of empty argument (~) in index expression");
90  }
91 
92  void
93  tree_index_expression::append (const std::string& n)
94  {
95  m_args.push_back (static_cast<tree_argument_list *> (nullptr));
96  m_type += '.';
97  m_arg_nm.push_back (n);
98  m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
99  }
100 
101  void
103  {
104  m_args.push_back (static_cast<tree_argument_list *> (nullptr));
105  m_type += '.';
106  m_arg_nm.push_back ("");
107  m_dyn_field.push_back (df);
108  }
109 
111  {
112  delete m_expr;
113 
114  while (! m_args.empty ())
115  {
116  auto p = m_args.begin ();
117  delete *p;
118  m_args.erase (p);
119  }
120 
121  while (! m_dyn_field.empty ())
122  {
123  auto p = m_dyn_field.begin ();
124  delete *p;
125  m_dyn_field.erase (p);
126  }
127  }
128 
129  // This is useful for printing the name of the variable in an indexed
130  // assignment.
131 
132  std::string
134  {
135  return m_expr->name ();
136  }
137 
138  std::string
140  (tree_evaluator& tw,
141  std::list<string_vector>::const_iterator p_arg_nm,
142  std::list<tree_expression *>::const_iterator p_dyn_field) const
143  {
144  std::string fn = (*p_arg_nm)(0);
145 
146  if (fn.empty ())
147  {
148  tree_expression *df = *p_dyn_field;
149 
150  if (df)
151  {
152  octave_value t = df->evaluate (tw);
153 
154  fn = t.xstring_value ("dynamic structure field names must be strings");
155  }
156  else
157  panic_impossible ();
158  }
159 
160  return fn;
161  }
162 
165  {
166  std::list<octave_value_list> idx;
167 
168  int n = m_args.size ();
169 
170  auto p_args = m_args.begin ();
171  auto p_arg_nm = m_arg_nm.begin ();
172  auto p_dyn_field = m_dyn_field.begin ();
173 
175 
177  act ([&tw] (const octave_value& val,
178  const std::string& index_type,
179  const std::list<octave_value_list>& index_list)
180  {
181  tw.set_indexed_object (val);
182  tw.set_index_list (index_type, index_list);
183  }, tw.indexed_object (), tw.index_type (), tw.index_list ());
184 
185  tw.set_indexed_object (retval.value ());
186  tw.clear_index_list ();
187 
188  for (int i = 0; i < n; i++)
189  {
190  switch (m_type[i])
191  {
192  case '(':
193  {
194  octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
195 
196  tw.append_index_list ('(', tidx);
197  idx.push_back (tidx);
198  }
199  break;
200 
201  case '{':
202  {
203  octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
204 
205  tw.append_index_list ('{', tidx);
206  idx.push_back (tidx);
207  }
208  break;
209 
210  case '.':
211  {
212  octave_value tidx = get_struct_index (tw, p_arg_nm, p_dyn_field);
213 
214  tw.append_index_list ('.', tidx);
215  idx.push_back (tidx);
216  }
217  break;
218 
219  default:
220  panic_impossible ();
221  }
222 
223  if (idx.back ().empty ())
224  error ("invalid empty index list");
225 
226  p_args++;
227  p_arg_nm++;
228  p_dyn_field++;
229  }
230 
231  retval.set_index (m_type, idx);
232 
233  return retval;
234  }
235 
238  {
239  tree_index_expression *new_idx_expr
240  = new tree_index_expression (line (), column ());
241 
242  new_idx_expr->m_expr = (m_expr ? m_expr->dup (scope) : nullptr);
243 
244  std::list<tree_argument_list *> new_args;
245 
246  for (const tree_argument_list *elt : m_args)
247  new_args.push_back (elt ? elt->dup (scope) : nullptr);
248 
249  new_idx_expr->m_args = new_args;
250 
251  new_idx_expr->m_type = m_type;
252 
253  new_idx_expr->m_arg_nm = m_arg_nm;
254 
255  std::list<tree_expression *> new_dyn_field;
256 
257  for (const tree_expression *elt : m_dyn_field)
258  new_dyn_field.push_back (elt ? elt->dup (scope) : nullptr);
259 
260  new_idx_expr->m_dyn_field = new_dyn_field;
261 
262  new_idx_expr->copy_base (*this);
263 
264  return new_idx_expr;
265  }
266 
267  // Unlike Matlab, which does not allow the result of a function call
268  // or array indexing expression to be further indexed, Octave attempts
269  // to handle arbitrary index expressions. For example, Octave allows
270  // expressions like
271  //
272  // svd (rand (10))(1:5)
273  //
274  // Although octave_value objects may contain function objects, no
275  // indexing operation or function call is supposed to return them
276  // directly. Instead, the language is supposed to only allow function
277  // objects to be stored as function handles (named or anonymous) or as
278  // inline functions. The only place a function object should appear
279  // directly is if the symbol stored in a tree_identifier object
280  // resolves to a function. This means that the only place we need to
281  // look for functions is in the first element of the index
282  // expression.
283  //
284  // Steps:
285  //
286  // * Obtain the initial value from the expression component of the
287  // tree_index_expression object. If it is a tree_identifier object
288  // indexed by '(args)' and the identifier is not a variable, then
289  // perform a function call. Use the (optional) arguments to perform
290  // the function lookup so we choose the correct function or class
291  // method to call. Otherwise, evaluate the first expression
292  // without any additional arguments.
293  //
294  // * Iterate over the remaining elements of the index expression and
295  // call the octave_value::subsref method. If indexing a class or
296  // classdef object, build up a list of indices for a call to the
297  // subsref method for the object. Otherwise, use the result of
298  // each temporary evaluation for the next index element.
299  //
300  // * If not indexing a class or classdef object and any partial
301  // expression evaluation produces a class or classdef object, then
302  // build up a complete argument list from that point on for a final
303  // subsref call for that object.
304  //
305  // Multiple partial evaluations may be required. For example,
306  // given a class or classdef object X, then for the expression
307  //
308  // x.a{end}(2:end).b
309  //
310  // we must evaluate x.a to obtain the size for the first {end}
311  // expression, then we must evaluate x.a{end} to obtain the size
312  // for the second (2:end) expression. Finally, the complete
313  // expression may be evaluated.
314  //
315  // If X is a cell array in the above expression, and none of the
316  // intermediate evaluations produces a class or classdef object,
317  // then the evaluation is performed as the following series of
318  // steps
319  //
320  // tmp = x.a
321  // tmp = tmp{end}
322  // tmp = tmp(2:end)
323  // result = tmp.b
324  //
325  // If any of the partial evaluations produces a class or classdef
326  // object, then the subsref method for that object is called as
327  // described above. For example, suppose x.a produces a classdef
328  // object. Then the evaluation is performed as the following
329  // series of steps
330  //
331  // base_expr = tmp = x.a
332  // tmp = base_expr{end}
333  // base_expr{end}(2:end).b
334  //
335  // In the last two steps, the partial value computed in the
336  // previous step is used to determine the value of END.
337 
340  {
342 
343  assert (! m_args.empty ());
344 
345  auto p_args = m_args.begin ();
346  auto p_arg_nm = m_arg_nm.begin ();
347  auto p_dyn_field = m_dyn_field.begin ();
348 
349  int n = m_args.size ();
350  int beg = 0;
351 
352  octave_value base_expr_val;
353 
354  if (m_expr->is_identifier () && m_type[beg] == '(')
355  {
356  tree_identifier *id = dynamic_cast<tree_identifier *> (m_expr);
357 
358  bool is_var = tw.is_variable (m_expr);
359 
360  std::string nm = id->name ();
361 
362  if (is_var && is_word_list_cmd ())
363  error ("%s used as variable and later as function", nm.c_str ());
364 
365  if (! is_var)
366  {
367  octave_value_list first_args;
368 
369  tree_argument_list *al = *p_args;
370 
371  if (al && al->length () > 0)
372  {
373  unwind_action act ([&tw] (const std::list<octave_lvalue> *lvl)
374  {
375  tw.set_lvalue_list (lvl);
376  }, tw.lvalue_list ());
377 
378  tw.set_lvalue_list (nullptr);
379 
380  string_vector anm = *p_arg_nm;
381 
382  first_args = tw.convert_to_const_vector (al);
383 
384  first_args.stash_name_tags (anm);
385  }
386 
387  interpreter& interp = tw.get_interpreter ();
388 
389  symbol_table& symtab = interp.get_symbol_table ();
390 
391  octave_value val = symtab.find_function (nm, first_args);
392 
393  octave_function *fcn = nullptr;
394 
395  if (val.is_function ())
396  fcn = val.function_value (true);
397 
398  if (fcn)
399  {
400  try
401  {
402  retval = fcn->call (tw, nargout, first_args);
403  }
404  catch (index_exception& e)
405  {
406  tw.final_index_error (e, m_expr);
407  }
408 
409  beg++;
410  p_args++;
411  p_arg_nm++;
412  p_dyn_field++;
413 
414  if (n > beg)
415  {
416  // More indices to follow. Silently ignore
417  // extra output values.
418 
419  if (retval.length () == 0)
420  error ("indexing undefined value");
421  else
422  base_expr_val = retval(0);
423  }
424  else
425  {
426  // No more indices, so we are done.
427 
428  // See note at end of function about deleting
429  // temporaries prior to pushing result.
430 
431  base_expr_val = octave_value ();
432  first_args = octave_value_list ();
433 
434  return retval;
435  }
436  }
437  }
438  }
439 
440  if (base_expr_val.is_undefined ())
441  base_expr_val = m_expr->evaluate (tw);
442 
443  // If we are indexing an object or looking at something like
444  //
445  // classname.static_function (args, ...);
446  //
447  // then we'll just build a complete index list for one big subsref
448  // call. If the expression we are indexing is a classname then
449  // base_expr_val will be an octave_classdef_meta object. If we have
450  // files in a +packagename folder, they will also be an
451  // octave_classdef_meta object, but we don't want to index them.
452 
453  std::list<octave_value_list> idx_list;
454 
455  {
456  // Note: need new scope so that the following unwind action will
457  // happen before we perform the final indexing for objects (for
458  // example).
459 
461  act ([&tw] (const octave_value& val,
462  const std::string& index_type,
463  const std::list<octave_value_list>& index_list)
464  {
465  tw.set_indexed_object (val);
466  tw.set_index_list (index_type, index_list);
467  },
468  tw.indexed_object (),
469  tw.index_type (), tw.index_list ());
470 
471  tw.set_indexed_object ();
472  tw.clear_index_list ();
473 
474  bool indexing_object = (base_expr_val.isobject ()
475  || base_expr_val.isjava ()
476  || (base_expr_val.is_classdef_meta ()
477  && ! base_expr_val.is_package ()));
478 
479  octave_value partial_expr_val = base_expr_val;
480 
481  for (int i = beg; i < n; i++)
482  {
483  if (i > beg)
484  {
485  if (! indexing_object)
486  {
487  // Evaluate what we have so far.
488 
489  try
490  {
491  // Silently ignore extra output values.
492 
493  octave_value_list tmp_list
494  = base_expr_val.subsref (m_type.substr (beg, i-beg),
495  idx_list, nargout);
496 
497  partial_expr_val
498  = tmp_list.length () ? tmp_list(0) : octave_value ();
499 
500  base_expr_val = partial_expr_val;
501 
502  if (partial_expr_val.is_cs_list ())
504 
505  retval = partial_expr_val;
506 
507  beg = i;
508  idx_list.clear ();
509  tw.clear_index_list ();
510 
511  if (partial_expr_val.isobject ()
512  || partial_expr_val.isjava ()
513  || (partial_expr_val.is_classdef_meta ()
514  && ! partial_expr_val.is_package ()))
515  {
516  // Found an object, so now we'll build up
517  // complete index list for one big subsref
518  // call from this point on.
519 
520  // FIXME: is is also possible to have a
521  // static method call buried somewhere in
522  // the depths of a complex indexing
523  // expression so that we would also need to
524  // check for an octave_classdef_meta object
525  // here?
526 
527  indexing_object = true;
528  }
529  }
530  catch (index_exception& e)
531  {
532  tw.final_index_error (e, m_expr);
533  }
534  }
535  }
536 
537  tw.set_indexed_object (partial_expr_val);
538 
539  switch (m_type[i])
540  {
541  case '(':
542  {
543  octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
544  tw.append_index_list ('(', tmp);
545  idx_list.push_back (tmp);
546  }
547  break;
548 
549  case '{':
550  {
551  octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
552  tw.append_index_list ('{', tmp);
553  idx_list.push_back (tmp);
554  }
555  break;
556 
557  case '.':
558  {
559  octave_value tmp = get_struct_index (tw, p_arg_nm, p_dyn_field);
560  tw.append_index_list ('.', tmp);
561  idx_list.push_back (tmp);
562  }
563  break;
564 
565  default:
566  panic_impossible ();
567  }
568 
569  p_args++;
570  p_arg_nm++;
571  p_dyn_field++;
572  }
573  }
574 
575  // If ! idx_list.empty () that means we still have stuff to index
576  // otherwise they would have been dealt with and idx_list would have
577  // been emptied.
578  if (! idx_list.empty ())
579  {
580  // This is for +package and other classdef_meta objects
581  if (! base_expr_val.is_function ()
582  || base_expr_val.is_classdef_meta ())
583  {
584  try
585  {
586  retval = base_expr_val.subsref (m_type.substr (beg, n-beg),
587  idx_list, nargout);
588  beg = n;
589  idx_list.clear ();
590  }
591  catch (index_exception& e)
592  {
593  tw.final_index_error (e, m_expr);
594  }
595  }
596  else
597  {
598  // FIXME: we want this to only be a superclass constructor
599  // call Should we actually make a check for this or are all
600  // other types of calls already dealt with?
601 
602  octave_function *fcn = base_expr_val.function_value ();
603 
604  if (fcn)
605  {
606  try
607  {
608  // FIXME: is it possible for the IDX_LIST to have
609  // more than one element here? Do we need to check?
610 
611  octave_value_list final_args;
612 
613  if (idx_list.size () != 1)
614  error ("unexpected extra index at end of expression");
615 
616  if (m_type[beg] != '(')
617  error ("invalid index type '%c' for function call",
618  m_type[beg]);
619 
620  final_args = idx_list.front ();
621 
622  // FIXME: Do we ever need the names of the arguments
623  // passed to FCN here?
624 
625  retval = fcn->call (tw, nargout, final_args);
626  }
627  catch (index_exception& e)
628  {
629  tw.final_index_error (e, m_expr);
630  }
631  }
632  }
633  }
634 
635  // FIXME: when can the following happen? In what case does indexing
636  // result in a value that is a function? Classdef method calls?
637  // Something else?
638 
639  octave_value val = (retval.length () ? retval(0) : octave_value ());
640 
641  if (val.is_function ())
642  {
643  octave_function *fcn = val.function_value (true);
644 
645  if (fcn)
646  {
647  octave_value_list final_args;
648 
649  if (! idx_list.empty ())
650  {
651  if (n - beg != 1)
652  error ("unexpected extra index at end of expression");
653 
654  if (m_type[beg] != '(')
655  error ("invalid index type '%c' for function call",
656  m_type[beg]);
657 
658  final_args = idx_list.front ();
659  }
660 
661  retval = fcn->call (tw, nargout, final_args);
662  }
663  }
664 
665  // Delete any temporary values prior to returning so that
666  // destructors for any temporary classdef handle objects will be
667  // called before we return.
668 
669  idx_list.clear ();
670  base_expr_val = octave_value ();
671  val = octave_value ();
672 
673  return retval;
674  }
675 }
676 
677 /*
678 %!test
679 %! clear x;
680 %! clear y;
681 %! y = 3;
682 %! x(y(end)) = 1;
683 %! assert (x, [0, 0, 1]);
684 %! clear x;
685 %! clear y;
686 %! y = {3};
687 %! x(y{end}) = 1;
688 %! assert (x, [0, 0, 1]);
689 
690 %!test
691 %! x = {1, 2, 3};
692 %! [x{:}] = deal (4, 5, 6);
693 %! assert (x, {4, 5, 6});
694 
695 %!test
696 %! [x.a, x.b.c] = deal (1, 2);
697 %! assert (x.a == 1 && x.b.c == 2);
698 
699 %!test
700 %! [x.a, x(2).b] = deal (1, 2);
701 %! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
702 
703 %!test
704 %! x = struct (zeros (0, 1), {"a", "b"});
705 %! x(2).b = 1;
706 %! assert (x(2).b == 1);
707 
708 %!test
709 %! x = struct (zeros (0, 1), {"a", "b"});
710 %! x(2).b = 1;
711 %! assert (x(2).b == 1);
712 */
size_t length(void) const
Definition: base-list.h:53
symbol_table & get_symbol_table(void)
Definition: interpreter.h:258
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
string_vector get_arg_names(void) const
Definition: pt-arg-list.cc:101
bool has_magic_tilde(void) const
Definition: pt-arg-list.h:72
void set_lvalue_list(const std::list< octave_lvalue > *lst)
Definition: pt-eval.h:678
bool is_variable(const std::string &name) const
Definition: pt-eval.cc:1255
void set_index_list(const std::string &index_type, const std::list< octave_value_list > &index_list)
Definition: pt-eval.h:643
const std::list< octave_lvalue > * lvalue_list(void) const
Definition: pt-eval.h:673
void append_index_list(char type, const octave_value_list &idx)
Definition: pt-eval.h:656
void final_index_error(index_exception &e, const tree_expression *expr)
Definition: pt-eval.cc:3768
void set_indexed_object(const octave_value &obj=octave_value())
Definition: pt-eval.h:633
void clear_index_list(void)
Definition: pt-eval.h:650
const std::list< octave_value_list > & index_list(void) const
Definition: pt-eval.h:638
const std::string & index_type(void) const
Definition: pt-eval.h:662
octave_value_list convert_to_const_vector(tree_argument_list *arg_list)
Definition: pt-eval.cc:1685
octave_value indexed_object(void) const
Definition: pt-eval.h:628
octave_value_list make_value_list(tree_argument_list *args, const string_vector &arg_nm)
Definition: pt-eval.cc:3806
interpreter & get_interpreter(void)
Definition: pt-eval.h:370
virtual bool is_identifier(void) const
Definition: pt-exp.h:70
virtual void copy_base(const tree_expression &e)
Definition: pt-exp.h:131
virtual tree_expression * dup(symbol_scope &scope) const =0
virtual octave_lvalue lvalue(tree_evaluator &)
Definition: pt-exp.cc:43
virtual std::string name(void) const
Definition: pt-exp.h:103
virtual octave_value evaluate(tree_evaluator &tw, int nargout=1)=0
bool is_word_list_cmd(void) const
Definition: pt-idx.h:95
tree_index_expression * dup(symbol_scope &scope) const
Definition: pt-idx.cc:237
std::string get_struct_index(tree_evaluator &tw, std::list< string_vector >::const_iterator p_arg_nm, std::list< tree_expression * >::const_iterator p_dyn_field) const
Definition: pt-idx.cc:140
tree_index_expression(tree_expression *e=nullptr, tree_argument_list *lst=nullptr, int l=-1, int c=-1, char t='(')
Definition: pt-idx.cc:53
octave_lvalue lvalue(tree_evaluator &tw)
Definition: pt-idx.cc:164
std::list< tree_expression * > m_dyn_field
Definition: pt-idx.h:140
tree_expression * m_expr
Definition: pt-idx.h:127
std::string name(void) const
Definition: pt-idx.cc:133
octave_value_list evaluate_n(tree_evaluator &tw, int nargout=1)
Definition: pt-idx.cc:339
std::list< tree_argument_list * > m_args
Definition: pt-idx.h:130
std::list< string_vector > m_arg_nm
Definition: pt-idx.h:137
void append(tree_argument_list *lst=nullptr, char t='(')
Definition: pt-idx.cc:81
virtual int column(void) const
Definition: pt.h:62
virtual octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition: ov-fcn.cc:50
void stash_name_tags(const string_vector &nm)
Definition: ovl.h:165
octave_idx_type length(void) const
Definition: ovl.h:113
void clear(void)
Definition: ovl.h:173
bool is_function(void) const
Definition: ov.h:730
bool is_package(void) const
Definition: ov.h:617
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:449
bool is_cs_list(void) const
Definition: ov.h:626
bool is_classdef_meta(void) const
Definition: ov.h:608
octave_function * function_value(bool silent=false) const
bool isjava(void) const
Definition: ov.h:623
bool isobject(void) const
Definition: ov.h:620
std::string xstring_value(const char *fmt,...) const
bool is_undefined(void) const
Definition: ov.h:554
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
void err_indexed_cs_list(void)
Definition: errwarn.cc:65
octave_idx_type n
Definition: mx-inlines.cc:753
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