Mercurial > vim
diff src/vim9execute.c @ 20244:23d75968ca5e
patch 8.2.0677: Vim9: no support for closures
Commit: https://github.com/vim/vim/commit/c8cd2b34d1027c93fbca90f3cdc8123fe22dfa25
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri May 1 19:29:08 2020 +0200
patch 8.2.0677: Vim9: no support for closures
Problem: Vim9: no support for closures.
Solution: Find variables in the outer function scope, so long as the scope
exists.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 01 May 2020 19:30:04 +0200 |
parents | eaaee0dfa435 |
children | e46e72aaff74 |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -58,6 +58,9 @@ typedef struct { garray_T ec_stack; // stack of typval_T values int ec_frame; // index in ec_stack: context of ec_dfunc_idx + garray_T *ec_outer_stack; // stack used for closures + int ec_outer_frame; // stack frame in ec_outer_stack + garray_T ec_trystack; // stack of trycmd_T values int ec_in_catch; // when TRUE in catch or finally block @@ -229,6 +232,10 @@ call_dfunc(int cdf_idx, int argcount_arg ectx->ec_instr = dfunc->df_instr; estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); + // used for closures + ectx->ec_outer_stack = ufunc->uf_ectx_stack; + ectx->ec_outer_frame = ufunc->uf_ectx_frame; + // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); @@ -508,6 +515,9 @@ call_def_function( // Get pointer to a local variable on the stack. Negative for arguments. #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) +// Like STACK_TV_VAR but use the outer scope +#define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) + CLEAR_FIELD(ectx); ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); if (ga_grow(&ectx.ec_stack, 20) == FAIL) @@ -786,6 +796,15 @@ call_def_function( ++ectx.ec_stack.ga_len; break; + // load variable or argument from outer scope + case ISN_LOADOUTER: + if (ga_grow(&ectx.ec_stack, 1) == FAIL) + goto failed; + copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number), + STACK_TV_BOT(0)); + ++ectx.ec_stack.ga_len; + break; + // load v: variable case ISN_LOADV: if (ga_grow(&ectx.ec_stack, 1) == FAIL) @@ -1304,6 +1323,14 @@ call_def_function( pt->pt_refcount = 1; ++dfunc->df_ufunc->uf_refcount; + if (dfunc->df_ufunc->uf_flags & FC_CLOSURE) + { + // Closure needs to find local variables in the current + // stack. + dfunc->df_ufunc->uf_ectx_stack = &ectx.ec_stack; + dfunc->df_ufunc->uf_ectx_frame = ectx.ec_frame; + } + if (ga_grow(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); @@ -1862,7 +1889,12 @@ call_def_function( checktype_T *ct = &iptr->isn_arg.type; tv = STACK_TV_BOT(ct->ct_off); - if (tv->v_type != ct->ct_type) + // TODO: better type comparison + if (tv->v_type != ct->ct_type + && !((tv->v_type == VAR_PARTIAL + && ct->ct_type == VAR_FUNC) + || (tv->v_type == VAR_FUNC + && ct->ct_type == VAR_PARTIAL))) { semsg(_("E1029: Expected %s but got %s"), vartype_name(ct->ct_type), @@ -2029,12 +2061,18 @@ ex_disassemble(exarg_T *eap) (long long)(iptr->isn_arg.number)); break; case ISN_LOAD: - if (iptr->isn_arg.number < 0) - smsg("%4d LOAD arg[%lld]", current, - (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE)); - else - smsg("%4d LOAD $%lld", current, + case ISN_LOADOUTER: + { + char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER"; + + if (iptr->isn_arg.number < 0) + smsg("%4d LOAD%s arg[%lld]", current, add, + (long long)(iptr->isn_arg.number + + STACK_FRAME_SIZE)); + else + smsg("%4d LOAD%s $%lld", current, add, (long long)(iptr->isn_arg.number)); + } break; case ISN_LOADV: smsg("%4d LOADV v:%s", current,