Mercurial > vim
diff src/vim9compile.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 | 6f9010b6f7f9 |
line wrap: on
line diff
--- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -116,6 +116,9 @@ struct cctx_S { garray_T ctx_locals; // currently visible local variables int ctx_locals_count; // total number of local variables + int ctx_closure_count; // number of closures created in the + // function + garray_T ctx_imports; // imported items int ctx_skip; // when TRUE skip commands, when FALSE skip @@ -1254,7 +1257,8 @@ generate_FUNCREF(cctx_T *cctx, int dfunc RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) return FAIL; - isn->isn_arg.number = dfunc_idx; + isn->isn_arg.funcref.fr_func = dfunc_idx; + isn->isn_arg.funcref.fr_var_idx = cctx->ctx_closure_count++; if (ga_grow(stack, 1) == FAIL) return FAIL; @@ -6395,6 +6399,7 @@ compile_def_function(ufunc_T *ufunc, int dfunc->df_instr = instr->ga_data; dfunc->df_instr_count = instr->ga_len; dfunc->df_varcount = cctx.ctx_locals_count; + dfunc->df_closure_count = cctx.ctx_closure_count; if (cctx.ctx_outer_used) ufunc->uf_flags |= FC_CLOSURE; } @@ -6620,6 +6625,23 @@ delete_def_function_contents(dfunc_T *df delete_instr(dfunc->df_instr + idx); VIM_CLEAR(dfunc->df_instr); } + if (dfunc->df_funcstack != NULL) + { + // Decrease the reference count for the context of a closure. If down + // to zero free it and clear the variables on the stack. + if (--dfunc->df_funcstack->fs_refcount == 0) + { + garray_T *gap = &dfunc->df_funcstack->fs_ga; + typval_T *stack = gap->ga_data; + int i; + + for (i = 0; i < gap->ga_len; ++i) + clear_tv(stack + i); + ga_clear(gap); + vim_free(dfunc->df_funcstack); + } + dfunc->df_funcstack = NULL; + } dfunc->df_deleted = TRUE; }