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,  | 
