summaryrefslogtreecommitdiff
path: root/src/vim9execute.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-15 17:19:37 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-15 17:19:37 +0100
commitb46c083a5ed9e0c4ac5f3aec577946dcbe8c9dc5 (patch)
treef91c0168ac87183c5df558840b9cf920d18df558 /src/vim9execute.c
parent3735f11050616652525bf80b4fbcb2b3bfeab113 (diff)
downloadvim-git-b46c083a5ed9e0c4ac5f3aec577946dcbe8c9dc5.tar.gz
patch 9.0.0470: in :def function all closures in loop get the same variablesv9.0.0470
Problem: In a :def function all closures in a loop get the same variables. Solution: When in a loop and a closure refers to a variable declared in the loop, prepare for making a copy of variables for each closure.
Diffstat (limited to 'src/vim9execute.c')
-rw-r--r--src/vim9execute.c112
1 files changed, 96 insertions, 16 deletions
diff --git a/src/vim9execute.c b/src/vim9execute.c
index cbf9af7ad..a1c2f8b27 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -504,7 +504,8 @@ call_dfunc(
// - if needed: a counter for number of closures created in
// ectx->ec_funcrefs.
varcount = dfunc->df_varcount + dfunc->df_has_closure;
- if (GA_GROW_FAILS(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE + varcount))
+ if (GA_GROW_FAILS(&ectx->ec_stack,
+ arg_to_add + STACK_FRAME_SIZE + varcount))
return FAIL;
// If depth of calling is getting too high, don't execute the function.
@@ -553,6 +554,8 @@ call_dfunc(
{
typval_T *tv = STACK_TV_BOT(STACK_FRAME_SIZE + dfunc->df_varcount);
+ // Initialize the variable that counts how many closures were created.
+ // This is used in handle_closure_in_use().
tv->v_type = VAR_NUMBER;
tv->vval.v_number = 0;
}
@@ -1821,8 +1824,8 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ectx->ec_dfunc_idx;
- // The closure may need to find arguments and local variables in the
- // current stack.
+ // The closure may need to find arguments and local variables of the
+ // current function in the stack.
pt->pt_outer.out_stack = &ectx->ec_stack;
pt->pt_outer.out_frame_idx = ectx->ec_frame_idx;
if (ectx->ec_outer_ref != NULL)
@@ -1836,8 +1839,9 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
}
}
- // If this function returns and the closure is still being used, we
- // need to make a copy of the context (arguments and local variables).
+ // If the function currently executing returns and the closure is still
+ // being referenced, we need to make a copy of the context (arguments
+ // and local variables) so that the closure can use it later.
// Store a reference to the partial so we can handle that.
if (GA_GROW_FAILS(&ectx->ec_funcrefs, 1))
{
@@ -2477,6 +2481,7 @@ execute_unletrange(isn_T *iptr, ectx_T *ectx)
execute_for(isn_T *iptr, ectx_T *ectx)
{
typval_T *tv;
+ int jump = FALSE;
typval_T *ltv = STACK_TV_BOT(-1);
typval_T *idxtv =
STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
@@ -2492,9 +2497,7 @@ execute_for(isn_T *iptr, ectx_T *ectx)
if (list == NULL
|| idxtv->vval.v_number >= list->lv_len)
{
- // past the end of the list, jump to "endfor"
- ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&ectx->ec_funclocal);
+ jump = TRUE;
}
else if (list->lv_first == &range_list_item)
{
@@ -2524,9 +2527,7 @@ execute_for(isn_T *iptr, ectx_T *ectx)
++idxtv->vval.v_number;
if (str == NULL || str[idxtv->vval.v_number] == NUL)
{
- // past the end of the string, jump to "endfor"
- ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&ectx->ec_funclocal);
+ jump = TRUE;
}
else
{
@@ -2557,12 +2558,9 @@ execute_for(isn_T *iptr, ectx_T *ectx)
// The index is for the previous byte.
++idxtv->vval.v_number;
- if (blob == NULL
- || idxtv->vval.v_number >= blob_len(blob))
+ if (blob == NULL || idxtv->vval.v_number >= blob_len(blob))
{
- // past the end of the blob, jump to "endfor"
- ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
- may_restore_cmdmod(&ectx->ec_funclocal);
+ jump = TRUE;
}
else
{
@@ -2580,6 +2578,33 @@ execute_for(isn_T *iptr, ectx_T *ectx)
vartype_name(ltv->v_type));
return FAIL;
}
+
+ if (jump)
+ {
+ // past the end of the list/string/blob, jump to "endfor"
+ ectx->ec_iidx = iptr->isn_arg.forloop.for_end;
+ may_restore_cmdmod(&ectx->ec_funclocal);
+ }
+ else
+ {
+ // Store the current number of funcrefs, this may be used in
+ // ISN_LOOPEND. The variable index is always one more than the loop
+ // variable index.
+ tv = STACK_TV_VAR(iptr->isn_arg.forloop.for_idx + 1);
+ tv->vval.v_number = ectx->ec_funcrefs.ga_len;
+ }
+
+ return OK;
+}
+
+/*
+ * End of a for or while loop: Handle any variables used by a closure.
+ */
+ static int
+execute_endloop(isn_T *iptr UNUSED, ectx_T *ectx UNUSED)
+{
+ // TODO
+
return OK;
}
@@ -3989,6 +4014,31 @@ exec_instructions(ectx_T *ectx)
}
break;
+ // "while": jump to end if a condition is false
+ case ISN_WHILE:
+ {
+ int error = FALSE;
+ int jump = TRUE;
+
+ tv = STACK_TV_BOT(-1);
+ SOURCING_LNUM = iptr->isn_lnum;
+ jump = !tv_get_bool_chk(tv, &error);
+ if (error)
+ goto on_error;
+ // drop the value from the stack
+ clear_tv(tv);
+ --ectx->ec_stack.ga_len;
+ if (jump)
+ ectx->ec_iidx = iptr->isn_arg.whileloop.while_end;
+
+ // Store the current funccal count, may be used by
+ // ISN_LOOPEND later
+ tv = STACK_TV_VAR(
+ iptr->isn_arg.whileloop.while_funcref_idx);
+ tv->vval.v_number = ectx->ec_funcrefs.ga_len;
+ }
+ break;
+
// Jump if an argument with a default value was already set and not
// v:none.
case ISN_JUMP_IF_ARG_SET:
@@ -4005,6 +4055,12 @@ exec_instructions(ectx_T *ectx)
goto theend;
break;
+ // end of a for or while loop
+ case ISN_ENDLOOP:
+ if (execute_endloop(iptr, ectx) == FAIL)
+ goto theend;
+ break;
+
// start of ":try" block
case ISN_TRY:
{
@@ -6185,6 +6241,9 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case JUMP_IF_FALSE:
when = "JUMP_IF_FALSE";
break;
+ case JUMP_WHILE_FALSE:
+ when = "JUMP_WHILE_FALSE"; // unused
+ break;
case JUMP_IF_COND_FALSE:
when = "JUMP_IF_COND_FALSE";
break;
@@ -6212,6 +6271,27 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
}
break;
+ case ISN_ENDLOOP:
+ {
+ endloop_T *endloop = &iptr->isn_arg.endloop;
+
+ smsg("%s%4d ENDLOOP $%d save $%d - $%d", pfx, current,
+ endloop->end_funcref_idx,
+ endloop->end_var_idx,
+ endloop->end_var_idx + endloop->end_var_count - 1);
+ }
+ break;
+
+ case ISN_WHILE:
+ {
+ whileloop_T *whileloop = &iptr->isn_arg.whileloop;
+
+ smsg("%s%4d WHILE $%d -> %d", pfx, current,
+ whileloop->while_funcref_idx,
+ whileloop->while_end);
+ }
+ break;
+
case ISN_TRY:
{
try_T *try = &iptr->isn_arg.tryref;