Mercurial > vim
comparison src/vim9execute.c @ 20247:e46e72aaff74 v8.2.0679
patch 8.2.0679: Vim9: incomplete support for closures
Commit: https://github.com/vim/vim/commit/bf67ea1af05cbb30cd8f0b665fb567c0dca79796
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat May 2 17:52:42 2020 +0200
patch 8.2.0679: Vim9: incomplete support for closures
Problem: Vim9: incomplete support for closures.
Solution: At the end of a function copy arguments and local variables if
they are still used by a referenced closure.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 02 May 2020 18:00:04 +0200 |
parents | 23d75968ca5e |
children | aac52c32a91f |
comparison
equal
deleted
inserted
replaced
20246:ef2250432801 | 20247:e46e72aaff74 |
---|---|
22 | 22 |
23 #include "vim9.h" | 23 #include "vim9.h" |
24 | 24 |
25 // Structure put on ec_trystack when ISN_TRY is encountered. | 25 // Structure put on ec_trystack when ISN_TRY is encountered. |
26 typedef struct { | 26 typedef struct { |
27 int tcd_frame; // ec_frame when ISN_TRY was encountered | 27 int tcd_frame_idx; // ec_frame_idx when ISN_TRY was encountered |
28 int tcd_catch_idx; // instruction of the first catch | 28 int tcd_catch_idx; // instruction of the first catch |
29 int tcd_finally_idx; // instruction of the finally block | 29 int tcd_finally_idx; // instruction of the finally block |
30 int tcd_caught; // catch block entered | 30 int tcd_caught; // catch block entered |
31 int tcd_return; // when TRUE return from end of :finally | 31 int tcd_return; // when TRUE return from end of :finally |
32 } trycmd_T; | 32 } trycmd_T; |
54 /* | 54 /* |
55 * Execution context. | 55 * Execution context. |
56 */ | 56 */ |
57 typedef struct { | 57 typedef struct { |
58 garray_T ec_stack; // stack of typval_T values | 58 garray_T ec_stack; // stack of typval_T values |
59 int ec_frame; // 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 garray_T *ec_outer_stack; // stack used for closures |
62 int ec_outer_frame; // stack frame in ec_outer_stack | 62 int ec_outer_frame; // stack frame in ec_outer_stack |
63 | 63 |
64 garray_T ec_trystack; // stack of trycmd_T values | 64 garray_T ec_trystack; // stack of trycmd_T values |
200 if (arg_to_add < 0) | 200 if (arg_to_add < 0) |
201 { | 201 { |
202 iemsg("Argument count wrong?"); | 202 iemsg("Argument count wrong?"); |
203 return FAIL; | 203 return FAIL; |
204 } | 204 } |
205 if (ga_grow(&ectx->ec_stack, arg_to_add + 3 + dfunc->df_varcount) == FAIL) | 205 if (ga_grow(&ectx->ec_stack, arg_to_add + 3 |
206 + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) | |
206 return FAIL; | 207 return FAIL; |
207 | 208 |
208 // Move the vararg-list to below the missing optional arguments. | 209 // Move the vararg-list to below the missing optional arguments. |
209 if (vararg_count > 0 && arg_to_add > 0) | 210 if (vararg_count > 0 && arg_to_add > 0) |
210 *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1); | 211 *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1); |
213 for (idx = 0; idx < arg_to_add; ++idx) | 214 for (idx = 0; idx < arg_to_add; ++idx) |
214 STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN; | 215 STACK_TV_BOT(idx - vararg_count)->v_type = VAR_UNKNOWN; |
215 ectx->ec_stack.ga_len += arg_to_add; | 216 ectx->ec_stack.ga_len += arg_to_add; |
216 | 217 |
217 // Store current execution state in stack frame for ISN_RETURN. | 218 // Store current execution state in stack frame for ISN_RETURN. |
218 // TODO: If the actual number of arguments doesn't match what the called | |
219 // function expects things go bad. | |
220 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; | 219 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; |
221 STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; | 220 STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; |
222 STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame; | 221 STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx; |
223 ectx->ec_frame = ectx->ec_stack.ga_len; | 222 ectx->ec_frame_idx = ectx->ec_stack.ga_len; |
224 | 223 |
225 // Initialize local variables | 224 // Initialize local variables |
226 for (idx = 0; idx < dfunc->df_varcount; ++idx) | 225 for (idx = 0; idx < dfunc->df_varcount + dfunc->df_closure_count; ++idx) |
227 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; | 226 STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; |
228 ectx->ec_stack.ga_len += STACK_FRAME_SIZE + dfunc->df_varcount; | 227 ectx->ec_stack.ga_len += STACK_FRAME_SIZE |
228 + dfunc->df_varcount + dfunc->df_closure_count; | |
229 | 229 |
230 // Set execution state to the start of the called function. | 230 // Set execution state to the start of the called function. |
231 ectx->ec_dfunc_idx = cdf_idx; | 231 ectx->ec_dfunc_idx = cdf_idx; |
232 ectx->ec_instr = dfunc->df_instr; | 232 ectx->ec_instr = dfunc->df_instr; |
233 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); | 233 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); |
234 | 234 |
235 // used for closures | 235 // used for closures |
236 ectx->ec_outer_stack = ufunc->uf_ectx_stack; | 236 ectx->ec_outer_stack = dfunc->df_ectx_stack; |
237 ectx->ec_outer_frame = ufunc->uf_ectx_frame; | 237 ectx->ec_outer_frame = dfunc->df_ectx_frame; |
238 | 238 |
239 // Decide where to start execution, handles optional arguments. | 239 // Decide where to start execution, handles optional arguments. |
240 init_instr_idx(ufunc, argcount, ectx); | 240 init_instr_idx(ufunc, argcount, ectx); |
241 | 241 |
242 return OK; | 242 return OK; |
243 } | 243 } |
244 | 244 |
245 // Get pointer to item in the stack. | 245 // Get pointer to item in the stack. |
246 #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) | 246 #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) |
247 | |
248 /* | |
249 * Used when returning from a function: Check if any closure is still | |
250 * referenced. If so then move the arguments and variables to a separate piece | |
251 * of stack to be used when the closure is called. | |
252 * When "free_arguments" is TRUE the arguments are to be freed. | |
253 * Returns FAIL when out of memory. | |
254 */ | |
255 static int | |
256 handle_closure_in_use(ectx_T *ectx, int free_arguments) | |
257 { | |
258 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) | |
259 + ectx->ec_dfunc_idx; | |
260 int argcount = ufunc_argcount(dfunc->df_ufunc); | |
261 int top = ectx->ec_frame_idx - argcount; | |
262 int idx; | |
263 typval_T *tv; | |
264 int closure_in_use = FALSE; | |
265 | |
266 // Check if any created closure is still in use. | |
267 for (idx = 0; idx < dfunc->df_closure_count; ++idx) | |
268 { | |
269 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE | |
270 + dfunc->df_varcount + idx); | |
271 if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1) | |
272 closure_in_use = TRUE; | |
273 } | |
274 | |
275 if (closure_in_use) | |
276 { | |
277 funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T); | |
278 typval_T *stack; | |
279 | |
280 // A closure is using the arguments and/or local variables. | |
281 // Move them to the called function. | |
282 if (funcstack == NULL) | |
283 return FAIL; | |
284 funcstack->fs_ga.ga_len = argcount + STACK_FRAME_SIZE | |
285 + dfunc->df_varcount; | |
286 stack = ALLOC_CLEAR_MULT(typval_T, funcstack->fs_ga.ga_len); | |
287 funcstack->fs_ga.ga_data = stack; | |
288 if (stack == NULL) | |
289 { | |
290 vim_free(funcstack); | |
291 return FAIL; | |
292 } | |
293 | |
294 // Move or copy the arguments. | |
295 for (idx = 0; idx < argcount; ++idx) | |
296 { | |
297 tv = STACK_TV(top + idx); | |
298 if (free_arguments) | |
299 { | |
300 *(stack + idx) = *tv; | |
301 tv->v_type = VAR_UNKNOWN; | |
302 } | |
303 else | |
304 copy_tv(tv, stack + idx); | |
305 } | |
306 // Move the local variables. | |
307 for (idx = 0; idx < dfunc->df_varcount; ++idx) | |
308 { | |
309 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx); | |
310 *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv; | |
311 tv->v_type = VAR_UNKNOWN; | |
312 } | |
313 | |
314 for (idx = 0; idx < dfunc->df_closure_count; ++idx) | |
315 { | |
316 tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE | |
317 + dfunc->df_varcount + idx); | |
318 if (tv->v_type == VAR_PARTIAL | |
319 && tv->vval.v_partial->pt_refcount > 1) | |
320 { | |
321 dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) | |
322 + tv->vval.v_partial->pt_func->uf_dfunc_idx; | |
323 ++funcstack->fs_refcount; | |
324 pt_dfunc->df_funcstack = funcstack; | |
325 pt_dfunc->df_ectx_stack = &funcstack->fs_ga; | |
326 pt_dfunc->df_ectx_frame = ectx->ec_frame_idx - top; | |
327 } | |
328 } | |
329 } | |
330 | |
331 return OK; | |
332 } | |
247 | 333 |
248 /* | 334 /* |
249 * Return from the current function. | 335 * Return from the current function. |
250 */ | 336 */ |
251 static void | 337 static int |
252 func_return(ectx_T *ectx) | 338 func_return(ectx_T *ectx) |
253 { | 339 { |
254 int idx; | 340 int idx; |
255 dfunc_T *dfunc; | 341 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) |
256 int top; | 342 + ectx->ec_dfunc_idx; |
343 int argcount = ufunc_argcount(dfunc->df_ufunc); | |
344 int top = ectx->ec_frame_idx - argcount; | |
257 | 345 |
258 // execution context goes one level up | 346 // execution context goes one level up |
259 estack_pop(); | 347 estack_pop(); |
260 | 348 |
261 // Clear the local variables and temporary values, but not | 349 if (handle_closure_in_use(ectx, TRUE) == FAIL) |
262 // the return value. | 350 return FAIL; |
263 for (idx = ectx->ec_frame + STACK_FRAME_SIZE; | 351 |
352 // Clear the arguments. | |
353 for (idx = top; idx < ectx->ec_frame_idx; ++idx) | |
354 clear_tv(STACK_TV(idx)); | |
355 | |
356 // Clear local variables and temp values, but not the return value. | |
357 for (idx = ectx->ec_frame_idx + STACK_FRAME_SIZE; | |
264 idx < ectx->ec_stack.ga_len - 1; ++idx) | 358 idx < ectx->ec_stack.ga_len - 1; ++idx) |
265 clear_tv(STACK_TV(idx)); | 359 clear_tv(STACK_TV(idx)); |
266 | 360 |
267 // Clear the arguments. | |
268 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; | |
269 top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc); | |
270 for (idx = top; idx < ectx->ec_frame; ++idx) | |
271 clear_tv(STACK_TV(idx)); | |
272 | |
273 // Restore the previous frame. | 361 // Restore the previous frame. |
274 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number; | 362 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number; |
275 ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number; | 363 ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number; |
276 ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number; | 364 ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 2)->vval.v_number; |
277 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; | 365 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; |
278 ectx->ec_instr = dfunc->df_instr; | 366 ectx->ec_instr = dfunc->df_instr; |
279 | 367 |
280 // Reset the stack to the position before the call, move the return value | 368 // Reset the stack to the position before the call, move the return value |
281 // to the top of the stack. | 369 // to the top of the stack. |
282 idx = ectx->ec_stack.ga_len - 1; | 370 idx = ectx->ec_stack.ga_len - 1; |
283 ectx->ec_stack.ga_len = top + 1; | 371 ectx->ec_stack.ga_len = top + 1; |
284 *STACK_TV_BOT(-1) = *STACK_TV(idx); | 372 *STACK_TV_BOT(-1) = *STACK_TV(idx); |
373 | |
374 return OK; | |
285 } | 375 } |
286 | 376 |
287 #undef STACK_TV | 377 #undef STACK_TV |
288 | 378 |
289 /* | 379 /* |
496 typval_T *argv, // arguments | 586 typval_T *argv, // arguments |
497 typval_T *rettv) // return value | 587 typval_T *rettv) // return value |
498 { | 588 { |
499 ectx_T ectx; // execution context | 589 ectx_T ectx; // execution context |
500 int argc = argc_arg; | 590 int argc = argc_arg; |
501 int initial_frame_ptr; | 591 int initial_frame_idx; |
502 typval_T *tv; | 592 typval_T *tv; |
503 int idx; | 593 int idx; |
504 int ret = FAIL; | 594 int ret = FAIL; |
505 int defcount = ufunc->uf_args.ga_len - argc; | 595 int defcount = ufunc->uf_args.ga_len - argc; |
506 int save_sc_version = current_sctx.sc_version; | 596 int save_sc_version = current_sctx.sc_version; |
511 // Get pointer to item at the bottom of the stack, -1 is the bottom. | 601 // Get pointer to item at the bottom of the stack, -1 is the bottom. |
512 #undef STACK_TV_BOT | 602 #undef STACK_TV_BOT |
513 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) | 603 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) |
514 | 604 |
515 // Get pointer to a local variable on the stack. Negative for arguments. | 605 // Get pointer to a local variable on the stack. Negative for arguments. |
516 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) | 606 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) |
517 | 607 |
518 // Like STACK_TV_VAR but use the outer scope | 608 // Like STACK_TV_VAR but use the outer scope |
519 #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) | 609 #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) |
520 | 610 |
521 CLEAR_FIELD(ectx); | 611 CLEAR_FIELD(ectx); |
560 } | 650 } |
561 if (ufunc->uf_va_name != NULL) | 651 if (ufunc->uf_va_name != NULL) |
562 ++ectx.ec_stack.ga_len; | 652 ++ectx.ec_stack.ga_len; |
563 | 653 |
564 // Frame pointer points to just after arguments. | 654 // Frame pointer points to just after arguments. |
565 ectx.ec_frame = ectx.ec_stack.ga_len; | 655 ectx.ec_frame_idx = ectx.ec_stack.ga_len; |
566 initial_frame_ptr = ectx.ec_frame; | 656 initial_frame_idx = ectx.ec_frame_idx; |
567 | 657 |
568 // dummy frame entries | 658 // dummy frame entries |
569 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) | 659 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) |
570 { | 660 { |
571 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN; | 661 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN; |
572 ++ectx.ec_stack.ga_len; | 662 ++ectx.ec_stack.ga_len; |
573 } | 663 } |
574 | 664 |
575 { | 665 { |
576 // Reserve space for local variables. | 666 // Reserve space for local variables and closure references. |
577 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) | 667 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) |
578 + ufunc->uf_dfunc_idx; | 668 + ufunc->uf_dfunc_idx; |
579 | 669 int count = dfunc->df_varcount + dfunc->df_closure_count; |
580 for (idx = 0; idx < dfunc->df_varcount; ++idx) | 670 |
671 for (idx = 0; idx < count; ++idx) | |
581 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; | 672 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; |
582 ectx.ec_stack.ga_len += dfunc->df_varcount; | 673 ectx.ec_stack.ga_len += count; |
583 | 674 |
584 ectx.ec_instr = dfunc->df_instr; | 675 ectx.ec_instr = dfunc->df_instr; |
585 } | 676 } |
586 | 677 |
587 // Commands behave like vim9script. | 678 // Commands behave like vim9script. |
621 | 712 |
622 // An exception jumps to the first catch, finally, or returns from | 713 // An exception jumps to the first catch, finally, or returns from |
623 // the current function. | 714 // the current function. |
624 if (trystack->ga_len > 0) | 715 if (trystack->ga_len > 0) |
625 trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; | 716 trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; |
626 if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame) | 717 if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx) |
627 { | 718 { |
628 // jump to ":catch" or ":finally" | 719 // jump to ":catch" or ":finally" |
629 ectx.ec_in_catch = TRUE; | 720 ectx.ec_in_catch = TRUE; |
630 ectx.ec_iidx = trycmd->tcd_catch_idx; | 721 ectx.ec_iidx = trycmd->tcd_catch_idx; |
631 } | 722 } |
632 else | 723 else |
633 { | 724 { |
634 // not inside try or need to return from current functions. | 725 // not inside try or need to return from current functions. |
635 if (ectx.ec_frame == initial_frame_ptr) | 726 if (ectx.ec_frame_idx == initial_frame_idx) |
636 { | 727 { |
637 // At the toplevel we are done. Push a dummy return value. | 728 // At the toplevel we are done. Push a dummy return value. |
638 if (ga_grow(&ectx.ec_stack, 1) == FAIL) | 729 if (ga_grow(&ectx.ec_stack, 1) == FAIL) |
639 goto failed; | 730 goto failed; |
640 tv = STACK_TV_BOT(0); | 731 tv = STACK_TV_BOT(0); |
641 tv->v_type = VAR_NUMBER; | 732 tv->v_type = VAR_NUMBER; |
642 tv->vval.v_number = 0; | 733 tv->vval.v_number = 0; |
643 ++ectx.ec_stack.ga_len; | 734 ++ectx.ec_stack.ga_len; |
644 need_rethrow = TRUE; | 735 need_rethrow = TRUE; |
736 if (handle_closure_in_use(&ectx, FALSE) == FAIL) | |
737 goto failed; | |
645 goto done; | 738 goto done; |
646 } | 739 } |
647 | 740 |
648 func_return(&ectx); | 741 if (func_return(&ectx) == FAIL) |
742 goto failed; | |
649 } | 743 } |
650 continue; | 744 continue; |
651 } | 745 } |
652 | 746 |
653 iptr = &ectx.ec_instr[ectx.ec_iidx++]; | 747 iptr = &ectx.ec_instr[ectx.ec_iidx++]; |
1071 default: // Cannot reach here | 1165 default: // Cannot reach here |
1072 goto failed; | 1166 goto failed; |
1073 } | 1167 } |
1074 | 1168 |
1075 --ectx.ec_stack.ga_len; | 1169 --ectx.ec_stack.ga_len; |
1076 di = find_var_in_ht(ht, 0, | 1170 di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE); |
1077 iptr->isn_arg.string + 2, TRUE); | |
1078 if (di == NULL) | 1171 if (di == NULL) |
1079 store_var(iptr->isn_arg.string, STACK_TV_BOT(0)); | 1172 store_var(iptr->isn_arg.string, STACK_TV_BOT(0)); |
1080 else | 1173 else |
1081 { | 1174 { |
1082 clear_tv(&di->di_tv); | 1175 clear_tv(&di->di_tv); |
1287 trycmd_T *trycmd = NULL; | 1380 trycmd_T *trycmd = NULL; |
1288 | 1381 |
1289 if (trystack->ga_len > 0) | 1382 if (trystack->ga_len > 0) |
1290 trycmd = ((trycmd_T *)trystack->ga_data) | 1383 trycmd = ((trycmd_T *)trystack->ga_data) |
1291 + trystack->ga_len - 1; | 1384 + trystack->ga_len - 1; |
1292 if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame | 1385 if (trycmd != NULL |
1386 && trycmd->tcd_frame_idx == ectx.ec_frame_idx | |
1293 && trycmd->tcd_finally_idx != 0) | 1387 && trycmd->tcd_finally_idx != 0) |
1294 { | 1388 { |
1295 // jump to ":finally" | 1389 // jump to ":finally" |
1296 ectx.ec_iidx = trycmd->tcd_finally_idx; | 1390 ectx.ec_iidx = trycmd->tcd_finally_idx; |
1297 trycmd->tcd_return = TRUE; | 1391 trycmd->tcd_return = TRUE; |
1298 } | 1392 } |
1299 else | 1393 else |
1300 { | 1394 { |
1301 // Restore previous function. If the frame pointer | 1395 // Restore previous function. If the frame pointer |
1302 // is zero then there is none and we are done. | 1396 // is zero then there is none and we are done. |
1303 if (ectx.ec_frame == initial_frame_ptr) | 1397 if (ectx.ec_frame_idx == initial_frame_idx) |
1398 { | |
1399 if (handle_closure_in_use(&ectx, FALSE) == FAIL) | |
1400 goto failed; | |
1304 goto done; | 1401 goto done; |
1305 | 1402 } |
1306 func_return(&ectx); | 1403 |
1404 if (func_return(&ectx) == FAIL) | |
1405 goto failed; | |
1307 } | 1406 } |
1308 } | 1407 } |
1309 break; | 1408 break; |
1310 | 1409 |
1311 // push a function reference to a compiled function | 1410 // push a function reference to a compiled function |
1312 case ISN_FUNCREF: | 1411 case ISN_FUNCREF: |
1313 { | 1412 { |
1314 partial_T *pt = NULL; | 1413 partial_T *pt = NULL; |
1315 dfunc_T *dfunc; | 1414 dfunc_T *pt_dfunc; |
1316 | 1415 |
1317 pt = ALLOC_CLEAR_ONE(partial_T); | 1416 pt = ALLOC_CLEAR_ONE(partial_T); |
1318 if (pt == NULL) | 1417 if (pt == NULL) |
1319 goto failed; | 1418 goto failed; |
1320 dfunc = ((dfunc_T *)def_functions.ga_data) | 1419 if (ga_grow(&ectx.ec_stack, 1) == FAIL) |
1321 + iptr->isn_arg.number; | 1420 { |
1322 pt->pt_func = dfunc->df_ufunc; | 1421 vim_free(pt); |
1422 goto failed; | |
1423 } | |
1424 pt_dfunc = ((dfunc_T *)def_functions.ga_data) | |
1425 + iptr->isn_arg.funcref.fr_func; | |
1426 pt->pt_func = pt_dfunc->df_ufunc; | |
1323 pt->pt_refcount = 1; | 1427 pt->pt_refcount = 1; |
1324 ++dfunc->df_ufunc->uf_refcount; | 1428 ++pt_dfunc->df_ufunc->uf_refcount; |
1325 | 1429 |
1326 if (dfunc->df_ufunc->uf_flags & FC_CLOSURE) | 1430 if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE) |
1327 { | 1431 { |
1328 // Closure needs to find local variables in the current | 1432 dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) |
1329 // stack. | 1433 + ectx.ec_dfunc_idx; |
1330 dfunc->df_ufunc->uf_ectx_stack = &ectx.ec_stack; | 1434 |
1331 dfunc->df_ufunc->uf_ectx_frame = ectx.ec_frame; | 1435 // The closure needs to find arguments and local |
1332 } | 1436 // variables in the current stack. |
1333 | 1437 pt_dfunc->df_ectx_stack = &ectx.ec_stack; |
1334 if (ga_grow(&ectx.ec_stack, 1) == FAIL) | 1438 pt_dfunc->df_ectx_frame = ectx.ec_frame_idx; |
1335 goto failed; | 1439 |
1440 // If this function returns and the closure is still | |
1441 // used, we need to make a copy of the context | |
1442 // (arguments and local variables). Store a reference | |
1443 // to the partial so we can handle that. | |
1444 ++pt->pt_refcount; | |
1445 tv = STACK_TV_VAR(dfunc->df_varcount | |
1446 + iptr->isn_arg.funcref.fr_var_idx); | |
1447 if (tv->v_type == VAR_PARTIAL) | |
1448 { | |
1449 // TODO: use a garray_T on ectx. | |
1450 emsg("Multiple closures not supported yet"); | |
1451 goto failed; | |
1452 } | |
1453 tv->v_type = VAR_PARTIAL; | |
1454 tv->vval.v_partial = pt; | |
1455 } | |
1456 | |
1336 tv = STACK_TV_BOT(0); | 1457 tv = STACK_TV_BOT(0); |
1337 ++ectx.ec_stack.ga_len; | 1458 ++ectx.ec_stack.ga_len; |
1338 tv->vval.v_partial = pt; | 1459 tv->vval.v_partial = pt; |
1339 tv->v_type = VAR_PARTIAL; | 1460 tv->v_type = VAR_PARTIAL; |
1340 } | 1461 } |
1408 goto failed; | 1529 goto failed; |
1409 trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data) | 1530 trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data) |
1410 + ectx.ec_trystack.ga_len; | 1531 + ectx.ec_trystack.ga_len; |
1411 ++ectx.ec_trystack.ga_len; | 1532 ++ectx.ec_trystack.ga_len; |
1412 ++trylevel; | 1533 ++trylevel; |
1413 trycmd->tcd_frame = ectx.ec_frame; | 1534 trycmd->tcd_frame_idx = ectx.ec_frame_idx; |
1414 trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch; | 1535 trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch; |
1415 trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally; | 1536 trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally; |
1416 trycmd->tcd_caught = FALSE; | 1537 trycmd->tcd_caught = FALSE; |
1417 } | 1538 } |
1418 break; | 1539 break; |
1470 | 1591 |
1471 if (trycmd->tcd_return) | 1592 if (trycmd->tcd_return) |
1472 { | 1593 { |
1473 // Restore previous function. If the frame pointer | 1594 // Restore previous function. If the frame pointer |
1474 // is zero then there is none and we are done. | 1595 // is zero then there is none and we are done. |
1475 if (ectx.ec_frame == initial_frame_ptr) | 1596 if (ectx.ec_frame_idx == initial_frame_idx) |
1597 { | |
1598 if (handle_closure_in_use(&ectx, FALSE) == FAIL) | |
1599 goto failed; | |
1476 goto done; | 1600 goto done; |
1477 | 1601 } |
1478 func_return(&ectx); | 1602 |
1603 if (func_return(&ectx) == FAIL) | |
1604 goto failed; | |
1479 } | 1605 } |
1480 } | 1606 } |
1481 } | 1607 } |
1482 break; | 1608 break; |
1483 | 1609 |
1947 tv->v_type = VAR_UNKNOWN; | 2073 tv->v_type = VAR_UNKNOWN; |
1948 ret = OK; | 2074 ret = OK; |
1949 | 2075 |
1950 failed: | 2076 failed: |
1951 // When failed need to unwind the call stack. | 2077 // When failed need to unwind the call stack. |
1952 while (ectx.ec_frame != initial_frame_ptr) | 2078 while (ectx.ec_frame_idx != initial_frame_idx) |
1953 func_return(&ectx); | 2079 func_return(&ectx); |
1954 failed_early: | 2080 failed_early: |
1955 current_sctx.sc_version = save_sc_version; | 2081 current_sctx.sc_version = save_sc_version; |
2082 | |
2083 // Free all local variables, but not arguments. | |
1956 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) | 2084 for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) |
1957 clear_tv(STACK_TV(idx)); | 2085 clear_tv(STACK_TV(idx)); |
2086 | |
1958 vim_free(ectx.ec_stack.ga_data); | 2087 vim_free(ectx.ec_stack.ga_data); |
1959 vim_free(ectx.ec_trystack.ga_data); | 2088 vim_free(ectx.ec_trystack.ga_data); |
1960 return ret; | 2089 return ret; |
1961 } | 2090 } |
1962 | 2091 |
2307 smsg("%4d RETURN", current); | 2436 smsg("%4d RETURN", current); |
2308 break; | 2437 break; |
2309 case ISN_FUNCREF: | 2438 case ISN_FUNCREF: |
2310 { | 2439 { |
2311 dfunc_T *df = ((dfunc_T *)def_functions.ga_data) | 2440 dfunc_T *df = ((dfunc_T *)def_functions.ga_data) |
2312 + iptr->isn_arg.number; | 2441 + iptr->isn_arg.funcref.fr_func; |
2313 | 2442 |
2314 smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name); | 2443 smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name, |
2444 iptr->isn_arg.funcref.fr_var_idx + df->df_varcount); | |
2315 } | 2445 } |
2316 break; | 2446 break; |
2317 | 2447 |
2318 case ISN_JUMP: | 2448 case ISN_JUMP: |
2319 { | 2449 { |