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