blob: 9ca1f34092d693a8e4f1a55cae4e17f89785afe3 [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;
Yegappan Lakshmanan97720252025-05-23 17:39:44 +0200521 // The first item in "rettv" is added to the tuple. Set the rettv
522 // type to unknown, so that the caller doesn't free it.
523 rettv->v_type = VAR_UNKNOWN;
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +0100524 }
525 }
526
527 if (**arg == ')')
528 // empty tuple
529 goto done;
530
531 if (vim9script && !IS_WHITE_NL_OR_NUL((*arg)[1]) && (*arg)[1] != ')')
532 {
533 semsg(_(e_white_space_required_after_str_str), ",", *arg);
534 goto failret;
535 }
536
537 *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
538 while (**arg != ')' && **arg != NUL)
539 {
540 if (eval1(arg, &tv, evalarg) == FAIL) // recursive!
541 goto failret;
542 if (check_typval_is_value(&tv) == FAIL)
543 {
544 if (evaluate)
545 clear_tv(&tv);
546 goto failret;
547 }
548
549 if (evaluate)
550 {
551 if (tuple_append_tv(tuple, &tv) == FAIL)
552 {
553 clear_tv(&tv);
554 goto failret;
555 }
556 }
557
558 if (!vim9script)
559 *arg = skipwhite(*arg);
560
561 // the comma must come after the value
562 had_comma = **arg == ',';
563 if (had_comma)
564 {
565 if (vim9script && !IS_WHITE_NL_OR_NUL((*arg)[1]) && (*arg)[1] != ')')
566 {
567 semsg(_(e_white_space_required_after_str_str), ",", *arg);
568 goto failret;
569 }
570 *arg = skipwhite(*arg + 1);
571 }
572
573 // The ")" can be on the next line. But a double quoted string may
574 // follow, not a comment.
575 *arg = skipwhite_and_linebreak(*arg, evalarg);
576 if (**arg == ')')
577 break;
578
579 if (!had_comma)
580 {
581 if (do_error)
582 {
583 if (**arg == ',')
584 semsg(_(e_no_white_space_allowed_before_str_str),
585 ",", *arg);
586 else
587 semsg(_(e_missing_comma_in_tuple_str), *arg);
588 }
589 goto failret;
590 }
591 }
592
593 if (**arg != ')')
594 {
595 if (do_error)
596 semsg(_(e_missing_end_of_tuple_rsp_str), *arg);
597failret:
598 if (evaluate)
599 tuple_free(tuple);
600 return FAIL;
601 }
602
603done:
604 *arg += 1;
605 if (evaluate)
606 rettv_tuple_set(rettv, tuple);
607
608 return OK;
609}
610
611/*
612 * Lock or unlock a tuple. "deep" is number of levels to go.
613 * When "check_refcount" is TRUE do not lock a tuple with a reference
614 * count larger than 1.
615 */
616 void
617tuple_lock(tuple_T *tuple, int deep, int lock, int check_refcount)
618{
619 if (tuple == NULL || (check_refcount && tuple->tv_refcount > 1))
620 return;
621
622 if (lock)
623 tuple->tv_lock |= VAR_LOCKED;
624 else
625 tuple->tv_lock &= ~VAR_LOCKED;
626
627 if (deep < 0 || deep > 1)
628 {
629 // recursive: lock/unlock the items the Tuple contains
630 for (int i = 0; i < TUPLE_LEN(tuple); i++)
631 item_lock(TUPLE_ITEM(tuple, i), deep - 1, lock, check_refcount);
632 }
633}
634
635typedef struct join_S {
636 char_u *s;
637 char_u *tofree;
638} join_T;
639
640 static int
641tuple_join_inner(
642 garray_T *gap, // to store the result in
643 tuple_T *tuple,
644 char_u *sep,
645 int echo_style,
646 int restore_copyID,
647 int copyID,
648 garray_T *join_gap) // to keep each tuple item string
649{
650 int i;
651 join_T *p;
652 int len;
653 int sumlen = 0;
654 int first = TRUE;
655 char_u *tofree;
656 char_u numbuf[NUMBUFLEN];
657 char_u *s;
658 typval_T *tv;
659
660 // Stringify each item in the tuple.
661 for (i = 0; i < TUPLE_LEN(tuple) && !got_int; i++)
662 {
663 tv = TUPLE_ITEM(tuple, i);
664 s = echo_string_core(tv, &tofree, numbuf, copyID,
665 echo_style, restore_copyID, !echo_style);
666 if (s == NULL)
667 return FAIL;
668
669 len = (int)STRLEN(s);
670 sumlen += len;
671
672 (void)ga_grow(join_gap, 1);
673 p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
674 if (tofree != NULL || s != numbuf)
675 {
676 p->s = s;
677 p->tofree = tofree;
678 }
679 else
680 {
681 p->s = vim_strnsave(s, len);
682 p->tofree = p->s;
683 }
684
685 line_breakcheck();
686 if (did_echo_string_emsg) // recursion error, bail out
687 break;
688 }
689
690 // Allocate result buffer with its total size, avoid re-allocation and
691 // multiple copy operations. Add 2 for a tailing ')' and NUL.
692 if (join_gap->ga_len >= 2)
693 sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
694 if (ga_grow(gap, sumlen + 2) == FAIL)
695 return FAIL;
696
697 for (i = 0; i < join_gap->ga_len && !got_int; ++i)
698 {
699 if (first)
700 first = FALSE;
701 else
702 ga_concat(gap, sep);
703 p = ((join_T *)join_gap->ga_data) + i;
704
705 if (p->s != NULL)
706 ga_concat(gap, p->s);
707 line_breakcheck();
708 }
709
710 // If there is only one item in the tuple, then add the separator after
711 // that.
712 if (join_gap->ga_len == 1)
713 ga_concat(gap, sep);
714
715 return OK;
716}
717
718/*
719 * Join tuple "tuple" into a string in "*gap", using separator "sep".
720 * When "echo_style" is TRUE use String as echoed, otherwise as inside a Tuple.
721 * Return FAIL or OK.
722 */
723 int
724tuple_join(
725 garray_T *gap,
726 tuple_T *tuple,
727 char_u *sep,
728 int echo_style,
729 int restore_copyID,
730 int copyID)
731{
732 garray_T join_ga;
733 int retval;
734 join_T *p;
735 int i;
736
737 if (TUPLE_LEN(tuple) < 1)
738 return OK; // nothing to do
739 ga_init2(&join_ga, sizeof(join_T), TUPLE_LEN(tuple));
740 retval = tuple_join_inner(gap, tuple, sep, echo_style, restore_copyID,
741 copyID, &join_ga);
742
743 if (join_ga.ga_data == NULL)
744 return retval;
745
746 // Dispose each item in join_ga.
747 p = (join_T *)join_ga.ga_data;
748 for (i = 0; i < join_ga.ga_len; ++i)
749 {
750 vim_free(p->tofree);
751 ++p;
752 }
753 ga_clear(&join_ga);
754
755 return retval;
756}
757
758/*
759 * Return an allocated string with the string representation of a tuple.
760 * May return NULL.
761 */
762 char_u *
763tuple2string(typval_T *tv, int copyID, int restore_copyID)
764{
765 garray_T ga;
766
767 if (tv->vval.v_tuple == NULL)
768 return NULL;
769 ga_init2(&ga, sizeof(char), 80);
770 ga_append(&ga, '(');
771 if (tuple_join(&ga, tv->vval.v_tuple, (char_u *)", ",
772 FALSE, restore_copyID, copyID) == FAIL)
773 {
774 vim_free(ga.ga_data);
775 return NULL;
776 }
777 ga_append(&ga, ')');
778 ga_append(&ga, NUL);
779 return (char_u *)ga.ga_data;
780}
781
782/*
783 * Implementation of foreach() for a Tuple. Apply "expr" to
784 * every item in Tuple "tuple" and return the result in "rettv".
785 */
786 void
787tuple_foreach(
788 tuple_T *tuple,
789 filtermap_T filtermap,
790 typval_T *expr)
791{
792 int len = tuple_len(tuple);
793 int rem;
794 typval_T newtv;
795 funccall_T *fc;
796
797 // set_vim_var_nr() doesn't set the type
798 set_vim_var_type(VV_KEY, VAR_NUMBER);
799
800 // Create one funccall_T for all eval_expr_typval() calls.
801 fc = eval_expr_get_funccal(expr, &newtv);
802
803 for (int idx = 0; idx < len; idx++)
804 {
805 set_vim_var_nr(VV_KEY, idx);
806 if (filter_map_one(TUPLE_ITEM(tuple, idx), expr, filtermap, fc,
807 &newtv, &rem) == FAIL)
808 break;
809 }
810
811 if (fc != NULL)
812 remove_funccal();
813}
814
815/*
816 * Count the number of times item "needle" occurs in Tuple "l" starting at index
817 * "idx". Case is ignored if "ic" is TRUE.
818 */
819 long
820tuple_count(tuple_T *tuple, typval_T *needle, long idx, int ic)
821{
822 long n = 0;
823
824 if (tuple == NULL)
825 return 0;
826
827 int len = TUPLE_LEN(tuple);
828 if (len == 0)
829 return 0;
830
831 if (idx < 0 || idx >= len)
832 {
833 semsg(_(e_tuple_index_out_of_range_nr), idx);
834 return 0;
835 }
836
837 for (int i = idx; i < len; i++)
838 {
839 if (tv_equal(TUPLE_ITEM(tuple, i), needle, ic))
840 ++n;
841 }
842
843 return n;
844}
845
846/*
847 * "items(tuple)" function
848 * Caller must have already checked that argvars[0] is a tuple.
849 */
850 void
851tuple2items(typval_T *argvars, typval_T *rettv)
852{
853 tuple_T *tuple = argvars[0].vval.v_tuple;
854 varnumber_T idx;
855
856 if (rettv_list_alloc(rettv) == FAIL)
857 return;
858
859 if (tuple == NULL)
860 return; // null tuple behaves like an empty list
861
862 for (idx = 0; idx < TUPLE_LEN(tuple); idx++)
863 {
864 list_T *l = list_alloc();
865
866 if (l == NULL)
867 break;
868
869 if (list_append_list(rettv->vval.v_list, l) == FAIL)
870 {
871 vim_free(l);
872 break;
873 }
874 if (list_append_number(l, idx) == FAIL
875 || list_append_tv(l, TUPLE_ITEM(tuple, idx)) == FAIL)
876 break;
877 }
878}
879
880/*
881 * Search for item "tv" in tuple "tuple" starting from index "start_idx".
882 * If "ic" is set to TRUE, then case is ignored.
883 *
884 * Returns the index where "tv" is present or -1 if it is not found.
885 */
886 int
887index_tuple(tuple_T *tuple, typval_T *tv, int start_idx, int ic)
888{
889 if (start_idx < 0)
890 {
891 start_idx = TUPLE_LEN(tuple) + start_idx;
892 if (start_idx < 0)
893 start_idx = 0;
894 }
895
896 for (int idx = start_idx; idx < TUPLE_LEN(tuple); idx++)
897 {
898 if (tv_equal(TUPLE_ITEM(tuple, idx), tv, ic))
899 return idx;
900 }
901
902 return -1; // "tv" not found
903}
904
905/*
906 * Evaluate 'expr' for each item in the Tuple 'tuple' starting with the item at
907 * 'startidx' and return the index of the item where 'expr' is TRUE. Returns
908 * -1 if 'expr' doesn't evaluate to TRUE for any of the items.
909 */
910 int
911indexof_tuple(tuple_T *tuple, long startidx, typval_T *expr)
912{
913 long idx = 0;
914 int len;
915 int found;
916
917 if (tuple == NULL)
918 return -1;
919
920 len = TUPLE_LEN(tuple);
921
922 if (startidx < 0)
923 {
924 // negative index: index from the end
925 startidx = len + startidx;
926 if (startidx < 0)
927 startidx = 0;
928 }
929
930 set_vim_var_type(VV_KEY, VAR_NUMBER);
931
932 int called_emsg_start = called_emsg;
933
934 for (idx = startidx; idx < len; idx++)
935 {
936 set_vim_var_nr(VV_KEY, idx);
937 copy_tv(TUPLE_ITEM(tuple, idx), get_vim_var_tv(VV_VAL));
938
939 found = indexof_eval_expr(expr);
940 clear_tv(get_vim_var_tv(VV_VAL));
941
942 if (found)
943 return idx;
944
945 if (called_emsg != called_emsg_start)
946 return -1;
947 }
948
949 return -1;
950}
951
952/*
953 * Return the max or min of the items in tuple "tuple".
954 * If a tuple item is not a number, then "error" is set to TRUE.
955 */
956 varnumber_T
957tuple_max_min(tuple_T *tuple, int domax, int *error)
958{
959 varnumber_T n = 0;
960 varnumber_T v;
961
962 if (tuple == NULL || TUPLE_LEN(tuple) == 0)
963 return 0;
964
965 n = tv_get_number_chk(TUPLE_ITEM(tuple, 0), error);
966 if (*error)
967 return n; // type error; errmsg already given
968
969 for (int idx = 1; idx < TUPLE_LEN(tuple); idx++)
970 {
971 v = tv_get_number_chk(TUPLE_ITEM(tuple, idx), error);
972 if (*error)
973 return n; // type error; errmsg already given
974 if (domax ? v > n : v < n)
975 n = v;
976 }
977
978 return n;
979}
980
981/*
982 * Repeat the tuple "tuple" "n" times and set "rettv" to the new tuple.
983 */
984 void
985tuple_repeat(tuple_T *tuple, int n, typval_T *rettv)
986{
987 rettv->v_type = VAR_TUPLE;
988 rettv->vval.v_tuple = NULL;
989
990 if (tuple == NULL || TUPLE_LEN(tuple) == 0 || n <= 0)
991 return;
992
993 if (rettv_tuple_set_with_items(rettv, TUPLE_LEN(tuple) * n) == FAIL)
994 return;
995
996 tuple_T *new_tuple = rettv->vval.v_tuple;
997 for (int count = 0; count < n; count++)
998 {
999 for (int idx = 0; idx < TUPLE_LEN(tuple); idx++)
1000 {
1001 copy_tv(TUPLE_ITEM(tuple, idx),
1002 TUPLE_ITEM(new_tuple, TUPLE_LEN(new_tuple)));
1003 new_tuple->tv_items.ga_len++;
1004 }
1005 }
1006}
1007
1008/*
1009 * Reverse "tuple" and return the new tuple in "rettv"
1010 */
1011 void
1012tuple_reverse(tuple_T *tuple, typval_T *rettv)
1013{
1014 rettv->v_type = VAR_TUPLE;
1015 rettv->vval.v_tuple = NULL;
1016
1017 int len = tuple_len(tuple);
1018
1019 if (len == 0)
1020 return;
1021
1022 if (rettv_tuple_set_with_items(rettv, len) == FAIL)
1023 return;
1024
1025 tuple_T *new_tuple = rettv->vval.v_tuple;
1026 for (int i = 0; i < len; i++)
1027 copy_tv(TUPLE_ITEM(tuple, i), TUPLE_ITEM(new_tuple, len - i - 1));
1028 new_tuple->tv_items.ga_len = tuple->tv_items.ga_len;
1029}
1030
1031/*
1032 * Tuple reduce() function
1033 */
1034 void
1035tuple_reduce(typval_T *argvars, typval_T *expr, typval_T *rettv)
1036{
1037 tuple_T *tuple = argvars[0].vval.v_tuple;
1038 int called_emsg_start = called_emsg;
1039 typval_T initial;
1040 int idx = 0;
1041 funccall_T *fc;
1042 typval_T argv[3];
1043 int r;
1044
1045 if (argvars[2].v_type == VAR_UNKNOWN)
1046 {
1047 if (tuple == NULL || TUPLE_LEN(tuple) == 0)
1048 {
1049 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Tuple");
1050 return;
1051 }
1052 initial = *TUPLE_ITEM(tuple, 0);
1053 idx = 1;
1054 }
1055 else
1056 {
1057 initial = argvars[2];
1058 idx = 0;
1059 }
1060
1061 copy_tv(&initial, rettv);
1062
1063 if (tuple == NULL)
1064 return;
1065
1066 // Create one funccall_T for all eval_expr_typval() calls.
1067 fc = eval_expr_get_funccal(expr, rettv);
1068
1069 for ( ; idx < TUPLE_LEN(tuple); idx++)
1070 {
1071 argv[0] = *rettv;
1072 rettv->v_type = VAR_UNKNOWN;
1073 argv[1] = *TUPLE_ITEM(tuple, idx);
1074
1075 r = eval_expr_typval(expr, TRUE, argv, 2, fc, rettv);
1076
1077 clear_tv(&argv[0]);
1078
1079 if (r == FAIL || called_emsg != called_emsg_start)
1080 break;
1081 }
1082
1083 if (fc != NULL)
1084 remove_funccal();
1085}
1086
1087/*
1088 * Returns TRUE if two tuples with types "type1" and "type2" are addable.
1089 * Otherwise returns FALSE.
1090 */
1091 int
1092check_tuples_addable(type_T *type1, type_T *type2)
1093{
1094 int addable = TRUE;
1095
1096 // If the first operand is a variadic tuple and the second argument is
1097 // non-variadic, then concatenation is not possible.
1098 if ((type1->tt_flags & TTFLAG_VARARGS)
1099 && !(type2->tt_flags & TTFLAG_VARARGS)
1100 && (type2->tt_argcount > 0))
1101 addable = FALSE;
1102
1103 if ((type1->tt_flags & TTFLAG_VARARGS)
1104 && (type2->tt_flags & TTFLAG_VARARGS))
1105 {
1106 // two variadic tuples
1107 if (type1->tt_argcount > 1 || type2->tt_argcount > 1)
1108 // one of the variadic tuple has fixed number of items
1109 addable = FALSE;
1110 else if ((type1->tt_argcount == 1 && type2->tt_argcount == 1)
1111 && !equal_type(type1->tt_args[0], type2->tt_args[0], 0))
1112 // the tuples have different item types
1113 addable = FALSE;
1114 }
1115
1116 if (!addable)
1117 {
1118 emsg(_(e_cannot_use_variadic_tuple_in_concatenation));
1119 return FAIL;
1120 }
1121
1122 return OK;
1123}
1124
1125#endif // defined(FEAT_EVAL)