patch 9.1.1232: Vim script is missing the tuple data type
Problem: Vim script is missing the tuple data type
Solution: Add support for the tuple data type
(Yegappan Lakshmanan)
closes: #16776
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/evalvars.c b/src/evalvars.c
index 2745ac2..9382842 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -162,6 +162,7 @@
{VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("stacktrace", VAR_LIST), &t_list_dict_any, VV_RO},
+ {VV_NAME("t_tuple", VAR_NUMBER), NULL, VV_RO},
};
// shorthand
@@ -265,8 +266,9 @@
set_vim_var_nr(VV_TYPE_CLASS, VAR_TYPE_CLASS);
set_vim_var_nr(VV_TYPE_OBJECT, VAR_TYPE_OBJECT);
set_vim_var_nr(VV_TYPE_TYPEALIAS, VAR_TYPE_TYPEALIAS);
- set_vim_var_nr(VV_TYPE_ENUM, VAR_TYPE_ENUM);
+ set_vim_var_nr(VV_TYPE_ENUM, VAR_TYPE_ENUM);
set_vim_var_nr(VV_TYPE_ENUMVALUE, VAR_TYPE_ENUMVALUE);
+ set_vim_var_nr(VV_TYPE_TUPLE, VAR_TYPE_TUPLE);
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
@@ -321,13 +323,13 @@
int
garbage_collect_globvars(int copyID)
{
- return set_ref_in_ht(&globvarht, copyID, NULL);
+ return set_ref_in_ht(&globvarht, copyID, NULL, NULL);
}
int
garbage_collect_vimvars(int copyID)
{
- return set_ref_in_ht(&vimvarht, copyID, NULL);
+ return set_ref_in_ht(&vimvarht, copyID, NULL, NULL);
}
int
@@ -340,7 +342,7 @@
for (i = 1; i <= script_items.ga_len; ++i)
{
- abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
+ abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL, NULL);
si = SCRIPT_ITEM(i);
for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
@@ -348,7 +350,7 @@
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
if (sv->sv_name != NULL)
- abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL);
+ abort = abort || set_ref_in_item(sv->sv_tv, copyID, NULL, NULL, NULL);
}
}
@@ -1234,10 +1236,13 @@
{
char_u *arg = arg_start;
list_T *l;
+ tuple_T *tuple = NULL;
int i;
int var_idx = 0;
- listitem_T *item;
+ listitem_T *item = NULL;
typval_T ltv;
+ int is_list = tv->v_type == VAR_LIST;
+ int idx;
if (tv->v_type == VAR_VOID)
{
@@ -1253,58 +1258,121 @@
}
// ":let [v1, v2] = list" or ":for [v1, v2] in listlist"
- if (tv->v_type != VAR_LIST || (l = tv->vval.v_list) == NULL)
+ // or
+ // ":let [v1, v2] = tuple" or ":for [v1, v2] in tupletuple"
+ if (tv->v_type != VAR_LIST && tv->v_type != VAR_TUPLE)
{
- emsg(_(e_list_required));
+ emsg(_(e_list_or_tuple_required));
return FAIL;
}
+ if (is_list)
+ {
+ l = tv->vval.v_list;
+ if (l == NULL)
+ {
+ emsg(_(e_list_required));
+ return FAIL;
+ }
+ i = list_len(l);
+ }
+ else
+ {
+ tuple = tv->vval.v_tuple;
+ if (tuple == NULL)
+ {
+ emsg(_(e_tuple_required));
+ return FAIL;
+ }
+ i = tuple_len(tuple);
+ }
- i = list_len(l);
if (semicolon == 0 && var_count < i)
{
- emsg(_(e_less_targets_than_list_items));
+ emsg(_(is_list ? e_less_targets_than_list_items
+ : e_less_targets_than_tuple_items));
return FAIL;
}
if (var_count - semicolon > i)
{
- emsg(_(e_more_targets_than_list_items));
+ emsg(_(is_list ? e_more_targets_than_list_items
+ : e_more_targets_than_tuple_items));
return FAIL;
}
- CHECK_LIST_MATERIALIZE(l);
- item = l->lv_first;
+ if (is_list)
+ {
+ CHECK_LIST_MATERIALIZE(l);
+ item = l->lv_first;
+ }
+ else
+ idx = 0;
+
while (*arg != ']')
{
arg = skipwhite(arg + 1);
++var_idx;
- arg = ex_let_one(arg, &item->li_tv, TRUE,
- flags | ASSIGN_UNPACK, (char_u *)",;]", op, var_idx);
- item = item->li_next;
+ arg = ex_let_one(arg, is_list ? &item->li_tv : TUPLE_ITEM(tuple, idx),
+ TRUE, flags | ASSIGN_UNPACK, (char_u *)",;]", op,
+ var_idx);
+ if (is_list)
+ item = item->li_next;
+ else
+ idx++;
if (arg == NULL)
return FAIL;
arg = skipwhite(arg);
if (*arg == ';')
{
- // Put the rest of the list (may be empty) in the var after ';'.
- // Create a new list for this.
- l = list_alloc();
- if (l == NULL)
- return FAIL;
- while (item != NULL)
+ // Put the rest of the list or tuple (may be empty) in the var
+ // after ';'. Create a new list or tuple for this.
+ if (is_list)
{
- list_append_tv(l, &item->li_tv);
- item = item->li_next;
+ // Put the rest of the list (may be empty) in the var
+ // after ';'. Create a new list for this.
+ l = list_alloc();
+ if (l == NULL)
+ return FAIL;
+
+ // list
+ while (item != NULL)
+ {
+ list_append_tv(l, &item->li_tv);
+ item = item->li_next;
+ }
+
+ ltv.v_type = VAR_LIST;
+ ltv.v_lock = 0;
+ ltv.vval.v_list = l;
+ l->lv_refcount = 1;
+ }
+ else
+ {
+ tuple_T *new_tuple = tuple_alloc();
+ if (new_tuple == NULL)
+ return FAIL;
+
+ // Put the rest of the tuple (may be empty) in the var
+ // after ';'. Create a new tuple for this.
+ while (idx < TUPLE_LEN(tuple))
+ {
+ typval_T new_tv;
+
+ copy_tv(TUPLE_ITEM(tuple, idx), &new_tv);
+ if (tuple_append_tv(new_tuple, &new_tv) == FAIL)
+ return FAIL;
+ idx++;
+ }
+
+ ltv.v_type = VAR_TUPLE;
+ ltv.v_lock = 0;
+ ltv.vval.v_tuple = new_tuple;
+ new_tuple->tv_refcount = 1;
}
- ltv.v_type = VAR_LIST;
- ltv.v_lock = 0;
- ltv.vval.v_list = l;
- l->lv_refcount = 1;
++var_idx;
-
arg = ex_let_one(skipwhite(arg + 1), <v, FALSE,
- flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
+ flags | ASSIGN_UNPACK, (char_u *)"]", op, var_idx);
clear_tv(<v);
if (arg == NULL)
return FAIL;
@@ -2418,6 +2486,9 @@
}
}
break;
+ case VAR_TUPLE:
+ tuple_lock(tv->vval.v_tuple, deep, lock, check_refcount);
+ break;
case VAR_DICT:
if ((d = tv->vval.v_dict) != NULL
&& !(check_refcount && d->dv_refcount > 1))
@@ -3189,9 +3260,9 @@
}
}
- // If a list or dict variable wasn't initialized and has meaningful
- // type, do it now. Not for global variables, they are not
- // declared.
+ // If a list or tuple or dict variable wasn't initialized and has
+ // meaningful type, do it now. Not for global variables, they are
+ // not declared.
if (ht != &globvarht)
{
if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL
@@ -3220,6 +3291,19 @@
sv->sv_flags |= SVFLAG_ASSIGNED;
}
}
+ else if (tv->v_type == VAR_TUPLE && tv->vval.v_tuple == NULL
+ && ((type != NULL && !was_assigned)
+ || !in_vim9script()))
+ {
+ tv->vval.v_tuple = tuple_alloc();
+ if (tv->vval.v_tuple != NULL)
+ {
+ ++tv->vval.v_tuple->tv_refcount;
+ tv->vval.v_tuple->tv_type = alloc_type(type);
+ if (sv != NULL)
+ sv->sv_flags |= SVFLAG_ASSIGNED;
+ }
+ }
else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL
&& ((type != NULL && !was_assigned)
|| !in_vim9script()))