blob: eff4bdccc44ed5d9c18336deae546fa0e867193a [file] [log] [blame]
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * tuple.c: Tuple support functions.
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17
18// Tuple heads for garbage collection.
19static tuple_T *first_tuple = NULL; // list of all tuples
20
21 static void
22tuple_init(tuple_T *tuple)
23{
24 // Prepend the tuple to the list of tuples for garbage collection.
25 if (first_tuple != NULL)
26 first_tuple->tv_used_prev = tuple;
27 tuple->tv_used_prev = NULL;
28 tuple->tv_used_next = first_tuple;
29 first_tuple = tuple;
30
31 ga_init2(&tuple->tv_items, sizeof(typval_T), 20);
32}
33
34/*
35 * Allocate an empty header for a tuple.
36 * Caller should take care of the reference count.
37 */
38 tuple_T *
39tuple_alloc(void)
40{
41 tuple_T *tuple;
42
43 tuple = ALLOC_CLEAR_ONE(tuple_T);
44 if (tuple != NULL)
45 tuple_init(tuple);
46 return tuple;
47}
48
49/*
50 * Allocate space for a tuple with "count" items.
51 * This uses one allocation for efficiency.
52 * The reference count is not set.
53 * Next tuple_set_item() must be called for each item.
54 */
55 tuple_T *
56tuple_alloc_with_items(int count)
57{
58 tuple_T *tuple;
59
60 tuple = tuple_alloc();
61 if (tuple == NULL)
62 return NULL;
63
64 if (count <= 0)
65 return tuple;
66
67 if (ga_grow(&tuple->tv_items, count) == FAIL)
68 {
69 tuple_free(tuple);
70 return NULL;
71 }
72
73 return tuple;
74}
75
76/*
77 * Set item "idx" for a tuple previously allocated with
78 * tuple_alloc_with_items().
79 * The contents of "tv" is copied into the tuple item.
80 * Each item must be set exactly once.
81 */
82 void
83tuple_set_item(tuple_T *tuple, int idx, typval_T *tv)
84{
85 *TUPLE_ITEM(tuple, idx) = *tv;
86 tuple->tv_items.ga_len++;
87}
88
89/*
90 * Allocate an empty tuple for a return value, with reference count set.
91 * Returns OK or FAIL.
92 */
93 int
94rettv_tuple_alloc(typval_T *rettv)
95{
96 tuple_T *tuple = tuple_alloc();
97
98 if (tuple == NULL)
99 return FAIL;
100
101 rettv->v_lock = 0;
102 rettv_tuple_set(rettv, tuple);
103 return OK;
104}
105
106/*
107 * Set a tuple as the return value. Increments the reference count.
108 */
109 void
110rettv_tuple_set(typval_T *rettv, tuple_T *tuple)
111{
112 rettv->v_type = VAR_TUPLE;
113 rettv->vval.v_tuple = tuple;
114 if (tuple != NULL)
115 ++tuple->tv_refcount;
116}
117
118/*
119 * Set a new tuple with "count" items as the return value.
120 * Returns OK on success and FAIL on allocation failure.
121 */
122 int
123rettv_tuple_set_with_items(typval_T *rettv, int count)
124{
125 tuple_T *new_tuple;
126
127 new_tuple = tuple_alloc_with_items(count);
128 if (new_tuple == NULL)
129 return FAIL;
130
131 rettv_tuple_set(rettv, new_tuple);
132
133 return OK;
134}
135
136/*
137 * Unreference a tuple: decrement the reference count and free it when it
138 * becomes zero.
139 */
140 void
141tuple_unref(tuple_T *tuple)
142{
143 if (tuple != NULL && --tuple->tv_refcount <= 0)
144 tuple_free(tuple);
145}
146
147/*
148 * Free a tuple, including all non-container items it points to.
149 * Ignores the reference count.
150 */
151 static void
152tuple_free_contents(tuple_T *tuple)
153{
154 for (int i = 0; i < TUPLE_LEN(tuple); i++)
155 clear_tv(TUPLE_ITEM(tuple, i));
156
157 ga_clear(&tuple->tv_items);
158}
159
160/*
161 * Go through the list of tuples and free items without the copyID.
162 * But don't free a tuple that has a watcher (used in a for loop), these
163 * are not referenced anywhere.
164 */
165 int
166tuple_free_nonref(int copyID)
167{
168 tuple_T *tt;
169 int did_free = FALSE;
170
171 for (tt = first_tuple; tt != NULL; tt = tt->tv_used_next)
172 if ((tt->tv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
173 {
174 // Free the Tuple and ordinary items it contains, but don't recurse
175 // into Lists and Dictionaries, they will be in the list of dicts
176 // or list of lists.
177 tuple_free_contents(tt);
178 did_free = TRUE;
179 }
180 return did_free;
181}
182
183 static void
184tuple_free_list(tuple_T *tuple)
185{
186 // Remove the tuple from the list of tuples for garbage collection.
187 if (tuple->tv_used_prev == NULL)
188 first_tuple = tuple->tv_used_next;
189 else
190 tuple->tv_used_prev->tv_used_next = tuple->tv_used_next;
191 if (tuple->tv_used_next != NULL)
192 tuple->tv_used_next->tv_used_prev = tuple->tv_used_prev;
193
194 free_type(tuple->tv_type);
195 vim_free(tuple);
196}
197
198 void
199tuple_free_items(int copyID)
200{
201 tuple_T *tt, *tt_next;
202
203 for (tt = first_tuple; tt != NULL; tt = tt_next)
204 {
205 tt_next = tt->tv_used_next;
206 if ((tt->tv_copyID & COPYID_MASK) != (copyID & COPYID_MASK))
207 {
208 // Free the tuple and ordinary items it contains, but don't recurse
209 // into Lists and Dictionaries, they will be in the list of dicts
210 // or list of lists.
211 tuple_free_list(tt);
212 }
213 }
214}
215
216 void
217tuple_free(tuple_T *tuple)
218{
219 if (in_free_unref_items)
220 return;
221
222 tuple_free_contents(tuple);
223 tuple_free_list(tuple);
224}
225
226/*
227 * Get the number of items in a tuple.
228 */
229 long
230tuple_len(tuple_T *tuple)
231{
232 if (tuple == NULL)
233 return 0L;
234 return tuple->tv_items.ga_len;
235}
236
237/*
238 * Return TRUE when two tuples have exactly the same values.
239 */
240 int
241tuple_equal(
242 tuple_T *t1,
243 tuple_T *t2,
244 int ic) // ignore case for strings
245{
246 if (t1 == t2)
247 return TRUE;
248
249 int t1_len = tuple_len(t1);
250 int t2_len = tuple_len(t2);
251
252 if (t1_len != t2_len)
253 return FALSE;
254
255 if (t1_len == 0)
256 // empty and NULL tuples are considered equal
257 return TRUE;
258
259 // If the tuples "t1" or "t2" is NULL, then it is handled by the length
260 // checks above.
261
262 for (int i = 0, j = 0; i < t1_len && j < t2_len; i++, j++)
263 if (!tv_equal(TUPLE_ITEM(t1, i), TUPLE_ITEM(t2, j), ic))
264 return FALSE;
265
266 return TRUE;
267}
268
269/*
270 * Locate item with index "n" in tuple "tuple" and return it.
271 * A negative index is counted from the end; -1 is the last item.
272 * Returns NULL when "n" is out of range.
273 */
274 typval_T *
275tuple_find(tuple_T *tuple, long n)
276{
277 if (tuple == NULL)
278 return NULL;
279
280 // Negative index is relative to the end.
281 if (n < 0)
282 n = TUPLE_LEN(tuple) + n;
283
284 // Check for index out of range.
285 if (n < 0 || n >= TUPLE_LEN(tuple))
286 return NULL;
287
288 return TUPLE_ITEM(tuple, n);
289}
290
291 int
292tuple_append_tv(tuple_T *tuple, typval_T *tv)
293{
294 if (ga_grow(&tuple->tv_items, 1) == FAIL)
295 return FAIL;
296
297 tuple_set_item(tuple, TUPLE_LEN(tuple), tv);
298
299 return OK;
300}
301
302/*
303 * Concatenate tuples "t1" and "t2" into a new tuple, stored in "tv".
304 * Return FAIL when out of memory.
305 */
306 int
307tuple_concat(tuple_T *t1, tuple_T *t2, typval_T *tv)
308{
309 tuple_T *tuple;
310
311 // make a copy of the first tuple.
312 if (t1 == NULL)
313 tuple = tuple_alloc();
314 else
315 tuple = tuple_copy(t1, FALSE, TRUE, 0);
316 if (tuple == NULL)
317 return FAIL;
318
319 tv->v_type = VAR_TUPLE;
320 tv->v_lock = 0;
321 tv->vval.v_tuple = tuple;
322 if (t1 == NULL)
323 ++tuple->tv_refcount;
324
325 // append all the items from the second tuple
326 for (int i = 0; i < tuple_len(t2); i++)
327 {
328 typval_T new_tv;
329
330 copy_tv(TUPLE_ITEM(t2, i), &new_tv);
331
332 if (tuple_append_tv(tuple, &new_tv) == FAIL)
333 {
334 tuple_free(tuple);
335 return FAIL;
336 }
337 }
338
339 return OK;
340}
341
342/*
343 * Return a slice of tuple starting at index n1 and ending at index n2,
344 * inclusive (tuple[n1 : n2])
345 */
346 tuple_T *
347tuple_slice(tuple_T *tuple, long n1, long n2)
348{
349 tuple_T *new_tuple;
350
351 new_tuple = tuple_alloc_with_items(n2 - n1 + 1);
352 if (new_tuple == NULL)
353 return NULL;
354
355 for (int i = n1; i <= n2; i++)
356 {
357 typval_T new_tv;
358
359 copy_tv(TUPLE_ITEM(tuple, i), &new_tv);
360
361 if (tuple_append_tv(new_tuple, &new_tv) == FAIL)
362 {
363 tuple_free(new_tuple);
364 return NULL;
365 }
366 }
367
368 return new_tuple;
369}
370
371 int
372tuple_slice_or_index(
373 tuple_T *tuple,
374 int range,
375 varnumber_T n1_arg,
376 varnumber_T n2_arg,
377 int exclusive,
378 typval_T *rettv,
379 int verbose)
380{
381 long len = tuple_len(tuple);
382 varnumber_T n1 = n1_arg;
383 varnumber_T n2 = n2_arg;
384 typval_T var1;
385
386 if (n1 < 0)
387 n1 = len + n1;
388 if (n1 < 0 || n1 >= len)
389 {
390 // For a range we allow invalid values and for legacy script return an
391 // empty tuple, for Vim9 script start at the first item.
392 // A tuple index out of range is an error.
393 if (!range)
394 {
395 if (verbose)
396 semsg(_(e_tuple_index_out_of_range_nr), (long)n1_arg);
397 return FAIL;
398 }
399 if (in_vim9script())
400 n1 = n1 < 0 ? 0 : len;
401 else
402 n1 = len;
403 }
404 if (range)
405 {
406 tuple_T *new_tuple;
407
408 if (n2 < 0)
409 n2 = len + n2;
410 else if (n2 >= len)
411 n2 = len - (exclusive ? 0 : 1);
412 if (exclusive)
413 --n2;
414 if (n2 < 0 || n2 + 1 < n1)
415 n2 = -1;
416 new_tuple = tuple_slice(tuple, n1, n2);
417 if (new_tuple == NULL)
418 return FAIL;
419 clear_tv(rettv);
420 rettv_tuple_set(rettv, new_tuple);
421 }
422 else
423 {
424 // copy the item to "var1" to avoid that freeing the tuple makes it
425 // invalid.
426 copy_tv(tuple_find(tuple, n1), &var1);
427 clear_tv(rettv);
428 *rettv = var1;
429 }
430 return OK;
431}
432
433/*
434 * Make a copy of tuple "orig". Shallow if "deep" is FALSE.
435 * The refcount of the new tuple is set to 1.
436 * See item_copy() for "top" and "copyID".
437 * Returns NULL when out of memory.
438 */
439 tuple_T *
440tuple_copy(tuple_T *orig, int deep, int top, int copyID)
441{
442 tuple_T *copy;
443 int idx;
444
445 if (orig == NULL)
446 return NULL;
447
448 copy = tuple_alloc_with_items(TUPLE_LEN(orig));
449 if (copy == NULL)
450 return NULL;
451
452 if (orig->tv_type == NULL || top || deep)
453 copy->tv_type = NULL;
454 else
455 copy->tv_type = alloc_type(orig->tv_type);
456 if (copyID != 0)
457 {
458 // Do this before adding the items, because one of the items may
459 // refer back to this tuple.
460 orig->tv_copyID = copyID;
461 orig->tv_copytuple = copy;
462 }
463
464 for (idx = 0; idx < TUPLE_LEN(orig) && !got_int; idx++)
465 {
466 copy->tv_items.ga_len++;
467 if (deep)
468 {
469 if (item_copy(TUPLE_ITEM(orig, idx), TUPLE_ITEM(copy, idx),
470 deep, FALSE, copyID) == FAIL)
471 break;
472 }
473 else
474 copy_tv(TUPLE_ITEM(orig, idx), TUPLE_ITEM(copy, idx));
475 }
476
477 ++copy->tv_refcount;
478 if (idx != TUPLE_LEN(orig))
479 {
480 tuple_unref(copy);
481 copy = NULL;
482 }
483
484 return copy;
485}
486
487/*
488 * Allocate a variable for a tuple and fill it from "*arg".
489 * "*arg" points to the "," after the first element.
490 * "rettv" contains the first element.
491 * Returns OK or FAIL.
492 */
493 int
494eval_tuple(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int do_error)
495{
496 int evaluate = evalarg == NULL ? FALSE
497 : evalarg->eval_flags & EVAL_EVALUATE;
498 tuple_T *tuple = NULL;
499 typval_T tv;
500 int vim9script = in_vim9script();
501 int had_comma;
502
503 if (check_typval_is_value(rettv) == FAIL)
504 {
505 // the first item is not a valid value type
506 clear_tv(rettv);
507 return FAIL;
508 }
509
510 if (evaluate)
511 {
512 tuple = tuple_alloc();
513 if (tuple == NULL)
514 return FAIL;
515
516 if (rettv->v_type != VAR_UNKNOWN)
517 {
518 // Add the first item to the tuple from "rettv"
519 if (tuple_append_tv(tuple, rettv) == FAIL)
520 return FAIL;
521 }
522 }
523
524 if (**arg == ')')
525 // empty tuple
526 goto done;
527
528 if (vim9script && !IS_WHITE_NL_OR_NUL((*arg)[1]) && (*arg)[1] != ')')
529 {
530 semsg(_(e_white_space_required_after_str_str), ",", *arg);
531 goto failret;
532 }
533
534 *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
535 while (**arg != ')' && **arg != NUL)
536 {
537 if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
538 goto failret;
539 if (check_typval_is_value(&tv) == FAIL)
540 {
541 if (evaluate)
542 clear_tv(&tv);
543 goto failret;
544 }
545
546 if (evaluate)
547 {
548 if (tuple_append_tv(tuple, &tv) == FAIL)
549 {
550 clear_tv(&tv);
551 goto failret;
552 }
553 }
554
555 if (!vim9script)
556 *arg = skipwhite(*arg);
557
558 // the comma must come after the value
559 had_comma = **arg == ',';
560 if (had_comma)
561 {
562 if (vim9script && !IS_WHITE_NL_OR_NUL((*arg)[1]) && (*arg)[1] != ')')
563 {
564 semsg(_(e_white_space_required_after_str_str), ",", *arg);
565 goto failret;
566 }
567 *arg = skipwhite(*arg + 1);
568 }
569
570 // The ")" can be on the next line. But a double quoted string may
571 // follow, not a comment.
572 *arg = skipwhite_and_linebreak(*arg, evalarg);
573 if (**arg == ')')
574 break;
575
576 if (!had_comma)
577 {
578 if (do_error)
579 {
580 if (**arg == ',')
581 semsg(_(e_no_white_space_allowed_before_str_str),
582 ",", *arg);
583 else
584 semsg(_(e_missing_comma_in_tuple_str), *arg);
585 }
586 goto failret;
587 }
588 }
589
590 if (**arg != ')')
591 {
592 if (do_error)
593 semsg(_(e_missing_end_of_tuple_rsp_str), *arg);
594failret:
595 if (evaluate)
596 tuple_free(tuple);
597 return FAIL;
598 }
599
600done:
601 *arg += 1;
602 if (evaluate)
603 rettv_tuple_set(rettv, tuple);
604
605 return OK;
606}
607
608/*
609 * Lock or unlock a tuple. "deep" is number of levels to go.
610 * When "check_refcount" is TRUE do not lock a tuple with a reference
611 * count larger than 1.
612 */
613 void
614tuple_lock(tuple_T *tuple, int deep, int lock, int check_refcount)
615{
616 if (tuple == NULL || (check_refcount && tuple->tv_refcount > 1))
617 return;
618
619 if (lock)
620 tuple->tv_lock |= VAR_LOCKED;
621 else
622 tuple->tv_lock &= ~VAR_LOCKED;
623
624 if (deep < 0 || deep > 1)
625 {
626 // recursive: lock/unlock the items the Tuple contains
627 for (int i = 0; i < TUPLE_LEN(tuple); i++)
628 item_lock(TUPLE_ITEM(tuple, i), deep - 1, lock, check_refcount);
629 }
630}
631
632typedef struct join_S {
633 char_u *s;
634 char_u *tofree;
635} join_T;
636
637 static int
638tuple_join_inner(
639 garray_T *gap, // to store the result in
640 tuple_T *tuple,
641 char_u *sep,
642 int echo_style,
643 int restore_copyID,
644 int copyID,
645 garray_T *join_gap) // to keep each tuple item string
646{
647 int i;
648 join_T *p;
649 int len;
650 int sumlen = 0;
651 int first = TRUE;
652 char_u *tofree;
653 char_u numbuf[NUMBUFLEN];
654 char_u *s;
655 typval_T *tv;
656
657 // Stringify each item in the tuple.
658 for (i = 0; i < TUPLE_LEN(tuple) && !got_int; i++)
659 {
660 tv = TUPLE_ITEM(tuple, i);
661 s = echo_string_core(tv, &tofree, numbuf, copyID,
662 echo_style, restore_copyID, !echo_style);
663 if (s == NULL)
664 return FAIL;
665
666 len = (int)STRLEN(s);
667 sumlen += len;
668
669 (void)ga_grow(join_gap, 1);
670 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
671 if (tofree != NULL || s != numbuf)
672 {
673 p->s = s;
674 p->tofree = tofree;
675 }
676 else
677 {
678 p->s = vim_strnsave(s, len);
679 p->tofree = p->s;
680 }
681
682 line_breakcheck();
683 if (did_echo_string_emsg) // recursion error, bail out
684 break;
685 }
686
687 // Allocate result buffer with its total size, avoid re-allocation and
688 // multiple copy operations. Add 2 for a tailing ')' and NUL.
689 if (join_gap->ga_len >= 2)
690 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
691 if (ga_grow(gap, sumlen + 2) == FAIL)
692 return FAIL;
693
694 for (i = 0; i < join_gap->ga_len && !got_int; ++i)
695 {
696 if (first)
697 first = FALSE;
698 else
699 ga_concat(gap, sep);
700 p = ((join_T *)join_gap->ga_data) + i;
701
702 if (p->s != NULL)
703 ga_concat(gap, p->s);
704 line_breakcheck();
705 }
706
707 // If there is only one item in the tuple, then add the separator after
708 // that.
709 if (join_gap->ga_len == 1)
710 ga_concat(gap, sep);
711
712 return OK;
713}
714
715/*
716 * Join tuple "tuple" into a string in "*gap", using separator "sep".
717 * When "echo_style" is TRUE use String as echoed, otherwise as inside a Tuple.
718 * Return FAIL or OK.
719 */
720 int
721tuple_join(
722 garray_T *gap,
723 tuple_T *tuple,
724 char_u *sep,
725 int echo_style,
726 int restore_copyID,
727 int copyID)
728{
729 garray_T join_ga;
730 int retval;
731 join_T *p;
732 int i;
733
734 if (TUPLE_LEN(tuple) < 1)
735 return OK; // nothing to do
736 ga_init2(&join_ga, sizeof(join_T), TUPLE_LEN(tuple));
737 retval = tuple_join_inner(gap, tuple, sep, echo_style, restore_copyID,
738 copyID, &join_ga);
739
740 if (join_ga.ga_data == NULL)
741 return retval;
742
743 // Dispose each item in join_ga.
744 p = (join_T *)join_ga.ga_data;
745 for (i = 0; i < join_ga.ga_len; ++i)
746 {
747 vim_free(p->tofree);
748 ++p;
749 }
750 ga_clear(&join_ga);
751
752 return retval;
753}
754
755/*
756 * Return an allocated string with the string representation of a tuple.
757 * May return NULL.
758 */
759 char_u *
760tuple2string(typval_T *tv, int copyID, int restore_copyID)
761{
762 garray_T ga;
763
764 if (tv->vval.v_tuple == NULL)
765 return NULL;
766 ga_init2(&ga, sizeof(char), 80);
767 ga_append(&ga, '(');
768 if (tuple_join(&ga, tv->vval.v_tuple, (char_u *)", ",
769 FALSE, restore_copyID, copyID) == FAIL)
770 {
771 vim_free(ga.ga_data);
772 return NULL;
773 }
774 ga_append(&ga, ')');
775 ga_append(&ga, NUL);
776 return (char_u *)ga.ga_data;
777}
778
779/*
780 * Implementation of foreach() for a Tuple. Apply "expr" to
781 * every item in Tuple "tuple" and return the result in "rettv".
782 */
783 void
784tuple_foreach(
785 tuple_T *tuple,
786 filtermap_T filtermap,
787 typval_T *expr)
788{
789 int len = tuple_len(tuple);
790 int rem;
791 typval_T newtv;
792 funccall_T *fc;
793
794 // set_vim_var_nr() doesn't set the type
795 set_vim_var_type(VV_KEY, VAR_NUMBER);
796
797 // Create one funccall_T for all eval_expr_typval() calls.
798 fc = eval_expr_get_funccal(expr, &newtv);
799
800 for (int idx = 0; idx < len; idx++)
801 {
802 set_vim_var_nr(VV_KEY, idx);
803 if (filter_map_one(TUPLE_ITEM(tuple, idx), expr, filtermap, fc,
804 &newtv, &rem) == FAIL)
805 break;
806 }
807
808 if (fc != NULL)
809 remove_funccal();
810}
811
812/*
813 * Count the number of times item "needle" occurs in Tuple "l" starting at index
814 * "idx". Case is ignored if "ic" is TRUE.
815 */
816 long
817tuple_count(tuple_T *tuple, typval_T *needle, long idx, int ic)
818{
819 long n = 0;
820
821 if (tuple == NULL)
822 return 0;
823
824 int len = TUPLE_LEN(tuple);
825 if (len == 0)
826 return 0;
827
828 if (idx < 0 || idx >= len)
829 {
830 semsg(_(e_tuple_index_out_of_range_nr), idx);
831 return 0;
832 }
833
834 for (int i = idx; i < len; i++)
835 {
836 if (tv_equal(TUPLE_ITEM(tuple, i), needle, ic))
837 ++n;
838 }
839
840 return n;
841}
842
843/*
844 * "items(tuple)" function
845 * Caller must have already checked that argvars[0] is a tuple.
846 */
847 void
848tuple2items(typval_T *argvars, typval_T *rettv)
849{
850 tuple_T *tuple = argvars[0].vval.v_tuple;
851 varnumber_T idx;
852
853 if (rettv_list_alloc(rettv) == FAIL)
854 return;
855
856 if (tuple == NULL)
857 return; // null tuple behaves like an empty list
858
859 for (idx = 0; idx < TUPLE_LEN(tuple); idx++)
860 {
861 list_T *l = list_alloc();
862
863 if (l == NULL)
864 break;
865
866 if (list_append_list(rettv->vval.v_list, l) == FAIL)
867 {
868 vim_free(l);
869 break;
870 }
871 if (list_append_number(l, idx) == FAIL
872 || list_append_tv(l, TUPLE_ITEM(tuple, idx)) == FAIL)
873 break;
874 }
875}
876
877/*
878 * Search for item "tv" in tuple "tuple" starting from index "start_idx".
879 * If "ic" is set to TRUE, then case is ignored.
880 *
881 * Returns the index where "tv" is present or -1 if it is not found.
882 */
883 int
884index_tuple(tuple_T *tuple, typval_T *tv, int start_idx, int ic)
885{
886 if (start_idx < 0)
887 {
888 start_idx = TUPLE_LEN(tuple) + start_idx;
889 if (start_idx < 0)
890 start_idx = 0;
891 }
892
893 for (int idx = start_idx; idx < TUPLE_LEN(tuple); idx++)
894 {
895 if (tv_equal(TUPLE_ITEM(tuple, idx), tv, ic))
896 return idx;
897 }
898
899 return -1; // "tv" not found
900}
901
902/*
903 * Evaluate 'expr' for each item in the Tuple 'tuple' starting with the item at
904 * 'startidx' and return the index of the item where 'expr' is TRUE. Returns
905 * -1 if 'expr' doesn't evaluate to TRUE for any of the items.
906 */
907 int
908indexof_tuple(tuple_T *tuple, long startidx, typval_T *expr)
909{
910 long idx = 0;
911 int len;
912 int found;
913
914 if (tuple == NULL)
915 return -1;
916
917 len = TUPLE_LEN(tuple);
918
919 if (startidx < 0)
920 {
921 // negative index: index from the end
922 startidx = len + startidx;
923 if (startidx < 0)
924 startidx = 0;
925 }
926
927 set_vim_var_type(VV_KEY, VAR_NUMBER);
928
929 int called_emsg_start = called_emsg;
930
931 for (idx = startidx; idx < len; idx++)
932 {
933 set_vim_var_nr(VV_KEY, idx);
934 copy_tv(TUPLE_ITEM(tuple, idx), get_vim_var_tv(VV_VAL));
935
936 found = indexof_eval_expr(expr);
937 clear_tv(get_vim_var_tv(VV_VAL));
938
939 if (found)
940 return idx;
941
942 if (called_emsg != called_emsg_start)
943 return -1;
944 }
945
946 return -1;
947}
948
949/*
950 * Return the max or min of the items in tuple "tuple".
951 * If a tuple item is not a number, then "error" is set to TRUE.
952 */
953 varnumber_T
954tuple_max_min(tuple_T *tuple, int domax, int *error)
955{
956 varnumber_T n = 0;
957 varnumber_T v;
958
959 if (tuple == NULL || TUPLE_LEN(tuple) == 0)
960 return 0;
961
962 n = tv_get_number_chk(TUPLE_ITEM(tuple, 0), error);
963 if (*error)
964 return n; // type error; errmsg already given
965
966 for (int idx = 1; idx < TUPLE_LEN(tuple); idx++)
967 {
968 v = tv_get_number_chk(TUPLE_ITEM(tuple, idx), error);
969 if (*error)
970 return n; // type error; errmsg already given
971 if (domax ? v > n : v < n)
972 n = v;
973 }
974
975 return n;
976}
977
978/*
979 * Repeat the tuple "tuple" "n" times and set "rettv" to the new tuple.
980 */
981 void
982tuple_repeat(tuple_T *tuple, int n, typval_T *rettv)
983{
984 rettv->v_type = VAR_TUPLE;
985 rettv->vval.v_tuple = NULL;
986
987 if (tuple == NULL || TUPLE_LEN(tuple) == 0 || n <= 0)
988 return;
989
990 if (rettv_tuple_set_with_items(rettv, TUPLE_LEN(tuple) * n) == FAIL)
991 return;
992
993 tuple_T *new_tuple = rettv->vval.v_tuple;
994 for (int count = 0; count < n; count++)
995 {
996 for (int idx = 0; idx < TUPLE_LEN(tuple); idx++)
997 {
998 copy_tv(TUPLE_ITEM(tuple, idx),
999 TUPLE_ITEM(new_tuple, TUPLE_LEN(new_tuple)));
1000 new_tuple->tv_items.ga_len++;
1001 }
1002 }
1003}
1004
1005/*
1006 * Reverse "tuple" and return the new tuple in "rettv"
1007 */
1008 void
1009tuple_reverse(tuple_T *tuple, typval_T *rettv)
1010{
1011 rettv->v_type = VAR_TUPLE;
1012 rettv->vval.v_tuple = NULL;
1013
1014 int len = tuple_len(tuple);
1015
1016 if (len == 0)
1017 return;
1018
1019 if (rettv_tuple_set_with_items(rettv, len) == FAIL)
1020 return;
1021
1022 tuple_T *new_tuple = rettv->vval.v_tuple;
1023 for (int i = 0; i < len; i++)
1024 copy_tv(TUPLE_ITEM(tuple, i), TUPLE_ITEM(new_tuple, len - i - 1));
1025 new_tuple->tv_items.ga_len = tuple->tv_items.ga_len;
1026}
1027
1028/*
1029 * Tuple reduce() function
1030 */
1031 void
1032tuple_reduce(typval_T *argvars, typval_T *expr, typval_T *rettv)
1033{
1034 tuple_T *tuple = argvars[0].vval.v_tuple;
1035 int called_emsg_start = called_emsg;
1036 typval_T initial;
1037 int idx = 0;
1038 funccall_T *fc;
1039 typval_T argv[3];
1040 int r;
1041
1042 if (argvars[2].v_type == VAR_UNKNOWN)
1043 {
1044 if (tuple == NULL || TUPLE_LEN(tuple) == 0)
1045 {
1046 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Tuple");
1047 return;
1048 }
1049 initial = *TUPLE_ITEM(tuple, 0);
1050 idx = 1;
1051 }
1052 else
1053 {
1054 initial = argvars[2];
1055 idx = 0;
1056 }
1057
1058 copy_tv(&initial, rettv);
1059
1060 if (tuple == NULL)
1061 return;
1062
1063 // Create one funccall_T for all eval_expr_typval() calls.
1064 fc = eval_expr_get_funccal(expr, rettv);
1065
1066 for ( ; idx < TUPLE_LEN(tuple); idx++)
1067 {
1068 argv[0] = *rettv;
1069 rettv->v_type = VAR_UNKNOWN;
1070 argv[1] = *TUPLE_ITEM(tuple, idx);
1071
1072 r = eval_expr_typval(expr, TRUE, argv, 2, fc, rettv);
1073
1074 clear_tv(&argv[0]);
1075
1076 if (r == FAIL || called_emsg != called_emsg_start)
1077 break;
1078 }
1079
1080 if (fc != NULL)
1081 remove_funccal();
1082}
1083
1084/*
1085 * Returns TRUE if two tuples with types "type1" and "type2" are addable.
1086 * Otherwise returns FALSE.
1087 */
1088 int
1089check_tuples_addable(type_T *type1, type_T *type2)
1090{
1091 int addable = TRUE;
1092
1093 // If the first operand is a variadic tuple and the second argument is
1094 // non-variadic, then concatenation is not possible.
1095 if ((type1->tt_flags & TTFLAG_VARARGS)
1096 && !(type2->tt_flags & TTFLAG_VARARGS)
1097 && (type2->tt_argcount > 0))
1098 addable = FALSE;
1099
1100 if ((type1->tt_flags & TTFLAG_VARARGS)
1101 && (type2->tt_flags & TTFLAG_VARARGS))
1102 {
1103 // two variadic tuples
1104 if (type1->tt_argcount > 1 || type2->tt_argcount > 1)
1105 // one of the variadic tuple has fixed number of items
1106 addable = FALSE;
1107 else if ((type1->tt_argcount == 1 && type2->tt_argcount == 1)
1108 && !equal_type(type1->tt_args[0], type2->tt_args[0], 0))
1109 // the tuples have different item types
1110 addable = FALSE;
1111 }
1112
1113 if (!addable)
1114 {
1115 emsg(_(e_cannot_use_variadic_tuple_in_concatenation));
1116 return FAIL;
1117 }
1118
1119 return OK;
1120}
1121
1122#endif // defined(FEAT_EVAL)