Mercurial > vim
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 = ¤t_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) |