diff options
author | Michael Ennen <mike.ennen@gmail.com> | 2016-12-17 16:01:42 -0700 |
---|---|---|
committer | Michael Ennen <mike.ennen@gmail.com> | 2017-02-14 17:38:17 -0700 |
commit | f59321e319ecfc6977f666fb04a52ac50bead09d (patch) | |
tree | 9c98a259e9810ec6f2edc7d020d6164e64bb79e1 /src | |
parent | 9f6f7fe26d7caa89083f5d5b00c55bf2046591ca (diff) | |
download | rneovim-f59321e319ecfc6977f666fb04a52ac50bead09d.tar.gz rneovim-f59321e319ecfc6977f666fb04a52ac50bead09d.tar.bz2 rneovim-f59321e319ecfc6977f666fb04a52ac50bead09d.zip |
vim-patch:7.4.2120
Problem: User defined functions can't be a closure.
Solution: Add the "closure" argument. Allow using :unlet on a bound
variable. (Yasuhiro Matsumoto, Ken Takata)
https://github.com/vim/vim/commit/10ce39a0d52272a3dfff2feb8c631529f29e6740
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 90 | ||||
-rw-r--r-- | src/nvim/testdir/test_lambda.vim | 2 | ||||
-rw-r--r-- | src/nvim/version.c | 2 |
3 files changed, 80 insertions, 14 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 63af474030..5ebd86a59d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -209,10 +209,13 @@ static int echo_attr = 0; /* attributes used for ":echo" */ #define GLV_QUIET TFN_QUIET /* no error messages */ #define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD /* do not use script autoloading */ -/* function flags */ -#define FC_ABORT 1 /* abort function on error */ -#define FC_RANGE 2 /* function accepts range */ -#define FC_DICT 4 /* Dict function, uses "self" */ +// function flags +#define FC_ABORT 1 // abort function on error +#define FC_RANGE 2 // function accepts range +#define FC_DICT 4 // Dict function, uses "self" +#define FC_CLOSURE 8 // closure, uses outer scope variables +#define FC_DELETED 16 // :delfunction used while uf_refcount > 0 +#define FC_REMOVED 32 // function redefined while uf_refcount > 0 /* The names of packages that once were loaded are remembered. */ static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL}; @@ -3070,7 +3073,10 @@ int do_unlet(char_u *name, int forceit) return FAIL; } hi = hash_find(ht, varname); - if (!HASHITEM_EMPTY(hi)) { + if (HASHITEM_EMPTY(hi)) { + hi = find_hi_in_scoped_ht(name, &varname, &ht); + } + if (hi != NULL && !HASHITEM_EMPTY(hi)) { di = HI2DI(hi); if (var_check_fixed(di->di_flags, name, false) || var_check_ro(di->di_flags, name, false) @@ -7070,7 +7076,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) (*arg)++; if (evaluate) { - int len; + int len, flags = 0; char_u *p; snprintf((char *)name, sizeof(name), "<lambda>%d", lambda_no++); @@ -7100,6 +7106,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) fp->uf_args = newargs; fp->uf_lines = newlines; if (current_funccal != NULL && eval_lavars) { + flags |= FC_CLOSURE; fp->uf_scoped = current_funccal; current_funccal->fc_refcount++; ga_grow(¤t_funccal->fc_funcs, 1); @@ -7118,7 +7125,7 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) func_do_profile(fp); } fp->uf_varargs = true; - fp->uf_flags = 0; + fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ID = current_SID; @@ -21050,7 +21057,7 @@ void ex_function(exarg_T *eap) goto errret_2; } - // find extra arguments "range", "dict" and "abort" + // find extra arguments "range", "dict", "abort" and "closure" for (;; ) { p = skipwhite(p); if (STRNCMP(p, "range", 5) == 0) { @@ -21062,8 +21069,12 @@ void ex_function(exarg_T *eap) } else if (STRNCMP(p, "abort", 5) == 0) { flags |= FC_ABORT; p += 5; - } else + } else if (STRNCMP(p, "closure", 7) == 0) { + flags |= FC_CLOSURE; + p += 7; + } else { break; + } } /* When there is a line break use what follows for the function body. @@ -21346,7 +21357,21 @@ void ex_function(exarg_T *eap) fp->uf_refcount = 1; fp->uf_args = newargs; fp->uf_lines = newlines; - fp->uf_scoped = NULL; + if ((flags & FC_CLOSURE) != 0) { + if (current_funccal == NULL) { + emsg_funcname(N_("E932 Closure function should not be at top level: %s"), + name); + goto erret; + } + fp->uf_scoped = current_funccal; + current_funccal->fc_refcount++; + ga_grow(¤t_funccal->fc_funcs, 1); + ((ufunc_T **)current_funccal->fc_funcs.ga_data) + [current_funccal->fc_funcs.ga_len++] = fp; + func_ref(current_funccal->func->uf_name); + } else { + fp->uf_scoped = NULL; + } fp->uf_tml_count = NULL; fp->uf_tml_total = NULL; fp->uf_tml_self = NULL; @@ -21627,12 +21652,18 @@ static void list_func_head(ufunc_T *fp, int indent) MSG_PUTS("..."); } msg_putchar(')'); - if (fp->uf_flags & FC_ABORT) + if (fp->uf_flags & FC_ABORT) { MSG_PUTS(" abort"); - if (fp->uf_flags & FC_RANGE) + } + if (fp->uf_flags & FC_RANGE) { MSG_PUTS(" range"); - if (fp->uf_flags & FC_DICT) + } + if (fp->uf_flags & FC_DICT) { MSG_PUTS(" dict"); + } + if (fp->uf_flags & FC_CLOSURE) { + MSG_PUTS(" closure"); + } msg_clr_eos(); if (p_verbose > 0) last_set_msg(fp->uf_script_ID); @@ -22954,6 +22985,39 @@ static var_flavour_T var_flavour(char_u *varname) } } +/// Search hashitem in parent scope. +hashitem_T *find_hi_in_scoped_ht(char_u *name, char_u **varname, + hashtab_T **pht) +{ + funccall_T *old_current_funccal = current_funccal; + hashtab_T *ht; + hashitem_T *hi = NULL; + + if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) { + return NULL; + } + + // Search in parent scope which is possible to reference from lambda + current_funccal = current_funccal->func->uf_scoped; + while (current_funccal) { + ht = find_var_ht(name, varname); + if (ht != NULL && **varname != NUL) { + hi = hash_find(ht, *varname); + if (!HASHITEM_EMPTY(hi)) { + *pht = ht; + break; + } + } + if (current_funccal == current_funccal->func->uf_scoped) { + break; + } + current_funccal = current_funccal->func->uf_scoped; + } + current_funccal = old_current_funccal; + + return hi; +} + /// Search variable in parent scope. dictitem_T *find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoload) diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim index 8e572bea80..98d8ffab40 100644 --- a/src/nvim/testdir/test_lambda.vim +++ b/src/nvim/testdir/test_lambda.vim @@ -286,3 +286,5 @@ func Test_named_function_closure() endfunc ======= >>>>>>> 42b34811... vim-patch:7.4.2119 +======= +>>>>>>> 789a3319... vim-patch:7.4.2120 diff --git a/src/nvim/version.c b/src/nvim/version.c index 6c617d8080..854c57aac3 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -320,7 +320,7 @@ static int included_patches[] = { 2123, // 2122 NA // 2121, - // 2120, + 2120, 2119, // 2118 NA 2117, |