comparison src/vim9execute.c @ 23559:64dfb69e7d46 v8.2.2322

patch 8.2.2322: Vim9: closure nested limiting to one level Commit: https://github.com/vim/vim/commit/0186e58639b19933d3d9188d552fe6745265eb1b Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 10 18:33:11 2021 +0100 patch 8.2.2322: Vim9: closure nested limiting to one level Problem: Vim9: closure nested limiting to one level. Solution: Add outer_T. Also make STOREOUTER work.
author Bram Moolenaar <Bram@vim.org>
date Sun, 10 Jan 2021 18:45:04 +0100
parents f50ee1ae4d9b
children 754387a3aa35
comparison
equal deleted inserted replaced
23558:b9004f7d5aec 23559:64dfb69e7d46
56 */ 56 */
57 struct ectx_S { 57 struct ectx_S {
58 garray_T ec_stack; // stack of typval_T values 58 garray_T ec_stack; // stack of typval_T values
59 int ec_frame_idx; // index in ec_stack: context of ec_dfunc_idx 59 int ec_frame_idx; // index in ec_stack: context of ec_dfunc_idx
60 60
61 garray_T *ec_outer_stack; // stack used for closures 61 outer_T *ec_outer; // outer scope used for closures, allocated
62 int ec_outer_frame; // stack frame in ec_outer_stack
63 garray_T *ec_outer_up_stack; // ec_outer_stack one level up
64 int ec_outer_up_frame; // ec_outer_frame one level up
65 62
66 garray_T ec_trystack; // stack of trycmd_T values 63 garray_T ec_trystack; // stack of trycmd_T values
67 int ec_in_catch; // when TRUE in catch or finally block 64 int ec_in_catch; // when TRUE in catch or finally block
68 65
69 int ec_dfunc_idx; // current function index 66 int ec_dfunc_idx; // current function index
151 148
152 /* 149 /*
153 * Call compiled function "cdf_idx" from compiled code. 150 * Call compiled function "cdf_idx" from compiled code.
154 * This adds a stack frame and sets the instruction pointer to the start of the 151 * This adds a stack frame and sets the instruction pointer to the start of the
155 * called function. 152 * called function.
153 * If "pt" is not null use "pt->pt_outer" for ec_outer.
156 * 154 *
157 * Stack has: 155 * Stack has:
158 * - current arguments (already there) 156 * - current arguments (already there)
159 * - omitted optional argument (default values) added here 157 * - omitted optional argument (default values) added here
160 * - stack frame: 158 * - stack frame:
162 * - Index of next instruction in calling function 160 * - Index of next instruction in calling function
163 * - previous frame pointer 161 * - previous frame pointer
164 * - reserved space for local variables 162 * - reserved space for local variables
165 */ 163 */
166 static int 164 static int
167 call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) 165 call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx)
168 { 166 {
169 int argcount = argcount_arg; 167 int argcount = argcount_arg;
170 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx; 168 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
171 ufunc_T *ufunc = dfunc->df_ufunc; 169 ufunc_T *ufunc = dfunc->df_ufunc;
172 int arg_to_add; 170 int arg_to_add;
245 for (idx = 0; idx < arg_to_add; ++idx) 243 for (idx = 0; idx < arg_to_add; ++idx)
246 STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN; 244 STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN;
247 ectx->ec_stack.ga_len += arg_to_add; 245 ectx->ec_stack.ga_len += arg_to_add;
248 246
249 // Store current execution state in stack frame for ISN_RETURN. 247 // Store current execution state in stack frame for ISN_RETURN.
250 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; 248 STACK_TV_BOT(STACK_FRAME_FUNC_OFF)->vval.v_number = ectx->ec_dfunc_idx;
251 STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; 249 STACK_TV_BOT(STACK_FRAME_IIDX_OFF)->vval.v_number = ectx->ec_iidx;
252 STACK_TV_BOT(2)->vval.v_string = (void *)ectx->ec_outer_stack; 250 if (ectx->ec_outer != NULL)
253 STACK_TV_BOT(3)->vval.v_number = ectx->ec_outer_frame; 251 printf("here");
254 STACK_TV_BOT(4)->vval.v_number = ectx->ec_frame_idx; 252 STACK_TV_BOT(STACK_FRAME_OUTER_OFF)->vval.v_string = (void *)ectx->ec_outer;
255 // TODO: save ec_outer_up_stack as well? 253 STACK_TV_BOT(STACK_FRAME_IDX_OFF)->vval.v_number = ectx->ec_frame_idx;
256 ectx->ec_frame_idx = ectx->ec_stack.ga_len; 254 ectx->ec_frame_idx = ectx->ec_stack.ga_len;
257 255
258 // Initialize local variables 256 // Initialize local variables
259 for (idx = 0; idx < dfunc->df_varcount; ++idx) 257 for (idx = 0; idx < dfunc->df_varcount; ++idx)
260 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; 258 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN;
265 tv->v_type = VAR_NUMBER; 263 tv->v_type = VAR_NUMBER;
266 tv->vval.v_number = 0; 264 tv->vval.v_number = 0;
267 } 265 }
268 ectx->ec_stack.ga_len += STACK_FRAME_SIZE + varcount; 266 ectx->ec_stack.ga_len += STACK_FRAME_SIZE + varcount;
269 267
270 if (ufunc->uf_partial != NULL) 268 if (pt != NULL || ufunc->uf_partial != NULL || ufunc->uf_flags & FC_CLOSURE)
271 { 269 {
272 ectx->ec_outer_stack = ufunc->uf_partial->pt_ectx_stack; 270 outer_T *outer = ALLOC_CLEAR_ONE(outer_T);
273 ectx->ec_outer_frame = ufunc->uf_partial->pt_ectx_frame; 271
274 ectx->ec_outer_up_stack = ufunc->uf_partial->pt_outer_stack; 272 if (outer == NULL)
275 ectx->ec_outer_up_frame = ufunc->uf_partial->pt_outer_frame; 273 return FAIL;
276 } 274 if (pt != NULL)
277 else if (ufunc->uf_flags & FC_CLOSURE) 275 {
278 { 276 *outer = pt->pt_outer;
279 ectx->ec_outer_stack = &ectx->ec_stack; 277 outer->out_up_is_copy = TRUE;
280 ectx->ec_outer_frame = ectx->ec_frame_idx; 278 }
281 ectx->ec_outer_up_stack = ectx->ec_outer_stack; 279 else if (ufunc->uf_partial != NULL)
282 ectx->ec_outer_up_frame = ectx->ec_outer_frame; 280 {
283 } 281 *outer = ufunc->uf_partial->pt_outer;
282 outer->out_up_is_copy = TRUE;
283 }
284 else
285 {
286 outer->out_stack = &ectx->ec_stack;
287 outer->out_frame_idx = ectx->ec_frame_idx;
288 outer->out_up = ectx->ec_outer;
289 }
290 ectx->ec_outer = outer;
291 }
292 else
293 ectx->ec_outer = NULL;
284 294
285 // Set execution state to the start of the called function. 295 // Set execution state to the start of the called function.
286 ectx->ec_dfunc_idx = cdf_idx; 296 ectx->ec_dfunc_idx = cdf_idx;
287 ectx->ec_instr = dfunc->df_instr; 297 ectx->ec_instr = dfunc->df_instr;
288 entry = estack_push_ufunc(dfunc->df_ufunc, 1); 298 entry = estack_push_ufunc(dfunc->df_ufunc, 1);
427 - closure_count + idx]; 437 - closure_count + idx];
428 if (pt->pt_refcount > 1) 438 if (pt->pt_refcount > 1)
429 { 439 {
430 ++funcstack->fs_refcount; 440 ++funcstack->fs_refcount;
431 pt->pt_funcstack = funcstack; 441 pt->pt_funcstack = funcstack;
432 pt->pt_ectx_stack = &funcstack->fs_ga; 442 pt->pt_outer.out_stack = &funcstack->fs_ga;
433 pt->pt_ectx_frame = ectx->ec_frame_idx - top; 443 pt->pt_outer.out_frame_idx = ectx->ec_frame_idx - top;
434 pt->pt_outer_stack = ectx->ec_outer_stack; 444 pt->pt_outer.out_up = ectx->ec_outer;
435 pt->pt_outer_frame = ectx->ec_outer_frame;
436 } 445 }
437 } 446 }
438 } 447 }
439 448
440 for (idx = 0; idx < closure_count; ++idx) 449 for (idx = 0; idx < closure_count; ++idx)
516 clear_tv(STACK_TV(idx)); 525 clear_tv(STACK_TV(idx));
517 526
518 // The return value should be on top of the stack. However, when aborting 527 // The return value should be on top of the stack. However, when aborting
519 // it may not be there and ec_frame_idx is the top of the stack. 528 // it may not be there and ec_frame_idx is the top of the stack.
520 ret_idx = ectx->ec_stack.ga_len - 1; 529 ret_idx = ectx->ec_stack.ga_len - 1;
521 if (ret_idx == ectx->ec_frame_idx + 4) 530 if (ret_idx == ectx->ec_frame_idx + STACK_FRAME_IDX_OFF)
522 ret_idx = 0; 531 ret_idx = 0;
523 532
533 if (ectx->ec_outer != NULL)
534 printf("here");
535 vim_free(ectx->ec_outer);
536
524 // Restore the previous frame. 537 // Restore the previous frame.
525 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number; 538 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx
526 ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number; 539 + STACK_FRAME_FUNC_OFF)->vval.v_number;
527 ectx->ec_outer_stack = 540 ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx
528 (void *)STACK_TV(ectx->ec_frame_idx + 2)->vval.v_string; 541 + STACK_FRAME_IIDX_OFF)->vval.v_number;
529 ectx->ec_outer_frame = STACK_TV(ectx->ec_frame_idx + 3)->vval.v_number; 542 ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx
543 + STACK_FRAME_OUTER_OFF)->vval.v_string;
530 // restoring ec_frame_idx must be last 544 // restoring ec_frame_idx must be last
531 ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 4)->vval.v_number; 545 ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx
546 + STACK_FRAME_IDX_OFF)->vval.v_number;
547 if (ectx->ec_outer != NULL)
548 printf("here");
532 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; 549 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
533 ectx->ec_instr = dfunc->df_instr; 550 ectx->ec_instr = dfunc->df_instr;
534 551
535 if (ret_idx > 0) 552 if (ret_idx > 0)
536 { 553 {
615 /* 632 /*
616 * Execute a user defined function. 633 * Execute a user defined function.
617 * If the function is compiled this will add a stack frame and set the 634 * If the function is compiled this will add a stack frame and set the
618 * instruction pointer at the start of the function. 635 * instruction pointer at the start of the function.
619 * Otherwise the function is called here. 636 * Otherwise the function is called here.
637 * If "pt" is not null use "pt->pt_outer" for ec_outer.
620 * "iptr" can be used to replace the instruction with a more efficient one. 638 * "iptr" can be used to replace the instruction with a more efficient one.
621 */ 639 */
622 static int 640 static int
623 call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr) 641 call_ufunc(
642 ufunc_T *ufunc,
643 partial_T *pt,
644 int argcount,
645 ectx_T *ectx,
646 isn_T *iptr)
624 { 647 {
625 typval_T argvars[MAX_FUNC_ARGS]; 648 typval_T argvars[MAX_FUNC_ARGS];
626 funcexe_T funcexe; 649 funcexe_T funcexe;
627 int error; 650 int error;
628 int idx; 651 int idx;
651 delete_instr(iptr); 674 delete_instr(iptr);
652 iptr->isn_type = ISN_DCALL; 675 iptr->isn_type = ISN_DCALL;
653 iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; 676 iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
654 iptr->isn_arg.dfunc.cdf_argcount = argcount; 677 iptr->isn_arg.dfunc.cdf_argcount = argcount;
655 } 678 }
656 return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx); 679 return call_dfunc(ufunc->uf_dfunc_idx, pt, argcount, ectx);
657 } 680 }
658 681
659 if (call_prepare(argcount, argvars, ectx) == FAIL) 682 if (call_prepare(argcount, argvars, ectx) == FAIL)
660 return FAIL; 683 return FAIL;
661 CLEAR_FIELD(funcexe); 684 CLEAR_FIELD(funcexe);
724 if (vim9_aborting(called_emsg_before)) 747 if (vim9_aborting(called_emsg_before))
725 return FAIL; // bail out if loading the script caused an error 748 return FAIL; // bail out if loading the script caused an error
726 } 749 }
727 750
728 if (ufunc != NULL) 751 if (ufunc != NULL)
729 return call_ufunc(ufunc, argcount, ectx, iptr); 752 return call_ufunc(ufunc, NULL, argcount, ectx, iptr);
730 753
731 return FAIL; 754 return FAIL;
732 } 755 }
733 756
734 static int 757 static int
759 for (i = 0; i < pt->pt_argc; ++i) 782 for (i = 0; i < pt->pt_argc; ++i)
760 copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i)); 783 copy_tv(&pt->pt_argv[i], STACK_TV_BOT(-argcount + i));
761 } 784 }
762 785
763 if (pt->pt_func != NULL) 786 if (pt->pt_func != NULL)
764 { 787 return call_ufunc(pt->pt_func, pt, argcount, ectx, NULL);
765 int frame_idx = ectx->ec_frame_idx; 788
766 int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL);
767
768 if (ectx->ec_frame_idx != frame_idx)
769 {
770 // call_dfunc() added a stack frame, closure may need the
771 // function context where it was defined.
772 ectx->ec_outer_stack = pt->pt_ectx_stack;
773 ectx->ec_outer_frame = pt->pt_ectx_frame;
774 ectx->ec_outer_up_stack = pt->pt_outer_stack;
775 ectx->ec_outer_up_frame = pt->pt_outer_frame;
776 }
777
778 return ret;
779 }
780 name = pt->pt_name; 789 name = pt->pt_name;
781 } 790 }
782 else if (tv->v_type == VAR_FUNC) 791 else if (tv->v_type == VAR_FUNC)
783 name = tv->vval.v_string; 792 name = tv->vval.v_string;
784 if (name != NULL) 793 if (name != NULL)
1063 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) 1072 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
1064 + ectx->ec_dfunc_idx; 1073 + ectx->ec_dfunc_idx;
1065 1074
1066 // The closure needs to find arguments and local 1075 // The closure needs to find arguments and local
1067 // variables in the current stack. 1076 // variables in the current stack.
1068 pt->pt_ectx_stack = &ectx->ec_stack; 1077 pt->pt_outer.out_stack = &ectx->ec_stack;
1069 pt->pt_ectx_frame = ectx->ec_frame_idx; 1078 pt->pt_outer.out_frame_idx = ectx->ec_frame_idx;
1070 pt->pt_outer_stack = ectx->ec_outer_stack; 1079 pt->pt_outer.out_up = ectx->ec_outer;
1071 pt->pt_outer_frame = ectx->ec_outer_frame; 1080 pt->pt_outer.out_up_is_copy = TRUE;
1072 1081
1073 // If this function returns and the closure is still 1082 // If this function returns and the closure is still
1074 // being used, we need to make a copy of the context 1083 // being used, we need to make a copy of the context
1075 // (arguments and local variables). Store a reference 1084 // (arguments and local variables). Store a reference
1076 // to the partial so we can handle that. 1085 // to the partial so we can handle that.
1133 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) 1142 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx)
1134 1143
1135 // Get pointer to a local variable on the stack. Negative for arguments. 1144 // Get pointer to a local variable on the stack. Negative for arguments.
1136 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) 1145 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx)
1137 1146
1138 // Like STACK_TV_VAR but use the outer scope
1139 #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
1140
1141 if (ufunc->uf_def_status == UF_NOT_COMPILED 1147 if (ufunc->uf_def_status == UF_NOT_COMPILED
1142 || (ufunc->uf_def_status == UF_TO_BE_COMPILED 1148 || (ufunc->uf_def_status == UF_TO_BE_COMPILED
1143 && compile_def_function(ufunc, FALSE, NULL) == FAIL)) 1149 && compile_def_function(ufunc, FALSE, NULL) == FAIL))
1144 { 1150 {
1145 if (did_emsg_cumul + did_emsg == did_emsg_before) 1151 if (did_emsg_cumul + did_emsg == did_emsg_before)
1239 1245
1240 // Frame pointer points to just after arguments. 1246 // Frame pointer points to just after arguments.
1241 ectx.ec_frame_idx = ectx.ec_stack.ga_len; 1247 ectx.ec_frame_idx = ectx.ec_stack.ga_len;
1242 initial_frame_idx = ectx.ec_frame_idx; 1248 initial_frame_idx = ectx.ec_frame_idx;
1243 1249
1244 if (partial != NULL) 1250 if (partial != NULL || ufunc->uf_partial != NULL)
1245 { 1251 {
1246 if (partial->pt_ectx_stack == NULL && current_ectx != NULL) 1252 ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T);
1253 if (ectx.ec_outer == NULL)
1254 goto failed_early;
1255 if (partial != NULL)
1247 { 1256 {
1248 // TODO: is this always the right way? 1257 if (partial->pt_outer.out_stack == NULL && current_ectx != NULL)
1249 ectx.ec_outer_stack = &current_ectx->ec_stack; 1258 {
1250 ectx.ec_outer_frame = current_ectx->ec_frame_idx; 1259 if (current_ectx->ec_outer != NULL)
1251 ectx.ec_outer_up_stack = current_ectx->ec_outer_stack; 1260 *ectx.ec_outer = *current_ectx->ec_outer;
1252 ectx.ec_outer_up_frame = current_ectx->ec_outer_frame; 1261 }
1262 else
1263 *ectx.ec_outer = partial->pt_outer;
1253 } 1264 }
1254 else 1265 else
1255 { 1266 *ectx.ec_outer = ufunc->uf_partial->pt_outer;
1256 ectx.ec_outer_stack = partial->pt_ectx_stack; 1267 ectx.ec_outer->out_up_is_copy = TRUE;
1257 ectx.ec_outer_frame = partial->pt_ectx_frame;
1258 ectx.ec_outer_up_stack = partial->pt_outer_stack;
1259 ectx.ec_outer_up_frame = partial->pt_outer_frame;
1260 }
1261 }
1262 else if (ufunc->uf_partial != NULL)
1263 {
1264 ectx.ec_outer_stack = ufunc->uf_partial->pt_ectx_stack;
1265 ectx.ec_outer_frame = ufunc->uf_partial->pt_ectx_frame;
1266 ectx.ec_outer_up_stack = ufunc->uf_partial->pt_outer_stack;
1267 ectx.ec_outer_up_frame = ufunc->uf_partial->pt_outer_frame;
1268 } 1268 }
1269 1269
1270 // dummy frame entries 1270 // dummy frame entries
1271 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) 1271 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx)
1272 { 1272 {
1544 goto failed; 1544 goto failed;
1545 copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); 1545 copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
1546 ++ectx.ec_stack.ga_len; 1546 ++ectx.ec_stack.ga_len;
1547 break; 1547 break;
1548 1548
1549 // load variable or argument from outer scope
1550 case ISN_LOADOUTER:
1551 {
1552 typval_T *stack;
1553 int depth = iptr->isn_arg.outer.outer_depth;
1554
1555 if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
1556 goto failed;
1557 if (depth <= 1)
1558 stack = ((typval_T *)ectx.ec_outer_stack->ga_data)
1559 + ectx.ec_outer_frame;
1560 else if (depth == 2)
1561 stack = ((typval_T *)ectx.ec_outer_up_stack->ga_data)
1562 + ectx.ec_outer_up_frame;
1563 else
1564 {
1565 SOURCING_LNUM = iptr->isn_lnum;
1566 iemsg("LOADOUTER level > 2 not supported yet");
1567 goto failed;
1568 }
1569
1570 copy_tv(stack + STACK_FRAME_SIZE
1571 + iptr->isn_arg.outer.outer_idx,
1572 STACK_TV_BOT(0));
1573 ++ectx.ec_stack.ga_len;
1574 }
1575 break;
1576
1577 // load v: variable 1549 // load v: variable
1578 case ISN_LOADV: 1550 case ISN_LOADV:
1579 if (GA_GROW(&ectx.ec_stack, 1) == FAIL) 1551 if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
1580 goto failed; 1552 goto failed;
1581 copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); 1553 copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
1763 1735
1764 // store local variable 1736 // store local variable
1765 case ISN_STORE: 1737 case ISN_STORE:
1766 --ectx.ec_stack.ga_len; 1738 --ectx.ec_stack.ga_len;
1767 tv = STACK_TV_VAR(iptr->isn_arg.number); 1739 tv = STACK_TV_VAR(iptr->isn_arg.number);
1768 clear_tv(tv);
1769 *tv = *STACK_TV_BOT(0);
1770 break;
1771
1772 // store variable or argument in outer scope
1773 case ISN_STOREOUTER:
1774 --ectx.ec_stack.ga_len;
1775 // TODO: use outer_depth
1776 tv = STACK_OUT_TV_VAR(iptr->isn_arg.outer.outer_idx);
1777 clear_tv(tv); 1740 clear_tv(tv);
1778 *tv = *STACK_TV_BOT(0); 1741 *tv = *STACK_TV_BOT(0);
1779 break; 1742 break;
1780 1743
1781 // store s: variable in old script 1744 // store s: variable in old script
2052 ectx.ec_stack.ga_len -= 3; 2015 ectx.ec_stack.ga_len -= 3;
2053 if (status == FAIL) 2016 if (status == FAIL)
2054 { 2017 {
2055 clear_tv(tv); 2018 clear_tv(tv);
2056 goto on_error; 2019 goto on_error;
2020 }
2021 }
2022 break;
2023
2024 // load or store variable or argument from outer scope
2025 case ISN_LOADOUTER:
2026 case ISN_STOREOUTER:
2027 {
2028 int depth = iptr->isn_arg.outer.outer_depth;
2029 outer_T *outer = ectx.ec_outer;
2030
2031 while (depth > 1 && outer != NULL)
2032 {
2033 outer = outer->out_up;
2034 --depth;
2035 }
2036 if (outer == NULL)
2037 {
2038 SOURCING_LNUM = iptr->isn_lnum;
2039 iemsg("LOADOUTER depth more than scope levels");
2040 goto failed;
2041 }
2042 tv = ((typval_T *)outer->out_stack->ga_data)
2043 + outer->out_frame_idx + STACK_FRAME_SIZE
2044 + iptr->isn_arg.outer.outer_idx;
2045 if (iptr->isn_type == ISN_LOADOUTER)
2046 {
2047 if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
2048 goto failed;
2049 copy_tv(tv, STACK_TV_BOT(0));
2050 ++ectx.ec_stack.ga_len;
2051 }
2052 else
2053 {
2054 --ectx.ec_stack.ga_len;
2055 clear_tv(tv);
2056 *tv = *STACK_TV_BOT(0);
2057 } 2057 }
2058 } 2058 }
2059 break; 2059 break;
2060 2060
2061 // unlet item in list or dict variable 2061 // unlet item in list or dict variable
2294 break; 2294 break;
2295 2295
2296 // call a :def function 2296 // call a :def function
2297 case ISN_DCALL: 2297 case ISN_DCALL:
2298 SOURCING_LNUM = iptr->isn_lnum; 2298 SOURCING_LNUM = iptr->isn_lnum;
2299 if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx, 2299 if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx, NULL,
2300 iptr->isn_arg.dfunc.cdf_argcount, 2300 iptr->isn_arg.dfunc.cdf_argcount,
2301 &ectx) == FAIL) 2301 &ectx) == FAIL)
2302 goto on_error; 2302 goto on_error;
2303 break; 2303 break;
2304 2304
3552 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) 3552 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
3553 clear_tv(STACK_TV(idx)); 3553 clear_tv(STACK_TV(idx));
3554 3554
3555 vim_free(ectx.ec_stack.ga_data); 3555 vim_free(ectx.ec_stack.ga_data);
3556 vim_free(ectx.ec_trystack.ga_data); 3556 vim_free(ectx.ec_trystack.ga_data);
3557
3558 while (ectx.ec_outer != NULL)
3559 {
3560 outer_T *up = ectx.ec_outer->out_up_is_copy
3561 ? NULL : ectx.ec_outer->out_up;
3562
3563 vim_free(ectx.ec_outer);
3564 ectx.ec_outer = up;
3565 }
3557 3566
3558 // Not sure if this is necessary. 3567 // Not sure if this is necessary.
3559 suppress_errthrow = save_suppress_errthrow; 3568 suppress_errthrow = save_suppress_errthrow;
3560 3569
3561 if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before) 3570 if (ret != OK && did_emsg_cumul + did_emsg == did_emsg_before)