GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
pt-idx.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "Cell.h"
28 #include "error.h"
29 #include "oct-map.h"
30 #include "ovl.h"
31 #include "oct-lvalue.h"
32 #include "ov.h"
33 #include "pager.h"
34 #include "pt-arg-list.h"
35 #include "pt-bp.h"
36 #include "pt-id.h"
37 #include "pt-idx.h"
38 #include "pt-walk.h"
39 #include "utils.h"
40 #include "variables.h"
41 #include "errwarn.h"
42 
43 // Index expressions.
44 
46  : tree_expression (l, c), expr (0), args (0), type (),
47  arg_nm (), dyn_field () { }
48 
50  tree_argument_list *lst,
51  int l, int c, char t)
52  : tree_expression (l, c), expr (e), args (0), type (),
53  arg_nm (), dyn_field ()
54 {
55  append (lst, t);
56 }
57 
59  const std::string& n,
60  int l, int c)
61  : tree_expression (l, c), expr (e), args (0), type (),
62  arg_nm (), dyn_field ()
63 {
64  append (n);
65 }
66 
68  tree_expression *df,
69  int l, int c)
70  : tree_expression (l, c), expr (e), args (0), type (),
71  arg_nm (), dyn_field ()
72 {
73  append (df);
74 }
75 
76 void
78 {
79  args.push_back (lst);
80  type.append (1, t);
81  arg_nm.push_back (lst ? lst->get_arg_names () : string_vector ());
82  dyn_field.push_back (static_cast<tree_expression *> (0));
83 
84  if (lst && lst->has_magic_tilde ())
85  error ("invalid use of empty argument (~) in index expression");
86 }
87 
88 void
90 {
91  args.push_back (static_cast<tree_argument_list *> (0));
92  type.append (".");
93  arg_nm.push_back (n);
94  dyn_field.push_back (static_cast<tree_expression *> (0));
95 }
96 
97 void
99 {
100  args.push_back (static_cast<tree_argument_list *> (0));
101  type.append (".");
102  arg_nm.push_back ("");
103  dyn_field.push_back (df);
104 }
105 
107 {
108  delete expr;
109 
110  while (! args.empty ())
111  {
112  std::list<tree_argument_list *>::iterator p = args.begin ();
113  delete *p;
114  args.erase (p);
115  }
116 
117  while (! dyn_field.empty ())
118  {
119  std::list<tree_expression *>::iterator p = dyn_field.begin ();
120  delete *p;
121  dyn_field.erase (p);
122  }
123 }
124 
125 bool
127 {
128  for (std::list<tree_argument_list *>::const_iterator p = args.begin ();
129  p != args.end ();
130  p++)
131  {
132  tree_argument_list *elt = *p;
133 
134  if (elt && elt->has_magic_end ())
135  return true;
136  }
137 
138  return false;
139 }
140 
141 // This is useful for printing the name of the variable in an indexed
142 // assignment.
143 
146 {
147  return expr->name ();
148 }
149 
150 static Cell
152 {
153  Cell retval;
154 
155  octave_value_list arg_values;
156 
157  if (args)
158  arg_values = args->convert_to_const_vector ();
159 
160  int n = arg_values.length ();
161 
162  if (n > 0)
163  {
164  arg_values.stash_name_tags (arg_nm);
165 
166  retval.resize (dim_vector (1, n));
167 
168  for (int i = 0; i < n; i++)
169  retval(0,i) = arg_values(i);
170  }
171 
172  return retval;
173 }
174 
175 static inline octave_value_list
177  const octave_value *object, bool rvalue = true)
178 {
180 
181  if (args)
182  {
183  if (rvalue && object && args->has_magic_end () && object->is_undefined ())
185 
186  retval = args->convert_to_const_vector (object);
187  }
188 
189  octave_idx_type n = retval.length ();
190 
191  if (n > 0)
192  retval.stash_name_tags (arg_nm);
193 
194  return retval;
195 }
196 
199  (std::list<string_vector>::const_iterator p_arg_nm,
200  std::list<tree_expression *>::const_iterator p_dyn_field) const
201 {
202  std::string fn = (*p_arg_nm)(0);
203 
204  if (fn.empty ())
205  {
206  tree_expression *df = *p_dyn_field;
207 
208  if (df)
209  {
210  octave_value t = df->rvalue1 ();
211 
212  fn = t.xstring_value ("dynamic structure field names must be strings");
213  }
214  else
215  panic_impossible ();
216  }
217 
218  return fn;
219 }
220 
223 {
224  int n = args.size ();
225 
226  Cell type_field (n, 1);
227  Cell subs_field (n, 1);
228 
229  std::list<tree_argument_list *>::const_iterator p_args = args.begin ();
230  std::list<string_vector>::const_iterator p_arg_nm = arg_nm.begin ();
231  std::list<tree_expression *>::const_iterator p_dyn_field = dyn_field.begin ();
232 
233  octave_map m;
234 
235  for (int i = 0; i < n; i++)
236  {
237  switch (type[i])
238  {
239  case '(':
240  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
241  break;
242 
243  case '{':
244  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
245  break;
246 
247  case '.':
248  subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field);
249  break;
250 
251  default:
252  panic_impossible ();
253  }
254 
255  p_args++;
256  p_arg_nm++;
257  p_dyn_field++;
258  }
259 
260  m.assign ("type", type_field);
261  m.assign ("subs", subs_field);
262 
263  return m;
264 }
265 
268 {
269  return tree_index_expression::rvalue (nargout, 0);
270 }
271 
272 // Final step of processing an indexing error. Add the name of the
273 // variable being indexed, if any, then issue an error. (Will this also
274 // be needed by pt-lvalue, which calls subsref?)
275 
276 static void
278 {
279  if (expr->is_identifier ()
280  && dynamic_cast<const tree_identifier *> (expr)->is_variable ())
281  e.set_var (expr->name ());
282 
283  std::string msg = e.message ();
284  error_with_id (e.err_id (), msg.c_str ());
285 }
286 
289  const std::list<octave_lvalue> *lvalue_list)
290 {
292 
293  octave_value first_expr_val;
294 
295  octave_value_list first_args;
296 
297  bool have_args = false;
298 
299  if (expr->is_identifier () && type[0] == '(')
300  {
301  tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
302 
303  if (! (id->is_variable () || args.empty ()))
304  {
305  tree_argument_list *al = *(args.begin ());
306 
307  size_t n = al ? al->length () : 0;
308 
309  if (n > 0)
310  {
311  string_vector anm = *(arg_nm.begin ());
312  have_args = true;
313  first_args = al -> convert_to_const_vector ();
314  first_args.stash_name_tags (anm);
315 
316  first_expr_val = id->do_lookup (first_args);
317  }
318  }
319  }
320 
321  if (first_expr_val.is_undefined ())
322  first_expr_val = expr->rvalue1 ();
323 
324  octave_value tmp = first_expr_val;
325  octave_idx_type tmpi = 0;
326 
327  std::list<octave_value_list> idx;
328 
329  int n = args.size ();
330 
331  std::list<tree_argument_list *>::iterator p_args = args.begin ();
332  std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
333  std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
334 
335  for (int i = 0; i < n; i++)
336  {
337  if (i > 0)
338  {
339  tree_argument_list *al = *p_args;
340 
341  // In Matlab, () can only be followed by '.'. In Octave, we do not
342  // enforce this for rvalue expressions, but we'll split the
343  // evaluation at this point. This will, hopefully, allow Octave's
344  // looser rules apply smoothly for Matlab overloaded subsref
345  // codes.
346  bool force_split = type[i-1] == '(' && type[i] != '.';
347 
348  if (force_split || (al && al->has_magic_end ()))
349  {
350  // (we have force_split, or) we have an expression like
351  //
352  // x{end}.a(end)
353  //
354  // and we are looking at the argument list that
355  // contains the second (or third, etc.) "end" token,
356  // so we must evaluate everything up to the point of
357  // that argument list so we can pass the appropriate
358  // value to the built-in end function.
359 
360  try
361  {
362  octave_value_list tmp_list
363  =tmp.subsref (type.substr (tmpi, i-tmpi), idx, nargout);
364 
365  tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
366  tmpi = i;
367  idx.clear ();
368 
369  if (tmp.is_cs_list ())
371 
372  if (tmp.is_function ())
373  {
374  octave_function *fcn = tmp.function_value (true);
375 
376  if (fcn && ! fcn->is_postfix_index_handled (type[i]))
377  {
378  octave_value_list empty_args;
379 
380  tmp_list = tmp.do_multi_index_op (1, empty_args);
381  tmp = (tmp_list.length ()
382  ? tmp_list(0) : octave_value ());
383 
384  if (tmp.is_cs_list ())
386  }
387  }
388  }
389  catch (octave::index_exception& e) // problems with index range, type etc.
390  {
391  final_index_error (e, expr);
392  }
393  }
394  }
395 
396  switch (type[i])
397  {
398  case '(':
399  if (have_args)
400  {
401  idx.push_back (first_args);
402  have_args = false;
403  }
404  else
405  idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
406  break;
407 
408  case '{':
409  idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
410  break;
411 
412  case '.':
413  idx.push_back (octave_value (get_struct_index (p_arg_nm,
414  p_dyn_field)));
415  break;
416 
417  default:
418  panic_impossible ();
419  }
420 
421  p_args++;
422  p_arg_nm++;
423  p_dyn_field++;
424  }
425 
426  try
427  {
428  retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
429  lvalue_list);
430  }
431  catch (octave::index_exception& e) // range problems, bad index type, etc.
432  {
433  final_index_error (e, expr);
434  }
435 
436  octave_value val = retval.length () ? retval(0) : octave_value ();
437 
438  if (val.is_function ())
439  {
440  octave_function *fcn = val.function_value (true);
441 
442  if (fcn)
443  {
444  octave_value_list empty_args;
445 
446  retval = (lvalue_list
447  ? val.do_multi_index_op (nargout, empty_args,
448  lvalue_list)
449  : val.do_multi_index_op (nargout, empty_args));
450  }
451  }
452 
453  return retval;
454 }
455 
458 {
460 
461  const octave_value_list tmp = rvalue (nargout);
462 
463  if (! tmp.empty ())
464  retval = tmp(0);
465 
466  return retval;
467 }
468 
471 {
473 
474  std::list<octave_value_list> idx;
475  std::string tmp_type;
476 
477  int n = args.size ();
478 
479  std::list<tree_argument_list *>::iterator p_args = args.begin ();
480  std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
481  std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
482 
483  retval = expr->lvalue ();
484 
485  octave_value tmp = retval.value ();
486 
487  octave_idx_type tmpi = 0;
488  std::list<octave_value_list> tmpidx;
489 
490  for (int i = 0; i < n; i++)
491  {
492  if (retval.numel () != 1)
494 
495  if (tmpi < i)
496  {
497  try
498  {
499  tmp = tmp.subsref (type.substr (tmpi, i-tmpi), tmpidx, true);
500  }
501  catch (octave::index_exception& e) // problems with range, invalid type etc.
502  {
503  final_index_error (e, expr);
504  }
505 
506  tmpidx.clear ();
507  }
508 
509  switch (type[i])
510  {
511  case '(':
512  {
513  octave_value_list tidx
514  = make_value_list (*p_args, *p_arg_nm, &tmp, false);
515 
516  idx.push_back (tidx);
517 
518  if (i < n - 1)
519  {
520  if (type[i+1] != '.')
521  error ("() must be followed by . or close the index chain");
522 
523  tmpidx.push_back (tidx);
524  tmpi = i+1;
525  }
526  }
527  break;
528 
529  case '{':
530  {
531  octave_value_list tidx
532  = make_value_list (*p_args, *p_arg_nm, &tmp, false);
533 
534  if (tmp.is_undefined ())
535  {
536  if (tidx.has_magic_colon ())
538 
539  tmp = Cell ();
540  }
541  else if (tmp.is_zero_by_zero ()
542  && (tmp.is_matrix_type () || tmp.is_string ()))
543  {
544  tmp = Cell ();
545  }
546 
547  retval.numel (tmp.numel (tidx));
548 
549  idx.push_back (tidx);
550  tmpidx.push_back (tidx);
551  tmpi = i;
552  }
553  break;
554 
555  case '.':
556  {
557  octave_value tidx = get_struct_index (p_arg_nm, p_dyn_field);
558 
559  bool autoconv = (tmp.is_zero_by_zero ()
560  && (tmp.is_matrix_type () || tmp.is_string ()
561  || tmp.is_cell ()));
562 
563  if (i > 0 && type[i-1] == '(')
564  {
565  octave_value_list pidx = idx.back ();
566 
567  // Use octave_map, not octave_scalar_map so that the
568  // dimensions are 0x0, not 1x1.
569  if (tmp.is_undefined ())
570  {
571  if (pidx.has_magic_colon ())
573 
574  tmp = octave_map ();
575  }
576  else if (autoconv)
577  tmp = octave_map ();
578 
579  retval.numel (tmp.numel (pidx));
580 
581  tmpi = i-1;
582  tmpidx.push_back (tidx);
583  }
584  else
585  {
586  if (tmp.is_undefined () || autoconv)
587  {
588  tmpi = i+1;
589  tmp = octave_value ();
590  }
591  else
592  {
593  retval.numel (tmp.numel (octave_value_list ()));
594 
595  tmpi = i;
596  tmpidx.push_back (tidx);
597  }
598  }
599 
600  idx.push_back (tidx);
601  }
602  break;
603 
604  default:
605  panic_impossible ();
606  }
607 
608  if (idx.back ().empty ())
609  error ("invalid empty index list");
610 
611  p_args++;
612  p_arg_nm++;
613  p_dyn_field++;
614  }
615 
616  retval.set_index (type, idx);
617 
618  return retval;
619 }
620 
621 /*
622 %!test
623 %! clear x;
624 %! clear y;
625 %! y = 3;
626 %! x(y(end)) = 1;
627 %! assert (x, [0, 0, 1]);
628 %! clear x;
629 %! clear y;
630 %! y = {3};
631 %! x(y{end}) = 1;
632 %! assert (x, [0, 0, 1]);
633 
634 %!test
635 %! x = {1, 2, 3};
636 %! [x{:}] = deal (4, 5, 6);
637 %! assert (x, {4, 5, 6});
638 
639 %!test
640 %! [x.a, x.b.c] = deal (1, 2);
641 %! assert (x.a == 1 && x.b.c == 2);
642 
643 %!test
644 %! [x.a, x(2).b] = deal (1, 2);
645 %! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
646 
647 %!test
648 %! x = struct (zeros (0, 1), {"a", "b"});
649 %! x(2).b = 1;
650 %! assert (x(2).b == 1);
651 
652 %!test
653 %! x = struct (zeros (0, 1), {"a", "b"});
654 %! x(2).b = 1;
655 %! assert (x(2).b == 1);
656 */
657 
661 {
662  tree_index_expression *new_idx_expr
663  = new tree_index_expression (line (), column ());
664 
665  new_idx_expr->expr = expr ? expr->dup (scope, context) : 0;
666 
667  std::list<tree_argument_list *> new_args;
668 
669  for (std::list<tree_argument_list *>::const_iterator p = args.begin ();
670  p != args.end ();
671  p++)
672  {
673  const tree_argument_list *elt = *p;
674 
675  new_args.push_back (elt ? elt->dup (scope, context) : 0);
676  }
677 
678  new_idx_expr->args = new_args;
679 
680  new_idx_expr->type = type;
681 
682  new_idx_expr->arg_nm = arg_nm;
683 
684  std::list<tree_expression *> new_dyn_field;
685 
686  for (std::list<tree_expression *>::const_iterator p = dyn_field.begin ();
687  p != dyn_field.end ();
688  p++)
689  {
690  const tree_expression *elt = *p;
691 
692  new_dyn_field.push_back (elt ? elt->dup (scope, context) : 0);
693  }
694 
695  new_idx_expr->dyn_field = new_dyn_field;
696 
697  new_idx_expr->copy_base (*this);
698 
699  return new_idx_expr;
700 }
701 
702 void
704 {
705  tw.visit_index_expression (*this);
706 }
std::list< tree_argument_list * > args
Definition: pt-idx.h:106
bool has_magic_tilde(void) const
Definition: pt-arg-list.h:63
octave_value_list rvalue(int nargout)
Definition: pt-idx.cc:267
Definition: Cell.h:37
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:417
virtual bool is_postfix_index_handled(char type) const
Definition: ov-fcn.h:181
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:347
bool is_function(void) const
Definition: ov.h:711
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
~tree_index_expression(void)
Definition: pt-idx.cc:106
octave_idx_type length(void) const
Definition: ovl.h:96
octave_value_list convert_to_const_vector(const octave_value *object=0)
std::list< tree_expression * > dyn_field
Definition: pt-idx.h:116
virtual tree_expression * dup(symbol_table::scope_id, symbol_table::context_id context) const =0
void error(const char *fmt,...)
Definition: error.cc:570
std::list< string_vector > arg_nm
Definition: pt-idx.h:113
bool is_cell(void) const
Definition: ov.h:545
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
static bool is_variable(const std::string &name)
Definition: variables.cc:221
virtual void copy_base(const tree_expression &e)
Definition: pt-exp.h:131
std::string xstring_value(const char *fmt,...) const
Definition: ov.cc:2122
virtual bool is_variable(void) const
Definition: pt-id.h:71
i e
Definition: data.cc:2724
std::string name(void) const
Definition: pt-idx.cc:145
octave_function * fcn
Definition: ov-class.cc:1743
virtual std::string message(void) const
octave_lvalue lvalue(void)
Definition: pt-idx.cc:470
void set_var(const std::string &var_arg="")
JNIEnv void * args
Definition: ov-java.cc:67
void err_indexed_cs_list(void)
Definition: errwarn.cc:62
octave_value_list do_multi_index_op(int nargout, const octave_value_list &idx)
Definition: ov.cc:1527
static Cell make_subs_cell(tree_argument_list *args, const string_vector &arg_nm)
Definition: pt-idx.cc:151
octave_map make_arg_struct(void) const
Definition: pt-idx.cc:222
tree_expression * expr
Definition: pt-idx.h:103
octave_value value(void) const
Definition: oct-lvalue.cc:83
bool has_magic_end(void) const
Definition: pt-arg-list.cc:60
string_vector get_arg_names(void) const
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function xample nargout(@histc)
Definition: ov-usr-fcn.cc:935
octave_value rvalue1(int nargout=1)
Definition: pt-idx.cc:457
virtual const char * err_id(void) const =0
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:411
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
void error_with_id(const char *id, const char *fmt,...)
Definition: error.cc:615
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
bool is_matrix_type(void) const
Definition: ov.h:676
bool is_string(void) const
Definition: ov.h:578
void set_index(const std::string &t, const std::list< octave_value_list > &i)
Definition: oct-lvalue.cc:45
void numel(octave_idx_type n)
Definition: oct-lvalue.h:87
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1028
bool has_magic_colon(void) const
Definition: ovl.cc:202
double tmp
Definition: data.cc:6300
octave_value retval
Definition: data.cc:6294
#define panic_impossible()
Definition: error.h:40
idx type
Definition: ov.cc:3129
static octave_value_list make_value_list(tree_argument_list *args, const string_vector &arg_nm, const octave_value *object, bool rvalue=true)
Definition: pt-idx.cc:176
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
static void final_index_error(octave::index_exception &e, const tree_expression *expr)
Definition: pt-idx.cc:277
std::string type
Definition: pt-idx.h:109
tree_index_expression(tree_expression *e=0, tree_argument_list *lst=0, int l=-1, int c=-1, char t= '(')
Definition: pt-idx.cc:49
octave_function * function_value(bool silent=false) const
Definition: ov.cc:1705
virtual void visit_index_expression(tree_index_expression &)=0
virtual std::string name(void) const
Definition: pt-exp.h:103
virtual octave_value rvalue1(int nargout=1)
Definition: pt-exp.cc:54
bool empty(void) const
Definition: ovl.h:98
tree_argument_list * dup(symbol_table::scope_id scope, symbol_table::context_id context) const
bool has_magic_end(void) const
Definition: pt-idx.cc:126
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
bool is_cs_list(void) const
Definition: ov.h:602
void accept(tree_walker &tw)
Definition: pt-idx.cc:703
size_t length(void) const
Definition: base-list.h:50
virtual octave_lvalue lvalue(void)
Definition: pt-exp.cc:72
bool is_undefined(void) const
Definition: ov.h:539
void err_invalid_inquiry_subscript(void)
Definition: errwarn.cc:74
void append(tree_argument_list *lst=0, char t= '(')
Definition: pt-idx.cc:77
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
virtual int column(void) const
Definition: pt.h:51
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
bool is_zero_by_zero(void) const
Definition: ov.h:696
virtual bool is_identifier(void) const
Definition: pt-exp.h:61
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
std::string get_struct_index(std::list< string_vector >::const_iterator p_arg_nm, std::list< tree_expression * >::const_iterator p_dyn_field) const
Definition: pt-idx.cc:199
tree_index_expression * dup(symbol_table::scope_id scope, symbol_table::context_id context) const
Definition: pt-idx.cc:659
void stash_name_tags(const string_vector &nm)
Definition: ovl.h:144