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/gc.c b/src/gc.c
index 54c7444..b95b2ca 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -122,31 +122,31 @@
// buffer-local variables
FOR_ALL_BUFFERS(buf)
abort = abort || set_ref_in_item(&buf->b_bufvar.di_tv, copyID,
- NULL, NULL);
+ NULL, NULL, NULL);
// window-local variables
FOR_ALL_TAB_WINDOWS(tp, wp)
abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
- NULL, NULL);
+ NULL, NULL, NULL);
// window-local variables in autocmd windows
for (int i = 0; i < AUCMD_WIN_COUNT; ++i)
if (aucmd_win[i].auc_win != NULL)
abort = abort || set_ref_in_item(
- &aucmd_win[i].auc_win->w_winvar.di_tv, copyID, NULL, NULL);
+ &aucmd_win[i].auc_win->w_winvar.di_tv, copyID, NULL, NULL, NULL);
#ifdef FEAT_PROP_POPUP
FOR_ALL_POPUPWINS(wp)
abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
- NULL, NULL);
+ NULL, NULL, NULL);
FOR_ALL_TABPAGES(tp)
FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
abort = abort || set_ref_in_item(&wp->w_winvar.di_tv, copyID,
- NULL, NULL);
+ NULL, NULL, NULL);
#endif
// tabpage-local variables
FOR_ALL_TABPAGES(tp)
abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
- NULL, NULL);
+ NULL, NULL, NULL);
// global variables
abort = abort || garbage_collect_globvars(copyID);
@@ -269,6 +269,9 @@
// Go through the list of lists and free items without this copyID.
did_free |= list_free_nonref(copyID);
+ // Go through the list of tuples and free items without this copyID.
+ did_free |= tuple_free_nonref(copyID);
+
// Go through the list of objects and free items without this copyID.
did_free |= object_free_nonref(copyID);
@@ -291,6 +294,7 @@
object_free_items(copyID);
dict_free_items(copyID);
list_free_items(copyID);
+ tuple_free_items(copyID);
#ifdef FEAT_JOB_CHANNEL
// Go through the list of jobs and free items without the copyID. This
@@ -314,7 +318,11 @@
* Returns TRUE if setting references failed somehow.
*/
int
-set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
+set_ref_in_ht(
+ hashtab_T *ht,
+ int copyID,
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
int todo;
int abort = FALSE;
@@ -336,8 +344,9 @@
if (!HASHITEM_EMPTY(hi))
{
--todo;
- abort = abort || set_ref_in_item(&HI2DI(hi)->di_tv, copyID,
- &ht_stack, list_stack);
+ abort = abort
+ || set_ref_in_item(&HI2DI(hi)->di_tv, copyID,
+ &ht_stack, list_stack, tuple_stack);
}
}
@@ -366,7 +375,7 @@
if (d != NULL && d->dv_copyID != copyID)
{
d->dv_copyID = copyID;
- return set_ref_in_ht(&d->dv_hashtab, copyID, NULL);
+ return set_ref_in_ht(&d->dv_hashtab, copyID, NULL, NULL);
}
return FALSE;
}
@@ -382,7 +391,7 @@
if (ll != NULL && ll->lv_copyID != copyID)
{
ll->lv_copyID = copyID;
- return set_ref_in_list_items(ll, copyID, NULL);
+ return set_ref_in_list_items(ll, copyID, NULL, NULL);
}
return FALSE;
}
@@ -394,7 +403,11 @@
* Returns TRUE if setting references failed somehow.
*/
int
-set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack)
+set_ref_in_list_items(
+ list_T *l,
+ int copyID,
+ ht_stack_T **ht_stack,
+ tuple_stack_T **tuple_stack)
{
listitem_T *li;
int abort = FALSE;
@@ -411,7 +424,7 @@
// list_stack.
for (li = cur_l->lv_first; !abort && li != NULL; li = li->li_next)
abort = abort || set_ref_in_item(&li->li_tv, copyID,
- ht_stack, &list_stack);
+ ht_stack, &list_stack, tuple_stack);
if (list_stack == NULL)
break;
@@ -426,6 +439,50 @@
}
/*
+ * Mark all lists and dicts referenced through tuple "t" with "copyID".
+ * "ht_stack" is used to add hashtabs to be marked. Can be NULL.
+ *
+ * Returns TRUE if setting references failed somehow.
+ */
+ int
+set_ref_in_tuple_items(
+ tuple_T *tuple,
+ int copyID,
+ ht_stack_T **ht_stack,
+ list_stack_T **list_stack)
+{
+ int abort = FALSE;
+ tuple_T *cur_t;
+ tuple_stack_T *tuple_stack = NULL;
+ tuple_stack_T *tempitem;
+
+ cur_t = tuple;
+ for (;;)
+ {
+ // Mark each item in the tuple. If the item contains a hashtab
+ // it is added to ht_stack, if it contains a list it is added to
+ // list_stack.
+ for (int i = 0; i < cur_t->tv_items.ga_len; i++)
+ {
+ typval_T *tv = ((typval_T *)cur_t->tv_items.ga_data) + i;
+ abort = abort
+ || set_ref_in_item(tv, copyID,
+ ht_stack, list_stack, &tuple_stack);
+ }
+ if (tuple_stack == NULL)
+ break;
+
+ // take an item from the stack
+ cur_t = tuple_stack->tuple;
+ tempitem = tuple_stack;
+ tuple_stack = tuple_stack->prev;
+ free(tempitem);
+ }
+
+ return abort;
+}
+
+/*
* Mark the partial in callback 'cb' with "copyID".
*/
int
@@ -438,7 +495,7 @@
tv.v_type = VAR_PARTIAL;
tv.vval.v_partial = cb->cb_partial;
- return set_ref_in_item(&tv, copyID, NULL, NULL);
+ return set_ref_in_item(&tv, copyID, NULL, NULL, NULL);
}
/*
@@ -450,7 +507,8 @@
dict_T *dd,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
if (dd == NULL || dd->dv_copyID == copyID)
return FALSE;
@@ -458,7 +516,7 @@
// Didn't see this dict yet.
dd->dv_copyID = copyID;
if (ht_stack == NULL)
- return set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
+ return set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack, tuple_stack);
ht_stack_T *newitem = ALLOC_ONE(ht_stack_T);
if (newitem == NULL)
@@ -480,7 +538,8 @@
list_T *ll,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
if (ll == NULL || ll->lv_copyID == copyID)
return FALSE;
@@ -488,7 +547,7 @@
// Didn't see this list yet.
ll->lv_copyID = copyID;
if (list_stack == NULL)
- return set_ref_in_list_items(ll, copyID, ht_stack);
+ return set_ref_in_list_items(ll, copyID, ht_stack, tuple_stack);
list_stack_T *newitem = ALLOC_ONE(list_stack_T);
if (newitem == NULL)
@@ -502,6 +561,37 @@
}
/*
+ * Mark the tuple "tt" with "copyID".
+ * Also see set_ref_in_item().
+ */
+ static int
+set_ref_in_item_tuple(
+ tuple_T *tt,
+ int copyID,
+ ht_stack_T **ht_stack,
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
+{
+ if (tt == NULL || tt->tv_copyID == copyID)
+ return FALSE;
+
+ // Didn't see this tuple yet.
+ tt->tv_copyID = copyID;
+ if (tuple_stack == NULL)
+ return set_ref_in_tuple_items(tt, copyID, ht_stack, list_stack);
+
+ tuple_stack_T *newitem = ALLOC_ONE(tuple_stack_T);
+ if (newitem == NULL)
+ return TRUE;
+
+ newitem->tuple = tt;
+ newitem->prev = *tuple_stack;
+ *tuple_stack = newitem;
+
+ return FALSE;
+}
+
+/*
* Mark the partial "pt" with "copyID".
* Also see set_ref_in_item().
*/
@@ -510,7 +600,8 @@
partial_T *pt,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
if (pt == NULL || pt->pt_copyID == copyID)
return FALSE;
@@ -526,7 +617,7 @@
dtv.v_type = VAR_DICT;
dtv.vval.v_dict = pt->pt_dict;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
if (pt->pt_obj != NULL)
@@ -535,12 +626,12 @@
objtv.v_type = VAR_OBJECT;
objtv.vval.v_object = pt->pt_obj;
- set_ref_in_item(&objtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&objtv, copyID, ht_stack, list_stack, tuple_stack);
}
for (int i = 0; i < pt->pt_argc; ++i)
abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
// pt_funcstack is handled in set_ref_in_funcstacks()
// pt_loopvars is handled in set_ref_in_loopvars()
@@ -557,7 +648,8 @@
job_T *job,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
typval_T dtv;
@@ -569,13 +661,13 @@
{
dtv.v_type = VAR_CHANNEL;
dtv.vval.v_channel = job->jv_channel;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
if (job->jv_exit_cb.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
dtv.vval.v_partial = job->jv_exit_cb.cb_partial;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
return FALSE;
@@ -590,7 +682,8 @@
channel_T *ch,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
typval_T dtv;
@@ -602,33 +695,33 @@
{
for (jsonq_T *jq = ch->ch_part[part].ch_json_head.jq_next;
jq != NULL; jq = jq->jq_next)
- set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack);
+ set_ref_in_item(jq->jq_value, copyID, ht_stack, list_stack, tuple_stack);
for (cbq_T *cq = ch->ch_part[part].ch_cb_head.cq_next; cq != NULL;
cq = cq->cq_next)
if (cq->cq_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
dtv.vval.v_partial = cq->cq_callback.cb_partial;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
if (ch->ch_part[part].ch_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
dtv.vval.v_partial = ch->ch_part[part].ch_callback.cb_partial;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
}
if (ch->ch_callback.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
dtv.vval.v_partial = ch->ch_callback.cb_partial;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
if (ch->ch_close_cb.cb_partial != NULL)
{
dtv.v_type = VAR_PARTIAL;
dtv.vval.v_partial = ch->ch_close_cb.cb_partial;
- set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ set_ref_in_item(&dtv, copyID, ht_stack, list_stack, tuple_stack);
}
return FALSE;
@@ -644,7 +737,8 @@
class_T *cl,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
int abort = FALSE;
@@ -659,7 +753,7 @@
for (int i = 0; !abort && i < cl->class_class_member_count; ++i)
abort = abort || set_ref_in_item(
&cl->class_members_tv[i],
- copyID, ht_stack, list_stack);
+ copyID, ht_stack, list_stack, tuple_stack);
}
for (int i = 0; !abort && i < cl->class_class_function_count; ++i)
@@ -682,7 +776,8 @@
object_T *obj,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
int abort = FALSE;
@@ -696,7 +791,7 @@
for (int i = 0; !abort
&& i < obj->obj_class->class_obj_member_count; ++i)
abort = abort || set_ref_in_item(mtv + i, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
return abort;
}
@@ -714,7 +809,8 @@
typval_T *tv,
int copyID,
ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+ list_stack_T **list_stack,
+ tuple_stack_T **tuple_stack)
{
int abort = FALSE;
@@ -722,12 +818,15 @@
{
case VAR_DICT:
return set_ref_in_item_dict(tv->vval.v_dict, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
case VAR_LIST:
return set_ref_in_item_list(tv->vval.v_list, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
+ case VAR_TUPLE:
+ return set_ref_in_item_tuple(tv->vval.v_tuple, copyID,
+ ht_stack, list_stack, tuple_stack);
case VAR_FUNC:
{
abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
@@ -736,12 +835,12 @@
case VAR_PARTIAL:
return set_ref_in_item_partial(tv->vval.v_partial, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
case VAR_JOB:
#ifdef FEAT_JOB_CHANNEL
return set_ref_in_item_job(tv->vval.v_job, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
#else
break;
#endif
@@ -749,18 +848,18 @@
case VAR_CHANNEL:
#ifdef FEAT_JOB_CHANNEL
return set_ref_in_item_channel(tv->vval.v_channel, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
#else
break;
#endif
case VAR_CLASS:
return set_ref_in_item_class(tv->vval.v_class, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
case VAR_OBJECT:
return set_ref_in_item_object(tv->vval.v_object, copyID,
- ht_stack, list_stack);
+ ht_stack, list_stack, tuple_stack);
case VAR_UNKNOWN:
case VAR_ANY: