GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
pt-idx.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2026 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
49tree_index_expression::tree_index_expression (tree_expression *e, const token& open_delim, tree_argument_list *lst, const token& close_delim, char t)
50 : m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
51{
52 append (open_delim, lst, close_delim, t);
53}
54
56 : m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
57{
58 append (dot_tok, struct_elt_tok);
59}
60
61tree_index_expression::tree_index_expression (tree_expression *e, const token& dot_tok, const token& open_paren, tree_expression *df, const token& close_paren)
62 : m_expr (e), m_args (0), m_type (), m_arg_nm (), m_dyn_field (), m_word_list_cmd (false)
63{
64 append (dot_tok, open_paren, df, close_paren);
65}
66
68tree_index_expression::append (const token& open_delim, tree_argument_list *lst, const token& close_delim, char t)
69{
70 lst->mark_in_delims (open_delim, close_delim);
71 m_args.push_back (lst);
72 m_type.append (1, t);
73 m_dot_tok.push_back (token ());
74 m_arg_nm.push_back (lst ? lst->get_arg_names () : string_vector ());
75 m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
76
77 if (lst && lst->has_magic_tilde ())
78 error ("invalid use of empty argument (~) in index expression");
79
80 return this;
81}
82
84tree_index_expression::append (const token& dot_tok, const token& struct_elt_tok)
85{
86 m_args.push_back (static_cast<tree_argument_list *> (nullptr));
87 m_type += '.';
88 m_dot_tok.push_back (dot_tok);
89 m_arg_nm.push_back (struct_elt_tok.text ());
90 m_dyn_field.push_back (static_cast<tree_expression *> (nullptr));
91
92 return this;
93}
94
96tree_index_expression::append (const token& dot_tok, const token& open_paren, tree_expression *df, const token& close_paren)
97{
98 m_args.push_back (static_cast<tree_argument_list *> (nullptr));
99 m_type += '.';
100 m_dot_tok.push_back (dot_tok);
101 m_arg_nm.push_back ("");
102 df->mark_in_delims (open_paren, close_paren);
103 m_dyn_field.push_back (df);
104
105 return this;
106}
107
109{
110 delete m_expr;
111
112 while (! m_args.empty ())
113 {
114 auto p = m_args.begin ();
115 delete *p;
116 m_args.erase (p);
117 }
118
119 while (! m_dyn_field.empty ())
120 {
121 auto p = m_dyn_field.begin ();
122 delete *p;
123 m_dyn_field.erase (p);
124 }
125}
126
127// This is useful for printing the name of the variable in an indexed
128// assignment.
129
130std::string
132{
133 return m_expr->name ();
134}
135
138{
139 int n = m_args.size ();
140
141 if (n == 0)
142 return m_expr->end_pos ();
143
144 switch (m_type[n-1])
145 {
146 case '(':
147 case '{':
148 {
149 tree_argument_list *args = m_args.back ();
150 return args->end_pos ();
151 }
152 break;
153
154 case '.':
155 {
156 string_vector arg_names = m_arg_nm.back ();
157
158 if (arg_names.empty ())
159 {
160 tree_expression *dyn_field = m_dyn_field.back ();
161
162 if (dyn_field)
163 return dyn_field->end_pos ();
164 else
165 error ("unexpected: dynamic field is nullptr in call to tree_index_expression::end_pos - please report this bug");
166
167 }
168
169 token dot_tok = m_dot_tok.back ();
170 std::string arg_nm = arg_names(0);
171
172 // FIXME: this might not be correct because we have no way
173 // to account for space between the '.' operator and the
174 // field name. Maybe we should really be storing an
175 // identifier that contains position information?
176
177 filepos pos = dot_tok.end_pos ();
178 pos.increment_column (arg_nm.size ());
179
180 return pos;
181 }
182
183 default:
184 error ("unexpected: index not '(', '{', or '.' in tree_index_expression::end_pos - please report this bug");
185 }
186}
187
190{
191 int n = m_args.size ();
192
193 if (n == 0)
194 return m_expr->trailing_comments ();
195
196 switch (m_type[n-1])
197 {
198 case '(':
199 case '{':
200 {
201 tree_argument_list *args = m_args.back ();
202 return args->trailing_comments ();
203 }
204 break;
205
206 case '.':
207 {
208 string_vector arg_names = m_arg_nm.back ();
209
210 if (arg_names.empty ())
211 {
212 tree_expression *dyn_field = m_dyn_field.back ();
213
214 if (dyn_field)
215 return dyn_field->trailing_comments ();
216 else
217 error ("unexpected: dynamic field is nullptr in call to tree_index_expression::trailing_comments - please report this bug");
218
219 }
220
221 token dot_tok = m_dot_tok.back ();
222 std::string arg_nm = arg_names(0);
223
224 // FIXME: is this correct? Are trailing comments in this case
225 // stored correctly by the parser? To which token are they
226 // attached?
227
228 return dot_tok.trailing_comments ();
229 }
230
231 default:
232 error ("unexpected: index not '(', '{', or '.' in tree_index_expression::trailing_comments - please report this bug");
233 }
234}
235
236std::string
238(tree_evaluator& tw,
239 std::list<string_vector>::const_iterator p_arg_nm,
240 std::list<tree_expression *>::const_iterator p_dyn_field) const
241{
242 std::string fn = (*p_arg_nm)(0);
243
244 if (fn.empty ())
245 {
246 tree_expression *df = *p_dyn_field;
247
248 if (df)
249 {
250 octave_value t = df->evaluate (tw);
251
252 fn = t.xstring_value ("dynamic structure field names must be strings");
253 }
254 else
255 error ("unexpected: DF is nullptr in call to tree_index_expression::get_struct_index - please report this bug");
256 }
257
258 return fn;
259}
260
263{
264 std::list<octave_value_list> idx;
265
266 int n = m_args.size ();
267
268 auto p_args = m_args.begin ();
269 auto p_arg_nm = m_arg_nm.begin ();
270 auto p_dyn_field = m_dyn_field.begin ();
271
272 octave_lvalue retval = m_expr->lvalue (tw);
273
275 act ([&tw] (const octave_value& val,
276 const std::string& index_type,
277 const std::list<octave_value_list>& index_list)
278 {
279 tw.set_indexed_object (val);
280 tw.set_index_list (index_type, index_list);
281 }, tw.indexed_object (), tw.index_type (), tw.index_list ());
282
283 tw.set_indexed_object (retval.value ());
284 tw.clear_index_list ();
285
286 for (int i = 0; i < n; i++)
287 {
288 switch (m_type[i])
289 {
290 case '(':
291 {
292 octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
293
294 tw.append_index_list ('(', tidx);
295 idx.push_back (tidx);
296 }
297 break;
298
299 case '{':
300 {
301 octave_value_list tidx = tw.make_value_list (*p_args, *p_arg_nm);
302
303 tw.append_index_list ('{', tidx);
304 idx.push_back (tidx);
305 }
306 break;
307
308 case '.':
309 {
310 octave_value tidx = get_struct_index (tw, p_arg_nm, p_dyn_field);
311
312 tw.append_index_list ('.', tidx);
313 idx.push_back (tidx);
314 }
315 break;
316
317 default:
318 error ("unexpected: index not '(', '{', or '.' in tree_index_expression::lvalue - please report this bug");
319 }
320
321 if (idx.back ().empty ())
322 error ("invalid empty index list");
323
324 p_args++;
325 p_arg_nm++;
326 p_dyn_field++;
327 }
328
329 retval.set_index (m_type, idx);
330
331 return retval;
332}
333
336{
337 tree_index_expression *new_idx_expr = new tree_index_expression ();
338
339 new_idx_expr->m_expr = (m_expr ? m_expr->dup (scope) : nullptr);
340
341 std::list<tree_argument_list *> new_args;
342
343 for (const tree_argument_list *elt : m_args)
344 new_args.push_back (elt ? elt->dup (scope) : nullptr);
345
346 new_idx_expr->m_args = new_args;
347
348 new_idx_expr->m_type = m_type;
349
350 new_idx_expr->m_arg_nm = m_arg_nm;
351
352 std::list<tree_expression *> new_dyn_field;
353
354 for (const tree_expression *elt : m_dyn_field)
355 new_dyn_field.push_back (elt ? elt->dup (scope) : nullptr);
356
357 new_idx_expr->m_dyn_field = new_dyn_field;
358
359 new_idx_expr->copy_base (*this);
360
361 return new_idx_expr;
362}
363
364// Unlike Matlab, which does not allow the result of a function call
365// or array indexing expression to be further indexed, Octave attempts
366// to handle arbitrary index expressions. For example, Octave allows
367// expressions like
368//
369// svd (rand (10))(1:5)
370//
371// Although octave_value objects may contain function objects, no
372// indexing operation or function call is supposed to return them
373// directly. Instead, the language is supposed to only allow function
374// objects to be stored as function handles (named or anonymous) or as
375// inline functions. The only place a function object should appear
376// directly is if the symbol stored in a tree_identifier object
377// resolves to a function. This means that the only place we need to
378// look for functions is in the first element of the index
379// expression.
380//
381// Steps:
382//
383// * Obtain the initial value from the expression component of the
384// tree_index_expression object. If it is a tree_identifier object
385// indexed by '(args)' and the identifier is not a variable, then
386// perform a function call. Use the (optional) arguments to perform
387// the function lookup so we choose the correct function or class
388// method to call. Otherwise, evaluate the first expression
389// without any additional arguments.
390//
391// * Iterate over the remaining elements of the index expression and
392// call the octave_value::subsref method. If indexing a class or
393// classdef object, build up a list of indices for a call to the
394// subsref method for the object. Otherwise, use the result of
395// each temporary evaluation for the next index element.
396//
397// * If not indexing a class or classdef object and any partial
398// expression evaluation produces a class or classdef object, then
399// build up a complete argument list from that point on for a final
400// subsref call for that object.
401//
402// Multiple partial evaluations may be required. For example,
403// given a class or classdef object X, then for the expression
404//
405// x.a{end}(2:end).b
406//
407// we must evaluate x.a to obtain the size for the first {end}
408// expression, then we must evaluate x.a{end} to obtain the size
409// for the second (2:end) expression. Finally, the complete
410// expression may be evaluated.
411//
412// If X is a cell array in the above expression, and none of the
413// intermediate evaluations produces a class or classdef object,
414// then the evaluation is performed as the following series of
415// steps
416//
417// tmp = x.a
418// tmp = tmp{end}
419// tmp = tmp(2:end)
420// result = tmp.b
421//
422// If any of the partial evaluations produces a class or classdef
423// object, then the subsref method for that object is called as
424// described above. For example, suppose x.a produces a classdef
425// object. Then the evaluation is performed as the following
426// series of steps
427//
428// base_expr = tmp = x.a
429// tmp = base_expr{end}
430// base_expr{end}(2:end).b
431//
432// In the last two steps, the partial value computed in the
433// previous step is used to determine the value of END.
434
437{
438 octave_value_list retval;
439
440 panic_if (m_args.empty ());
441
442 auto p_args = m_args.begin ();
443 auto p_arg_nm = m_arg_nm.begin ();
444 auto p_dyn_field = m_dyn_field.begin ();
445
446 int n = m_args.size ();
447 int beg = 0;
448
449 // Set nargout to 1 for all subsref operations except the last one.
450 int nargout_saved = nargout;
451 if (n > 1)
452 nargout = 1;
453
454 octave_value base_expr_val;
455
456 if (m_expr->is_identifier () && m_type[beg] == '(')
457 {
458 tree_identifier *id = dynamic_cast<tree_identifier *> (m_expr);
459
460 bool is_var = tw.is_variable (m_expr);
461
462 std::string nm = id->name ();
463
464 if (is_var && is_word_list_cmd ())
465 {
466 bool maybe_binary_op = false;
467 if ((*p_args) && (*p_args)->size () > 0)
468 {
469 // check if first character of first argument might be (the
470 // start of) a binary operator
471 std::string ops = "+-*/\\.^|&";
472 string_vector arg_list = (*p_args)->get_arg_names ();
473 if (! arg_list.isempty ()
474 && (ops.find (arg_list(0)[1]) != std::string::npos))
475 maybe_binary_op = true;
476 }
477
478 std::string advice;
479 if (maybe_binary_op)
480 advice = "\nCheck whitespace around potential binary operator.";
481
482 error ("variable \"%s\" used as function in command style expression%s",
483 nm.c_str (), advice.c_str ());
484 }
485
486 if (! is_var)
487 {
488 octave_value_list first_args;
489
490 tree_argument_list *al = *p_args;
491
492 if (al && al->size () > 0)
493 {
494 unwind_action act ([&tw] (const std::list<octave_lvalue> *lvl)
495 {
496 tw.set_lvalue_list (lvl);
497 }, tw.lvalue_list ());
498
499 tw.set_lvalue_list (nullptr);
500
501 string_vector anm = *p_arg_nm;
502
503 first_args = tw.convert_to_const_vector (al);
504
505 first_args.stash_name_tags (anm);
506 }
507
508 interpreter& interp = tw.get_interpreter ();
509
510 symbol_table& symtab = interp.get_symbol_table ();
511
512 octave_value val = symtab.find_function (nm, first_args);
513
514 octave_function *fcn = nullptr;
515
516 if (val.is_function ())
517 fcn = val.function_value (true);
518
519 if (fcn)
520 {
521 try
522 {
523 retval = fcn->call (tw, nargout, first_args);
524 }
525 catch (index_exception& ie)
526 {
527 tw.final_index_error (ie, m_expr);
528 }
529
530 beg++;
531 p_args++;
532 p_arg_nm++;
533 p_dyn_field++;
534
535 if (n > beg)
536 {
537 // More indices to follow. Silently ignore
538 // extra output values.
539
540 if (retval.length () == 0 || retval(0).is_undefined ())
541 error ("indexing undefined value");
542 else
543 base_expr_val = retval(0);
544 }
545 else
546 {
547 // No more indices, so we are done.
548
549 // See note at end of function about deleting
550 // temporaries prior to pushing result.
551
552 base_expr_val = octave_value ();
553 first_args = octave_value_list ();
554
555 return retval;
556 }
557 }
558 }
559 }
560
561 if (base_expr_val.is_undefined ())
562 base_expr_val = m_expr->evaluate (tw);
563
564 // If we are indexing an object or looking at something like
565 //
566 // classname.static_function (args, ...);
567 //
568 // then we'll just build a complete index list for one big subsref
569 // call. If the expression we are indexing is a classname then
570 // base_expr_val will be an octave_classdef_meta object. If we have
571 // files in a +packagename folder, they will also be an
572 // octave_classdef_meta object, but we don't want to index them.
573
574 std::list<octave_value_list> idx_list;
575
576 {
577 // Note: need new scope so that the following unwind action will
578 // happen before we perform the final indexing for objects (for
579 // example).
580
582 act ([&tw] (const octave_value& val,
583 const std::string& index_type,
584 const std::list<octave_value_list>& index_list)
585 {
586 tw.set_indexed_object (val);
587 tw.set_index_list (index_type, index_list);
588 },
589 tw.indexed_object (),
590 tw.index_type (), tw.index_list ());
591
592 tw.set_indexed_object ();
593 tw.clear_index_list ();
594
595 bool indexing_object = (base_expr_val.isobject ()
596 || base_expr_val.isjava ()
597 || (base_expr_val.is_classdef_meta ()
598 && ! base_expr_val.is_package ()));
599
600 octave_value partial_expr_val = base_expr_val;
601
602 for (int i = beg; i < n; i++)
603 {
604 if (i > beg)
605 {
606 if (! indexing_object)
607 {
608 // Evaluate what we have so far.
609
610 try
611 {
612 // Silently ignore extra output values.
613
614 octave_value_list tmp_list
615 = base_expr_val.subsref (m_type.substr (beg, i-beg),
616 idx_list, nargout);
617
618 partial_expr_val
619 = tmp_list.length () ? tmp_list(0) : octave_value ();
620
621 base_expr_val = partial_expr_val;
622
623 if (partial_expr_val.is_cs_list ())
625
626 retval = partial_expr_val;
627
628 beg = i;
629 idx_list.clear ();
630 tw.clear_index_list ();
631
632 if (partial_expr_val.isobject ()
633 || partial_expr_val.isjava ()
634 || (partial_expr_val.is_classdef_meta ()
635 && ! partial_expr_val.is_package ()))
636 {
637 // Found an object, so now we'll build up
638 // complete index list for one big subsref
639 // call from this point on.
640
641 // FIXME: is is also possible to have a
642 // static method call buried somewhere in
643 // the depths of a complex indexing
644 // expression so that we would also need to
645 // check for an octave_classdef_meta object
646 // here?
647
648 indexing_object = true;
649 }
650 }
651 catch (index_exception& ie)
652 {
653 tw.final_index_error (ie, m_expr);
654 }
655 }
656 }
657
658 tw.set_indexed_object (partial_expr_val);
659
660 switch (m_type[i])
661 {
662 case '(':
663 {
664 octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
665 tw.append_index_list ('(', tmp);
666 idx_list.push_back (tmp);
667 }
668 break;
669
670 case '{':
671 {
672 octave_value_list tmp = tw.make_value_list (*p_args, *p_arg_nm);
673 tw.append_index_list ('{', tmp);
674 idx_list.push_back (tmp);
675 }
676 break;
677
678 case '.':
679 {
680 octave_value tmp = get_struct_index (tw, p_arg_nm, p_dyn_field);
681 tw.append_index_list ('.', tmp);
682 idx_list.push_back (tmp);
683 }
684 break;
685
686 default:
687 error ("unexpected: index not '(', '{', or '.' in tree_index_expression::evaluate_n - please report this bug");
688 }
689
690 p_args++;
691 p_arg_nm++;
692 p_dyn_field++;
693 }
694 }
695
696 // Restore original nargout for last subsref operation
697 nargout = nargout_saved;
698
699 // If ! idx_list.empty () that means we still have stuff to index
700 // otherwise they would have been dealt with and idx_list would have
701 // been emptied.
702 if (! idx_list.empty ())
703 {
704 // This is for +package and other classdef_meta objects
705 if (! base_expr_val.is_function ()
706 || base_expr_val.is_classdef_meta ())
707 {
708 try
709 {
710 retval = base_expr_val.subsref (m_type.substr (beg, n-beg),
711 idx_list, nargout);
712 beg = n;
713 idx_list.clear ();
714 }
715 catch (index_exception& ie)
716 {
717 tw.final_index_error (ie, m_expr);
718 }
719 }
720 else
721 {
722 // FIXME: we want this to only be a superclass constructor
723 // call Should we actually make a check for this or are all
724 // other types of calls already dealt with?
725
726 octave_function *fcn = base_expr_val.function_value ();
727
728 if (fcn)
729 {
730 try
731 {
732 // FIXME: is it possible for the IDX_LIST to have
733 // more than one element here? Do we need to check?
734
735 octave_value_list final_args;
736
737 if (idx_list.size () != 1)
738 error ("unexpected extra index at end of expression");
739
740 if (m_type[beg] != '(')
741 error ("invalid index type '%c' for function call",
742 m_type[beg]);
743
744 final_args = idx_list.front ();
745
746 // FIXME: Do we ever need the names of the arguments
747 // passed to FCN here?
748
749 retval = fcn->call (tw, nargout, final_args);
750 }
751 catch (index_exception& ie)
752 {
753 tw.final_index_error (ie, m_expr);
754 }
755 }
756 }
757 }
758
759 // FIXME: when can the following happen? In what case does indexing
760 // result in a value that is a function? Classdef method calls?
761 // Something else?
762
763 octave_value val = (retval.length () ? retval(0) : octave_value ());
764
765 if (val.is_function ())
766 {
767 octave_function *fcn = val.function_value (true);
768
769 if (fcn)
770 {
771 octave_value_list final_args;
772
773 if (! idx_list.empty ())
774 {
775 if (n - beg != 1)
776 error ("unexpected extra index at end of expression");
777
778 if (m_type[beg] != '(')
779 error ("invalid index type '%c' for function call",
780 m_type[beg]);
781
782 final_args = idx_list.front ();
783 }
784
785 retval = fcn->call (tw, nargout, final_args);
786 }
787 }
788
789 // Delete any temporary values prior to returning so that
790 // destructors for any temporary classdef handle objects will be
791 // called before we return.
792
793 idx_list.clear ();
794 base_expr_val = octave_value ();
795 val = octave_value ();
796
797 return retval;
798}
799
800OCTAVE_END_NAMESPACE(octave)
801
802/*
803%!test
804%! clear x;
805%! clear y;
806%! y = 3;
807%! x(y(end)) = 1;
808%! assert (x, [0, 0, 1]);
809%! clear x;
810%! clear y;
811%! y = {3};
812%! x(y{end}) = 1;
813%! assert (x, [0, 0, 1]);
814
815%!test
816%! x = {1, 2, 3};
817%! [x{:}] = deal (4, 5, 6);
818%! assert (x, {4, 5, 6});
819
820%!test
821%! [x.a, x.b.c] = deal (1, 2);
822%! assert (x.a == 1 && x.b.c == 2);
823
824%!test
825%! [x.a, x(2).b] = deal (1, 2);
826%! assert (x(1).a == 1 && isempty (x(2).a) && isempty (x(1).b) && x(2).b == 2);
827
828%!test
829%! x = struct (zeros (0, 1), {"a", "b"});
830%! x(2).b = 1;
831%! assert (x(2).b == 1);
832
833%!test
834%! x = struct (zeros (0, 1), {"a", "b"});
835%! x(2).b = 1;
836%! assert (x(2).b == 1);
837
838## Test nargout when indexing function calls
839%!
840%!function [a] = __fcell ()
841%! a = num2cell (1:5);
842%!endfunction
843%!
844%!function [a] = __fstruct ()
845%! a = struct ('a', {1, 2}, 'b', {3, 4});
846%!endfunction
847%!
848%!test # Function call at the start of the index expression
849%! [a, b] = __fcell () {1:2};
850%! assert ([a, b], [1, 2]);
851%! [a, b] = __fstruct ().b;
852%! assert ([a, b], [3, 4]);
853#!
854%!test # Function handle call at the start of the index expression
855%! f = @__fcell;
856%! [a, b] = f () {1:2};
857%! assert ([a, b], [1, 2]);
858%! f = @__fstruct;
859%! [a, b] = f ().b;
860%! assert ([a, b], [3, 4]);
861#!
862%!test # Intermediate function handle call followed by {} indexing
863%! x = {@__fcell};
864%! [a, b] = x {1} () {1:2};
865%! assert ([a, b], [1, 2]);
866%! s.f = @__fcell;
867%! [a, b] = s.f () {3:4};
868%! assert ([a, b], [3, 4]);
869%!
870%!test # Intermediate function handle call followed by . indexing
871%! x = {@__fstruct};
872%! [a, b] = x {1} ().a;
873%! assert ([a, b], [1, 2]);
874%! s.f = @__fstruct;
875%! [a, b] = s.f ().b;
876%! assert ([a, b], [3, 4]);
877%!
878%!test # Anonymous function call at the start of the index expression
879%! f = @() num2cell (1:5);
880%! [a, b] = f () {1:2};
881%! assert ([a, b], [1, 2]);
882%! f = @() struct ('a', {1, 2}, 'b', {3, 4});
883%! [a, b] = f ().b;
884%! assert ([a, b], [3, 4]);
885#!
886%!test # Intermediate anon func call followed by {} indexing
887%! x = {@() num2cell (1:5)};
888%! [a, b] = x {1} () {1:2};
889%! assert ([a, b], [1, 2]);
890%! s.f = @() num2cell (1:5);
891%! [a, b] = s.f () {3:4};
892%! assert ([a, b], [3, 4]);
893%!
894%!test # Intermediate anon func call followed by . indexing
895%! x = {@() struct ('a', {1, 2}, 'b', {3, 4})};
896%! [a, b] = x {1} ().a;
897%! assert ([a, b], [1, 2]);
898%! s.f = @() struct ('a', {1, 2}, 'b', {3, 4});
899%! [a, b] = s.f ().b;
900%! assert ([a, b], [3, 4]);
901
902%!test <*67111>
903%! function [a] = fcelln (n)
904%! if (n >= 0)
905%! a = num2cell (1:n);
906%! endif
907%! endfunction
908%!
909%! fail ("fcelln (-5) {1:3}", "indexing undefined value");
910%! fail ("fcelln (-5) (1:3)", "indexing undefined value");
911%! fail ("fcelln (-5).prop", "indexing undefined value");
912
913%!test <*67111>
914%! function [a] = fnothing ()
915%! endfunction
916%!
917%! fail ("fnothing () {1:3}", "indexing undefined value");
918%! fail ("fnothing () (1:3)", "indexing undefined value");
919%! fail ("fnothing ().prop", "indexing undefined value");
920%! fail ("fnothing () ()", "indexing undefined value");
921*/
void increment_column(int val=1)
Definition filepos.h:56
symbol_table & get_symbol_table()
virtual octave_value_list call(octave::tree_evaluator &tw, int nargout=0, const octave_value_list &args=octave_value_list())
Definition ov-fcn.cc:79
void set_index(const std::string &t, const std::list< octave_value_list > &i)
octave_value value() const
void stash_name_tags(const string_vector &nm)
Definition ovl.h:163
void clear()
Definition ovl.h:171
octave_idx_type length() const
Definition ovl.h:111
bool is_undefined() const
Definition ov.h:593
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition ov.h:474
octave_function * function_value(bool silent=false) const
bool is_classdef_meta() const
Definition ov.h:650
bool isjava() const
Definition ov.h:665
bool is_function() const
Definition ov.h:775
bool is_package() const
Definition ov.h:659
bool is_cs_list() const
Definition ov.h:668
std::string xstring_value(const char *fmt,...) const
bool isobject() const
Definition ov.h:662
bool isempty() const
Definition str-vec.h:100
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition symtab.cc:254
Definition token.h:42
filepos end_pos() const
Definition token.h:127
comment_list trailing_comments() const
Definition token.h:133
std::string text() const
Definition token.h:149
filepos end_pos() const
Definition pt-arg-list.h:86
string_vector get_arg_names() const
bool has_magic_tilde() const
tree_argument_list * mark_in_delims(const token &open_delim, const token &close_delim)
Definition pt-arg-list.h:66
comment_list trailing_comments() const
void set_indexed_object(const octave_value &obj=octave_value())
Definition pt-eval.h:728
interpreter & get_interpreter()
Definition pt-eval.h:428
void final_index_error(index_exception &ie, const tree_expression *expr)
Definition pt-eval.cc:4831
const std::list< octave_lvalue > * lvalue_list() const
Definition pt-eval.h:768
octave_value_list convert_to_const_vector(tree_argument_list *arg_list)
Definition pt-eval.cc:2363
const std::list< octave_value_list > & index_list() const
Definition pt-eval.h:733
octave_value indexed_object() const
Definition pt-eval.h:723
octave_value_list make_value_list(tree_argument_list *args, const string_vector &arg_nm)
Definition pt-eval.cc:4869
bool is_variable(const std::string &name) const
Definition pt-eval.cc:1887
const std::string & index_type() const
Definition pt-eval.h:757
void set_lvalue_list(const std::list< octave_lvalue > *lst)
Definition pt-eval.h:773
void append_index_list(char type, const octave_value_list &idx)
Definition pt-eval.h:751
void clear_index_list()
Definition pt-eval.h:745
void set_index_list(const std::string &index_type, const std::list< octave_value_list > &index_list)
Definition pt-eval.h:738
virtual octave_value evaluate(tree_evaluator &tw, int nargout=1)=0
virtual bool is_identifier() const
Definition pt-exp.h:68
tree_expression * mark_in_delims(const token &open_delim, const token &close_delim)
Definition pt-exp.h:124
virtual void copy_base(const tree_expression &e)
Definition pt-exp.h:142
virtual std::string name() const
Definition pt-exp.h:114
virtual tree_expression * dup(symbol_scope &scope) const =0
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:436
comment_list trailing_comments() const
Definition pt-idx.cc:189
filepos end_pos() const
Definition pt-idx.cc:137
tree_index_expression * dup(symbol_scope &scope) const
Definition pt-idx.cc:335
std::string name() const
Definition pt-idx.cc:131
std::list< string_vector > arg_names()
Definition pt-idx.h:90
bool is_word_list_cmd() const
Definition pt-idx.h:96
tree_index_expression(tree_expression *e, const token &open_delim, tree_argument_list *lst, const token &close_delim, char t)
Definition pt-idx.cc:49
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:238
octave_lvalue lvalue(tree_evaluator &tw)
Definition pt-idx.cc:262
tree_index_expression * append(const token &open_delim, tree_argument_list *lst, const token &close_delim, char t='(')
Definition pt-idx.cc:68
virtual filepos end_pos() const =0
virtual comment_list trailing_comments() const =0
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void error(const char *fmt,...)
Definition error.cc:1008
void err_indexed_cs_list()
Definition errwarn.cc:65
#define panic_if(cond)
Definition panic.h:57