diff options
author | Michael Ennen <mike.ennen@gmail.com> | 2016-10-26 21:40:40 -0700 |
---|---|---|
committer | James McCoy <jamessan@jamessan.com> | 2016-12-12 10:17:35 -0500 |
commit | e2258598cacebf3c90bbb8e13789194c417d8dad (patch) | |
tree | d6eba9675ade2138b0ff566a50662878c5c8a79e /src/nvim/eval.c | |
parent | 5cf0c99755581f789973a4fa4bb3d95a61a01341 (diff) | |
download | rneovim-e2258598cacebf3c90bbb8e13789194c417d8dad.tar.gz rneovim-e2258598cacebf3c90bbb8e13789194c417d8dad.tar.bz2 rneovim-e2258598cacebf3c90bbb8e13789194c417d8dad.zip |
vim-patch:7.4.1582
Problem: Get E923 when using function(dict.func, [], dict). (Kent Sibilev)
Storing a function with a dict in a variable drops the dict if the
function is script-local.
Solution: Translate the function name. Use dict arg if present.
https://github.com/vim/vim/commit/6f2e4b36c9d9908e1cace2b1b96e2c154a837bc2
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 154 |
1 files changed, 87 insertions, 67 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5cd59157e9..157075eb81 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -170,8 +170,6 @@ static char *e_letwrong = N_("E734: Wrong variable type for %s="); static char *e_nofunc = N_("E130: Unknown function: %s"); static char *e_illvar = N_("E461: Illegal variable name: %s"); static char *e_float_as_string = N_("E806: using Float as a String"); -static char *e_dict_both = N_("E924: can't have both a \"self\" dict and " - "a partial: %s"); static char_u * const empty_string = (char_u *)""; static char_u * const namespace_char = (char_u *)"abglstvw"; @@ -6933,12 +6931,65 @@ get_func_tv ( return ret; } +#define ERROR_UNKNOWN 0 +#define ERROR_TOOMANY 1 +#define ERROR_TOOFEW 2 +#define ERROR_SCRIPT 3 +#define ERROR_DICT 4 +#define ERROR_NONE 5 +#define ERROR_OTHER 6 +#define ERROR_BOTH 7 +#define FLEN_FIXED 40 -/* - * Call a function with its resolved parameters - * Return FAIL when the function can't be called, OK otherwise. - * Also returns OK when an error was encountered while executing the function. - */ +/// In a script change <SID>name() and s:name() to K_SNR 123_name(). +/// Change <SNR>123_name() to K_SNR 123_name(). +/// Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory +/// (slow). +static char_u * +fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { + int llen; + char_u *fname; + int i; + + llen = eval_fname_script(name); + if (llen > 0) { + fname_buf[0] = K_SPECIAL; + fname_buf[1] = KS_EXTRA; + fname_buf[2] = (int)KE_SNR; + i = 3; + if (eval_fname_sid(name)) { // "<SID>" or "s:" + if (current_SID <= 0) { + *error = ERROR_SCRIPT; + } else { + vim_snprintf((char *)fname_buf + 3, ARRAY_SIZE(fname_buf) - 3, + "%" PRId64 "_", (int64_t)current_SID); + i = (int)STRLEN(fname_buf); + } + } + + if (i + STRLEN(name + llen) < FLEN_FIXED) { + STRCPY(fname_buf + i, name + llen); + fname = fname_buf; + } else { + fname = xmalloc((unsigned)(i + STRLEN(name + llen) + 1)); + if (fname == NULL) { + *error = ERROR_OTHER; + } else { + *tofree = fname; + memmove(fname, fname_buf, (size_t)i); + STRCPY(fname + i, name + llen); + } + } + } else { + fname = name; + } + + return fname; +} + +/// Call a function with its resolved parameters +/// Return FAIL when the function can't be called, OK otherwise. +/// Also returns OK when an error was encountered while executing the function. int call_func( char_u *funcname, // name of the function @@ -6956,21 +7007,12 @@ call_func( ) { int ret = FAIL; -#define ERROR_UNKNOWN 0 -#define ERROR_TOOMANY 1 -#define ERROR_TOOFEW 2 -#define ERROR_SCRIPT 3 -#define ERROR_DICT 4 -#define ERROR_NONE 5 -#define ERROR_OTHER 6 -#define ERROR_BOTH 7 int error = ERROR_NONE; - int llen; ufunc_T *fp; -#define FLEN_FIXED 40 char_u fname_buf[FLEN_FIXED + 1]; - char_u *fname; - char_u *name; + char_u *tofree = NULL; + char_u *fname; + char_u *name; int argcount = argcount_in; typval_T *argvars = argvars_in; dict_T *selfdict = selfdict_in; @@ -6980,44 +7022,20 @@ call_func( // Make a copy of the name, if it comes from a funcref variable it could // be changed or deleted in the called function. name = vim_strnsave(funcname, len); + if (name == NULL) { + return ret; + } - /* - * In a script change <SID>name() and s:name() to K_SNR 123_name(). - * Change <SNR>123_name() to K_SNR 123_name(). - * Use fname_buf[] when it fits, otherwise allocate memory (slow). - */ - llen = eval_fname_script(name); - if (llen > 0) { - fname_buf[0] = K_SPECIAL; - fname_buf[1] = KS_EXTRA; - fname_buf[2] = (int)KE_SNR; - int i = 3; - if (eval_fname_sid(name)) { // "<SID>" or "s:" - if (current_SID <= 0) { - error = ERROR_SCRIPT; - } else { - vim_snprintf((char *)fname_buf + 3, ARRAY_SIZE(fname_buf) - 3, - "%" PRId64 "_", (int64_t)current_SID); - i = (int)STRLEN(fname_buf); - } - } - if (i + STRLEN(name + llen) < FLEN_FIXED) { - STRCPY(fname_buf + i, name + llen); - fname = fname_buf; - } else { - fname = xmalloc(i + STRLEN(name + llen) + 1); - memmove(fname, fname_buf, (size_t)i); - STRCPY(fname + i, name + llen); - } - } else - fname = name; + fname = fname_trans_sid(name, fname_buf, &tofree, &error); *doesrange = FALSE; if (partial != NULL) { if (partial->pt_dict != NULL) { - if (selfdict_in != NULL) { - error = ERROR_BOTH; + // When the function has a partial with a dict and there is a dict + // argument, use the dict argument. That is backwards compatible. + if (selfdict_in == NULL) { + selfdict = partial->pt_dict; } selfdict = partial->pt_dict; } @@ -7138,18 +7156,13 @@ call_func( emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name); break; - case ERROR_BOTH: - emsg_funcname(N_(e_dict_both), name); - break; } } while (argv_clear > 0) { clear_tv(&argv[--argv_clear]); } - if (fname != name && fname != fname_buf) { - xfree(fname); - } + xfree(tofree); xfree(name); return ret; @@ -9505,11 +9518,6 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr) xfree(name); return; } - if (argvars[0].v_type == VAR_PARTIAL) { - EMSG2(_(e_dict_both), name); - xfree(name); - return; - } if (argvars[dict_idx].vval.v_dict == NULL) { dict_idx = 0; } @@ -9548,11 +9556,13 @@ static void f_function(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - if (argvars[0].v_type == VAR_PARTIAL) { - pt->pt_dict = argvars[0].vval.v_partial->pt_dict; + // For "function(dict.func, [], dict)" and "func" is a partial + // use "dict". That is backwards compatible. + if (dict_idx > 0) { + pt->pt_dict = argvars[dict_idx].vval.v_dict; (pt->pt_dict->dv_refcount)++; - } else if (dict_idx > 0) { - pt->pt_dict = argvars[dict_idx].vval.v_dict; + } else if (argvars[0].v_type == VAR_PARTIAL) { + pt->pt_dict = argvars[0].vval.v_partial->pt_dict; (pt->pt_dict->dv_refcount)++; } @@ -18350,7 +18360,17 @@ handle_subscript ( } if (rettv->v_type == VAR_FUNC && selfdict != NULL) { - ufunc_T *fp = find_func(rettv->vval.v_string); + char_u *fname; + char_u *tofree = NULL; + ufunc_T *fp; + char_u fname_buf[FLEN_FIXED + 1]; + int error; + + // Translate "s:func" to the stored function name. + fname = fname_trans_sid(rettv->vval.v_string, fname_buf, &tofree, &error); + + fp = find_func(fname); + xfree(tofree); // Turn "dict.Func" into a partial for "Func" with "dict". if (fp != NULL && (fp->uf_flags & FC_DICT)) { |