GNU Octave  4.4.1
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-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://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 "interpreter-private.h"
30 #include "oct-map.h"
31 #include "ovl.h"
32 #include "oct-lvalue.h"
33 #include "ov.h"
34 #include "pt-arg-list.h"
35 #include "pt-eval.h"
36 #include "pt-id.h"
37 #include "pt-idx.h"
38 #include "utils.h"
39 #include "variables.h"
40 #include "errwarn.h"
41 
42 namespace octave
43 {
44  // Index expressions.
45 
47  : tree_expression (l, c), m_expr (nullptr), m_args (0), m_type (),
48  m_arg_nm (), m_dyn_field () { }
49 
51  tree_argument_list *lst,
52  int l, int c, char t)
53  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
54  m_arg_nm (), m_dyn_field ()
55  {
56  append (lst, t);
57  }
58 
60  const std::string& n,
61  int l, int c)
62  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
63  m_arg_nm (), m_dyn_field ()
64  {
65  append (n);
66  }
67 
69  tree_expression *df,
70  int l, int c)
71  : tree_expression (l, c), m_expr (e), m_args (0), m_type (),
72  m_arg_nm (), m_dyn_field ()
73  {
74  append (df);
75  }
76 
77  void
79  {
80  m_args.push_back (lst);
81  m_type.append (1, t);
82  m_arg_nm.push_back (lst ? lst->get_arg_names () : string_vector ());
83  m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
84 
85  if (lst && lst->has_magic_tilde ())
86  error ("invalid use of empty argument (~) in index expression");
87  }
88 
89  void
91  {
92  m_args.push_back (static_cast<tree_argument_list *> (nullptr));
93  m_type += '.';
94  m_arg_nm.push_back (n);
95  m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
96  }
97 
98  void
100  {
101  m_args.push_back (static_cast<tree_argument_list *> (nullptr));
102  m_type += '.';
103  m_arg_nm.push_back ("");
104  m_dyn_field.push_back (df);
105  }
106 
108  {
109  delete m_expr;
110 
111  while (! m_args.empty ())
112  {
113  std::list<tree_argument_list *>::iterator p = m_args.begin ();
114  delete *p;
115  m_args.erase (p);
116  }
117 
118  while (! m_dyn_field.empty ())
119  {
120  std::list<tree_expression *>::iterator p = m_dyn_field.begin ();
121  delete *p;
122  m_dyn_field.erase (p);
123  }
124  }
125 
126  bool
128  {
129  for (const tree_argument_list *elt : m_args)
130  {
131  if (elt && elt->has_magic_end ())
132  return true;
133  }
134 
135  return false;
136  }
137 
138  // This is useful for printing the name of the variable in an indexed
139  // assignment.
140 
143  {
144  return m_expr->name ();
145  }
146 
147  static inline octave_value_list
150  const string_vector& m_arg_nm, const octave_value *object,
151  bool rvalue = true)
152  {
154 
155  if (m_args)
156  {
157  if (rvalue && object && m_args->has_magic_end ()
158  && object->is_undefined ())
160 
161  retval = m_args->convert_to_const_vector (tw, object);
162  }
163 
165 
166  if (n > 0)
167  retval.stash_name_tags (m_arg_nm);
168 
169  return retval;
170  }
171 
175  std::list<string_vector>::const_iterator p_arg_nm,
176  std::list<tree_expression *>::const_iterator p_dyn_field) const
177  {
178  std::string fn = (*p_arg_nm)(0);
179 
180  if (fn.empty ())
181  {
182  tree_expression *df = *p_dyn_field;
183 
184  if (df)
185  {
186  octave_value t = tw->evaluate (df);
187 
188  fn = t.xstring_value ("dynamic structure field names must be strings");
189  }
190  else
191  panic_impossible ();
192  }
193 
194  return fn;
195  }
196 
197  // Final step of processing an indexing error. Add the name of the
198  // variable being indexed, if any, then issue an error. (Will this also
199  // be needed by pt-lvalue, which calls subsref?)
200 
201  static void
203  const octave::tree_expression *expr)
204  {
205  std::string extra_message;
206 
207  octave::symbol_table& symtab
208  = octave::__get_symbol_table__ ("final_index_error");
209 
211 
212  if (expr->is_identifier ()
213  && dynamic_cast<const octave::tree_identifier *> (expr)->is_variable (context))
214  {
215  std::string var = expr->name ();
216 
217  e.set_var (var);
218 
219  octave_value fcn = symtab.find_function (var);
220 
221  if (fcn.is_function ())
222  {
224 
225  if (fp && fp->name () == var)
226  extra_message = " (note: variable '" + var + "' shadows function)";
227  }
228  }
229 
230  std::string msg = e.message () + extra_message;
231 
232  error_with_id (e.err_id (), msg.c_str ());
233  }
234 
235  octave_lvalue
237  {
239 
240  std::list<octave_value_list> idx;
241  std::string tmp_type;
242 
243  int n = m_args.size ();
244 
245  std::list<tree_argument_list *>::iterator p_args = m_args.begin ();
246  std::list<string_vector>::iterator p_arg_nm = m_arg_nm.begin ();
247  std::list<tree_expression *>::iterator p_dyn_field = m_dyn_field.begin ();
248 
249  retval = m_expr->lvalue (tw);
250 
251  octave_value tmp = retval.value ();
252 
253  octave_idx_type tmpi = 0;
254  std::list<octave_value_list> tmpidx;
255 
256  for (int i = 0; i < n; i++)
257  {
258  if (retval.numel () != 1)
260 
261  if (tmpi < i)
262  {
263  try
264  {
265  tmp = tmp.subsref (m_type.substr (tmpi, i-tmpi), tmpidx, true);
266  }
267  catch (index_exception& e) // problems with range, invalid type etc.
268  {
270  }
271 
272  tmpidx.clear ();
273  }
274 
275  switch (m_type[i])
276  {
277  case '(':
278  {
279  octave_value_list tidx
280  = make_value_list (tw, *p_args, *p_arg_nm, &tmp, false);
281 
282  idx.push_back (tidx);
283 
284  if (i < n - 1)
285  {
286  if (m_type[i+1] != '.')
287  error ("() must be followed by . or close the index chain");
288 
289  tmpidx.push_back (tidx);
290  tmpi = i+1;
291  }
292  }
293  break;
294 
295  case '{':
296  {
297  octave_value_list tidx
298  = make_value_list (tw, *p_args, *p_arg_nm, &tmp, false);
299 
300  if (tmp.is_undefined ())
301  {
302  if (tidx.has_magic_colon ())
304 
305  tmp = Cell ();
306  }
307  else if (tmp.is_zero_by_zero ()
308  && (tmp.is_matrix_type () || tmp.is_string ()))
309  {
310  tmp = Cell ();
311  }
312 
313  retval.numel (tmp.numel (tidx));
314 
315  idx.push_back (tidx);
316  tmpidx.push_back (tidx);
317  tmpi = i;
318  }
319  break;
320 
321  case '.':
322  {
323  octave_value tidx = get_struct_index (tw, p_arg_nm, p_dyn_field);
324 
325  bool autoconv = (tmp.is_zero_by_zero ()
326  && (tmp.is_matrix_type () || tmp.is_string ()
327  || tmp.iscell ()));
328 
329  if (i > 0 && m_type[i-1] == '(')
330  {
331  octave_value_list pidx = idx.back ();
332 
333  // Use octave_map, not octave_scalar_map so that the
334  // dimensions are 0x0, not 1x1.
335  if (tmp.is_undefined ())
336  {
337  if (pidx.has_magic_colon ())
339 
340  tmp = octave_map ();
341  }
342  else if (autoconv)
343  tmp = octave_map ();
344 
345  retval.numel (tmp.numel (pidx));
346 
347  tmpi = i-1;
348  tmpidx.push_back (tidx);
349  }
350  else
351  {
352  if (tmp.is_undefined () || autoconv)
353  {
354  tmpi = i+1;
355  tmp = octave_value ();
356  }
357  else
358  {
359  retval.numel (tmp.numel (octave_value_list ()));
360 
361  tmpi = i;
362  tmpidx.push_back (tidx);
363  }
364  }
365 
366  idx.push_back (tidx);
367  }
368  break;
369 
370  default:
371  panic_impossible ();
372  }
373 
374  if (idx.back ().empty ())
375  error ("invalid empty index list");
376 
377  p_args++;
378  p_arg_nm++;
379  p_dyn_field++;
380  }
381 
382  retval.set_index (m_type, idx);
383 
384  return retval;
385  }
386 
389  {
390  tree_index_expression *new_idx_expr
391  = new tree_index_expression (line (), column ());
392 
393  new_idx_expr->m_expr = (m_expr ? m_expr->dup (scope) : nullptr);
394 
395  std::list<tree_argument_list *> new_args;
396 
397  for (const tree_argument_list *elt : m_args)
398  new_args.push_back (elt ? elt->dup (scope) : nullptr);
399 
400  new_idx_expr->m_args = new_args;
401 
402  new_idx_expr->m_type = m_type;
403 
404  new_idx_expr->m_arg_nm = m_arg_nm;
405 
406  std::list<tree_expression *> new_dyn_field;
407 
408  for (const tree_expression *elt : m_dyn_field)
409  new_dyn_field.push_back (elt ? elt->dup (scope) : nullptr);
410 
411  new_idx_expr->m_dyn_field = new_dyn_field;
412 
413  new_idx_expr->copy_base (*this);
414 
415  return new_idx_expr;
416  }
417 }
418 
419 /*
420 %!test
421 %! clear x;
422 %! clear y;
423 %! y = 3;
424 %! x(y(end)) = 1;
425 %! assert (x, [0, 0, 1]);
426 %! clear x;
427 %! clear y;
428 %! y = {3};
429 %! x(y{end}) = 1;
430 %! assert (x, [0, 0, 1]);
431 
432 %!test
433 %! x = {1, 2, 3};
434 %! [x{:}] = deal (4, 5, 6);
435 %! assert (x, {4, 5, 6});
436 
437 %!test
438 %! [x.a, x.b.c] = deal (1, 2);
439 %! assert (x.a == 1 && x.b.c == 2);
440 
441 %!test
442 %! [x.a, x(2).b] = deal (1, 2);
443 %! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
444 
445 %!test
446 %! x = struct (zeros (0, 1), {"a", "b"});
447 %! x(2).b = 1;
448 %! assert (x(2).b == 1);
449 
450 %!test
451 %! x = struct (zeros (0, 1), {"a", "b"});
452 %! x(2).b = 1;
453 %! assert (x(2).b == 1);
454 */
virtual std::string name(void) const
Definition: pt-exp.h:102
static void final_index_error(octave::index_exception &e, const octave::tree_expression *expr)
Definition: pt-eval.cc:1204
bool has_magic_end(void) const
Definition: pt-idx.cc:127
octave_value find_function(const std::string &name, const octave_value_list &args=octave_value_list(), bool local_funcs=true)
Definition: symtab.cc:412
Definition: Cell.h:37
symbol_record::context_id current_context(void) const
Definition: symtab.h:87
virtual int column(void) const
Definition: pt.h:58
tree_index_expression * dup(symbol_scope &scope) const
Definition: pt-idx.cc:388
bool has_magic_colon(void) const
Definition: ovl.cc:200
void error(const char *fmt,...)
Definition: error.cc:578
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:79
octave_lvalue lvalue(tree_evaluator *tw)
Definition: pt-idx.cc:236
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:997
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
tree_index_expression(tree_expression *e=nullptr, tree_argument_list *lst=nullptr, int l=-1, int c=-1, char t='(')
Definition: pt-idx.cc:50
i e
Definition: data.cc:2591
var
Definition: givens.cc:88
octave_function * fcn
Definition: ov-class.cc:1754
bool has_magic_tilde(void) const
Definition: pt-arg-list.h:72
std::string name(void) const
Definition: pt-idx.cc:142
void err_indexed_cs_list(void)
Definition: errwarn.cc:62
symbol_table & __get_symbol_table__(const std::string &who)
std::list< tree_argument_list * > m_args
Definition: pt-idx.h:116
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:412
void error_with_id(const char *id, const char *fmt,...)
Definition: error.cc:623
virtual void copy_base(const tree_expression &e)
Definition: pt-exp.h:130
string_vector get_arg_names(void) const
bool is_function(void) const
Definition: ov-fcn.h:70
static bool is_variable(octave::symbol_table &symtab, const std::string &name)
Definition: variables.cc:201
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
#define panic_impossible()
Definition: error.h:40
std::list< string_vector > m_arg_nm
Definition: pt-idx.h:123
tree_expression * m_expr
Definition: pt-idx.h:113
virtual bool is_identifier(void) const
Definition: pt-exp.h:69
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
std::list< tree_expression * > m_dyn_field
Definition: pt-idx.h:126
virtual octave_lvalue lvalue(tree_evaluator *)
Definition: pt-exp.cc:41
p
Definition: lu.cc:138
static octave_value_list make_value_list(octave::tree_evaluator *tw, octave::tree_argument_list *m_args, const string_vector &m_arg_nm, const octave_value *object, bool rvalue=true)
Definition: pt-idx.cc:148
void err_invalid_inquiry_subscript(void)
Definition: errwarn.cc:74
octave_value evaluate(tree_expression *expr, int nargout=1)
Definition: pt-eval.h:294
for i
Definition: data.cc:5264
octave_value_list convert_to_const_vector(tree_evaluator *tw, const octave_value *object=nullptr)
bool has_magic_end(void) const
Definition: pt-arg-list.cc:63
virtual octave_function * function_value(bool silent=false)
Definition: ov-base.cc:871
octave_idx_type length(void) const
void append(tree_argument_list *lst=nullptr, char t='(')
Definition: pt-idx.cc:78
std::string name(void) const
Definition: ov-fcn.h:182
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:888
virtual tree_expression * dup(symbol_scope &scope) const =0
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:174