GNU Octave  4.0.0
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-2015 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 #ifdef 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 "oct-obj.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 "gripes.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
89 tree_index_expression::append (const std::string& n)
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 
144 std::string
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  if (! error_state)
161  {
162  int n = arg_values.length ();
163 
164  if (n > 0)
165  {
166  arg_values.stash_name_tags (arg_nm);
167 
168  retval.resize (dim_vector (1, n));
169 
170  for (int i = 0; i < n; i++)
171  retval(0,i) = arg_values(i);
172  }
173  }
174 
175  return retval;
176 }
177 
178 static inline octave_value_list
180  const octave_value *object, bool rvalue = true)
181 {
182  octave_value_list retval;
183 
184  if (args)
185  {
186  if (rvalue && object && args->has_magic_end () && object->is_undefined ())
188  else
189  retval = args->convert_to_const_vector (object);
190  }
191 
192  if (! error_state)
193  {
194  octave_idx_type n = retval.length ();
195 
196  if (n > 0)
197  retval.stash_name_tags (arg_nm);
198  }
199 
200  return retval;
201 }
202 
203 std::string
205  (std::list<string_vector>::const_iterator p_arg_nm,
206  std::list<tree_expression *>::const_iterator p_dyn_field) const
207 {
208  std::string fn = (*p_arg_nm)(0);
209 
210  if (fn.empty ())
211  {
212  tree_expression *df = *p_dyn_field;
213 
214  if (df)
215  {
216  octave_value t = df->rvalue1 ();
217 
218  if (! error_state)
219  {
220  if (t.is_string () && t.rows () == 1)
221  fn = t.string_value ();
222  else
223  error ("dynamic structure field names must be strings");
224  }
225  }
226  else
227  panic_impossible ();
228  }
229 
230  return fn;
231 }
232 
235 {
236  int n = args.size ();
237 
238  Cell type_field (n, 1);
239  Cell subs_field (n, 1);
240 
241  std::list<tree_argument_list *>::const_iterator p_args = args.begin ();
242  std::list<string_vector>::const_iterator p_arg_nm = arg_nm.begin ();
243  std::list<tree_expression *>::const_iterator p_dyn_field = dyn_field.begin ();
244 
245  octave_map m;
246 
247  for (int i = 0; i < n; i++)
248  {
249  switch (type[i])
250  {
251  case '(':
252  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
253  break;
254 
255  case '{':
256  subs_field(i) = make_subs_cell (*p_args, *p_arg_nm);
257  break;
258 
259  case '.':
260  subs_field(i) = get_struct_index (p_arg_nm, p_dyn_field);
261  break;
262 
263  default:
264  panic_impossible ();
265  }
266 
267  if (error_state)
268  return m;
269 
270  p_args++;
271  p_arg_nm++;
272  p_dyn_field++;
273  }
274 
275  m.assign ("type", type_field);
276  m.assign ("subs", subs_field);
277 
278  return m;
279 }
280 
283 {
284  return tree_index_expression::rvalue (nargout, 0);
285 }
286 
289  const std::list<octave_lvalue> *lvalue_list)
290 {
291  octave_value_list retval;
292 
293  if (error_state)
294  return retval;
295 
296  octave_value first_expr_val;
297 
298  octave_value_list first_args;
299 
300  bool have_args = false;
301 
302  if (expr->is_identifier () && type[0] == '(')
303  {
304  tree_identifier *id = dynamic_cast<tree_identifier *> (expr);
305 
306  if (! (id->is_variable () || args.empty ()))
307  {
308  tree_argument_list *al = *(args.begin ());
309 
310  size_t n = al ? al->length () : 0;
311 
312  if (n > 0)
313  {
314  string_vector anm = *(arg_nm.begin ());
315  have_args = true;
316  first_args = al -> convert_to_const_vector ();
317  first_args.stash_name_tags (anm);
318 
319  if (! error_state)
320  first_expr_val = id->do_lookup (first_args);
321  }
322  }
323  }
324 
325  if (! error_state)
326  {
327  if (first_expr_val.is_undefined ())
328  first_expr_val = expr->rvalue1 ();
329 
330  octave_value tmp = first_expr_val;
331  octave_idx_type tmpi = 0;
332 
333  std::list<octave_value_list> idx;
334 
335  int n = args.size ();
336 
337  std::list<tree_argument_list *>::iterator p_args = args.begin ();
338  std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
339  std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
340 
341  for (int i = 0; i < n; i++)
342  {
343  if (i > 0)
344  {
345  tree_argument_list *al = *p_args;
346 
347  // In Matlab, () can only be followed by . In Octave, we do not
348  // enforce this for rvalue expressions, but we'll split the
349  // evaluation at this point. This will, hopefully, allow Octave's
350  // looser rules apply smoothly for Matlab overloaded subsref
351  // codes.
352  bool force_split = type[i-1] == '(' && type[i] != '.';
353 
354  if (force_split || (al && al->has_magic_end ()))
355  {
356  // We have an expression like
357  //
358  // x{end}.a(end)
359  //
360  // and we are looking at the argument list that
361  // contains the second (or third, etc.) "end" token,
362  // so we must evaluate everything up to the point of
363  // that argument list so we can pass the appropriate
364  // value to the built-in end function.
365 
366  octave_value_list tmp_list
367  = tmp.subsref (type.substr (tmpi, i - tmpi), idx, nargout);
368 
369  tmp = tmp_list.length () ? tmp_list(0) : octave_value ();
370  tmpi = i;
371  idx.clear ();
372 
373  if (tmp.is_cs_list ())
375 
376  if (error_state)
377  break;
378 
379  if (tmp.is_function ())
380  {
381  octave_function *fcn = tmp.function_value (true);
382 
383  if (fcn && ! fcn->is_postfix_index_handled (type[i]))
384  {
385  octave_value_list empty_args;
386 
387  tmp_list = tmp.do_multi_index_op (1, empty_args);
388  tmp = (tmp_list.length ()
389  ? tmp_list(0) : octave_value ());
390 
391  if (tmp.is_cs_list ())
393 
394  if (error_state)
395  break;
396  }
397  }
398  }
399  }
400 
401  switch (type[i])
402  {
403  case '(':
404  if (have_args)
405  {
406  idx.push_back (first_args);
407  have_args = false;
408  }
409  else
410  idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
411  break;
412 
413  case '{':
414  idx.push_back (make_value_list (*p_args, *p_arg_nm, &tmp));
415  break;
416 
417  case '.':
418  idx.push_back (octave_value (get_struct_index (p_arg_nm,
419  p_dyn_field)));
420  break;
421 
422  default:
423  panic_impossible ();
424  }
425 
426  if (error_state)
427  break;
428 
429  p_args++;
430  p_arg_nm++;
431  p_dyn_field++;
432  }
433 
434  if (! error_state)
435  {
436  retval = tmp.subsref (type.substr (tmpi, n - tmpi), idx, nargout,
437  lvalue_list);
438 
439  octave_value val = retval.length () ? retval(0) : octave_value ();
440 
441  if (! error_state && val.is_function ())
442  {
443  octave_function *fcn = val.function_value (true);
444 
445  if (fcn)
446  {
447  octave_value_list empty_args;
448 
449  retval = (lvalue_list
450  ? val.do_multi_index_op (nargout, empty_args,
451  lvalue_list)
452  : val.do_multi_index_op (nargout, empty_args));
453  }
454  }
455  }
456  }
457 
458  return retval;
459 }
460 
463 {
464  octave_value retval;
465 
466  const octave_value_list tmp = rvalue (nargout);
467 
468  if (! tmp.empty ())
469  retval = tmp(0);
470 
471  return retval;
472 }
473 
476 {
477  octave_lvalue retval;
478 
479  std::list<octave_value_list> idx;
480  std::string tmp_type;
481 
482  int n = args.size ();
483 
484  std::list<tree_argument_list *>::iterator p_args = args.begin ();
485  std::list<string_vector>::iterator p_arg_nm = arg_nm.begin ();
486  std::list<tree_expression *>::iterator p_dyn_field = dyn_field.begin ();
487 
488  retval = expr->lvalue ();
489 
490  if (! error_state)
491  {
492  octave_value tmp = retval.value ();
493 
494  octave_idx_type tmpi = 0;
495  std::list<octave_value_list> tmpidx;
496 
497  for (int i = 0; i < n; i++)
498  {
499  if (retval.numel () != 1)
501  else if (tmpi < i)
502  {
503  tmp = tmp.subsref (type.substr (tmpi, i - tmpi), tmpidx, true);
504  tmpidx.clear ();
505  }
506 
507  if (error_state)
508  break;
509 
510  switch (type[i])
511  {
512  case '(':
513  {
514  octave_value_list tidx
515  = make_value_list (*p_args, *p_arg_nm, &tmp, false);
516 
517  idx.push_back (tidx);
518 
519  if (i < n - 1)
520  {
521  if (type[i+1] == '.')
522  {
523  tmpidx.push_back (tidx);
524  tmpi = i+1;
525  }
526  else
527  error ("() must be followed by . or close the index chain");
528  }
529  }
530  break;
531 
532  case '{':
533  {
534  octave_value_list tidx
535  = make_value_list (*p_args, *p_arg_nm, &tmp, false);
536 
537  if (tmp.is_undefined ())
538  {
539  if (tidx.has_magic_colon ())
541  else
542  tmp = Cell ();
543  }
544  else if (tmp.is_zero_by_zero ()
545  && (tmp.is_matrix_type () || tmp.is_string ()))
546  {
547  tmp = Cell ();
548  }
549 
550  retval.numel (tmp.numel (tidx));
551 
552  if (error_state)
553  break;
554 
555  idx.push_back (tidx);
556  tmpidx.push_back (tidx);
557  tmpi = i;
558  }
559  break;
560 
561  case '.':
562  {
563  octave_value tidx = get_struct_index (p_arg_nm, p_dyn_field);
564  if (error_state)
565  break;
566 
567  bool autoconv = (tmp.is_zero_by_zero ()
568  && (tmp.is_matrix_type () || tmp.is_string ()
569  || tmp.is_cell ()));
570 
571  if (i > 0 && type[i-1] == '(')
572  {
573  octave_value_list pidx = idx.back ();
574 
575  // Use octave_map, not octave_scalar_map so that the
576  // dimensions are 0x0, not 1x1.
577  if (tmp.is_undefined ())
578  {
579  if (pidx.has_magic_colon ())
581  else
582  tmp = octave_map ();
583  }
584  else if (autoconv)
585  tmp = octave_map ();
586 
587  retval.numel (tmp.numel (pidx));
588 
589  tmpi = i-1;
590  tmpidx.push_back (tidx);
591  }
592  else
593  {
594  if (tmp.is_undefined () || autoconv)
595  {
596  tmpi = i+1;
597  tmp = octave_value ();
598  }
599  else
600  {
601  retval.numel (tmp.numel (octave_value_list ()));
602 
603  tmpi = i;
604  tmpidx.push_back (tidx);
605  }
606  }
607 
608  if (error_state)
609  break;
610 
611  idx.push_back (tidx);
612  }
613  break;
614 
615  default:
616  panic_impossible ();
617  }
618 
619  if (idx.back ().empty ())
620  error ("invalid empty index list");
621 
622  if (error_state)
623  break;
624 
625  p_args++;
626  p_arg_nm++;
627  p_dyn_field++;
628  }
629 
630  if (! error_state)
631  retval.set_index (type, idx);
632 
633  }
634 
635  return retval;
636 }
637 
638 /*
639 %!test
640 %! clear x;
641 %! clear y;
642 %! y = 3;
643 %! x(y(end)) = 1;
644 %! assert (x, [0, 0, 1]);
645 %! clear x;
646 %! clear y;
647 %! y = {3};
648 %! x(y{end}) = 1;
649 %! assert (x, [0, 0, 1]);
650 
651 %!test
652 %! x = {1, 2, 3};
653 %! [x{:}] = deal (4, 5, 6);
654 %! assert (x, {4, 5, 6});
655 
656 %!test
657 %! [x.a, x.b.c] = deal (1, 2);
658 %! assert (x.a == 1 && x.b.c == 2);
659 
660 %!test
661 %! [x.a, x(2).b] = deal (1, 2);
662 %! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
663 
664 %!test
665 %! x = struct (zeros (0, 1), {"a", "b"});
666 %! x(2).b = 1;
667 %! assert (x(2).b == 1);
668 
669 %!test
670 %! x = struct (zeros (0, 1), {"a", "b"});
671 %! x(2).b = 1;
672 %! assert (x(2).b == 1);
673 */
674 
678 {
679  tree_index_expression *new_idx_expr
680  = new tree_index_expression (line (), column ());
681 
682  new_idx_expr->expr = expr ? expr->dup (scope, context) : 0;
683 
684  std::list<tree_argument_list *> new_args;
685 
686  for (std::list<tree_argument_list *>::const_iterator p = args.begin ();
687  p != args.end ();
688  p++)
689  {
690  const tree_argument_list *elt = *p;
691 
692  new_args.push_back (elt ? elt->dup (scope, context) : 0);
693  }
694 
695  new_idx_expr->args = new_args;
696 
697  new_idx_expr->type = type;
698 
699  new_idx_expr->arg_nm = arg_nm;
700 
701  std::list<tree_expression *> new_dyn_field;
702 
703  for (std::list<tree_expression *>::const_iterator p = dyn_field.begin ();
704  p != dyn_field.end ();
705  p++)
706  {
707  const tree_expression *elt = *p;
708 
709  new_dyn_field.push_back (elt ? elt->dup (scope, context) : 0);
710  }
711 
712  new_idx_expr->dyn_field = new_dyn_field;
713 
714  new_idx_expr->copy_base (*this);
715 
716  return new_idx_expr;
717 }
718 
719 void
721 {
722  tw.visit_index_expression (*this);
723 }
std::list< tree_argument_list * > args
Definition: pt-idx.h:104
bool has_magic_tilde(void) const
Definition: pt-arg-list.h:61
octave_value_list rvalue(int nargout)
Definition: pt-idx.cc:282
size_t length(void) const
Definition: base-list.h:45
Definition: Cell.h:35
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov.h:401
octave_idx_type rows(void) const
Definition: ov.h:473
virtual bool is_postfix_index_handled(char type) const
Definition: ov-fcn.h:179
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:348
bool is_function(void) const
Definition: ov.h:695
~tree_index_expression(void)
Definition: pt-idx.cc:106
octave_idx_type length(void) const
Definition: oct-obj.h:89
octave_value_list convert_to_const_vector(const octave_value *object=0)
Definition: pt-arg-list.cc:204
std::list< tree_expression * > dyn_field
Definition: pt-idx.h:114
virtual tree_expression * dup(symbol_table::scope_id, symbol_table::context_id context) const =0
void error(const char *fmt,...)
Definition: error.cc:476
std::list< string_vector > arg_nm
Definition: pt-idx.h:111
bool is_cell(void) const
Definition: ov.h:529
virtual void copy_base(const tree_expression &e)
Definition: pt-exp.h:129
virtual bool is_variable(void)
Definition: pt-id.h:69
std::string name(void) const
Definition: pt-idx.cc:145
void gripe_invalid_inquiry_subscript(void)
Definition: gripes.cc:217
void gripe_indexed_cs_list(void)
Definition: gripes.cc:223
octave_lvalue lvalue(void)
Definition: pt-idx.cc:475
octave_value_list do_multi_index_op(int nargout, const octave_value_list &idx)
Definition: ov.cc:1382
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:234
tree_expression * expr
Definition: pt-idx.h:101
octave_value value(void) const
Definition: oct-lvalue.cc:70
bool has_magic_end(void) const
Definition: pt-arg-list.cc:60
string_vector get_arg_names(void) const
Definition: pt-arg-list.cc:287
octave_value rvalue1(int nargout=1)
Definition: pt-idx.cc:462
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:395
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:76
std::string string_value(bool force=false) const
Definition: ov.h:897
bool is_matrix_type(void) const
Definition: ov.h:660
bool is_string(void) const
Definition: ov.h:562
void set_index(const std::string &t, const std::list< octave_value_list > &i)
Definition: oct-lvalue.cc:45
int error_state
Definition: error.cc:101
void numel(octave_idx_type n)
Definition: oct-lvalue.h:85
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1033
bool has_magic_colon(void) const
Definition: oct-obj.cc:208
#define panic_impossible()
Definition: error.h:33
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:179
tree_argument_list * dup(symbol_table::scope_id scope, symbol_table::context_id context) const
Definition: pt-arg-list.cc:333
std::string type
Definition: pt-idx.h:107
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:1597
virtual void visit_index_expression(tree_index_expression &)=0
virtual std::string name(void) const
Definition: pt-exp.h:101
virtual octave_value rvalue1(int nargout=1)
Definition: pt-exp.cc:58
bool empty(void) const
Definition: oct-obj.h:91
bool has_magic_end(void) const
Definition: pt-idx.cc:126
bool is_cs_list(void) const
Definition: ov.h:586
void accept(tree_walker &tw)
Definition: pt-idx.cc:720
virtual octave_lvalue lvalue(void)
Definition: pt-exp.cc:78
bool is_undefined(void) const
Definition: ov.h:523
void append(tree_argument_list *lst=0, char t= '(')
Definition: pt-idx.cc:77
virtual int column(void) const
Definition: pt.h:47
bool is_zero_by_zero(void) const
Definition: ov.h:680
virtual bool is_identifier(void) const
Definition: pt-exp.h:59
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:205
tree_index_expression * dup(symbol_table::scope_id scope, symbol_table::context_id context) const
Definition: pt-idx.cc:676
void stash_name_tags(const string_vector &nm)
Definition: oct-obj.h:137