forked from aniani/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.
This commit is contained in:
161
src/eval.c
161
src/eval.c
@@ -110,7 +110,6 @@ static char *e_illvar = N_("E461: Illegal variable name: %s");
|
||||
#ifdef FEAT_FLOAT
|
||||
static char *e_float_as_string = N_("E806: using Float as a String");
|
||||
#endif
|
||||
static char *e_dict_both = N_("E924: can't have both a \"self\" dict and a partial: %s");
|
||||
|
||||
#define NAMESPACE_CHAR (char_u *)"abglstvw"
|
||||
|
||||
@@ -8678,6 +8677,67 @@ 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 FLEN_FIXED 40
|
||||
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
sprintf((char *)fname_buf + 3, "%ld_", (long)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 = alloc((unsigned)(i + STRLEN(name + llen) + 1));
|
||||
if (fname == NULL)
|
||||
*error = ERROR_OTHER;
|
||||
else
|
||||
{
|
||||
*tofree = fname;
|
||||
mch_memmove(fname, fname_buf, (size_t)i);
|
||||
STRCPY(fname + i, name + llen);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
fname = name;
|
||||
return fname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call a function with its resolved parameters
|
||||
@@ -8700,20 +8760,11 @@ call_func(
|
||||
dict_T *selfdict_in) /* Dictionary for "self" */
|
||||
{
|
||||
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 i;
|
||||
int llen;
|
||||
ufunc_T *fp;
|
||||
#define FLEN_FIXED 40
|
||||
char_u fname_buf[FLEN_FIXED + 1];
|
||||
char_u *tofree = NULL;
|
||||
char_u *fname;
|
||||
char_u *name;
|
||||
int argcount = argcount_in;
|
||||
@@ -8728,47 +8779,7 @@ call_func(
|
||||
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;
|
||||
i = 3;
|
||||
if (eval_fname_sid(name)) /* "<SID>" or "s:" */
|
||||
{
|
||||
if (current_SID <= 0)
|
||||
error = ERROR_SCRIPT;
|
||||
else
|
||||
{
|
||||
sprintf((char *)fname_buf + 3, "%ld_", (long)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 = alloc((unsigned)(i + STRLEN(name + llen) + 1));
|
||||
if (fname == NULL)
|
||||
error = ERROR_OTHER;
|
||||
else
|
||||
{
|
||||
mch_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;
|
||||
|
||||
@@ -8776,9 +8787,11 @@ call_func(
|
||||
{
|
||||
if (partial->pt_dict != NULL)
|
||||
{
|
||||
if (selfdict_in != NULL)
|
||||
error = ERROR_BOTH;
|
||||
selfdict = partial->pt_dict;
|
||||
/* 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;
|
||||
}
|
||||
if (error == ERROR_NONE && partial->pt_argc > 0)
|
||||
{
|
||||
@@ -8934,16 +8947,12 @@ call_func(
|
||||
emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
|
||||
name);
|
||||
break;
|
||||
case ERROR_BOTH:
|
||||
emsg_funcname(e_dict_both, name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (argv_clear > 0)
|
||||
clear_tv(&argv[--argv_clear]);
|
||||
if (fname != name && fname != fname_buf)
|
||||
vim_free(fname);
|
||||
vim_free(tofree);
|
||||
vim_free(name);
|
||||
|
||||
return ret;
|
||||
@@ -11876,12 +11885,6 @@ f_function(typval_T *argvars, typval_T *rettv)
|
||||
vim_free(name);
|
||||
return;
|
||||
}
|
||||
if (argvars[0].v_type == VAR_PARTIAL)
|
||||
{
|
||||
EMSG2(_(e_dict_both), name);
|
||||
vim_free(name);
|
||||
return;
|
||||
}
|
||||
if (argvars[dict_idx].vval.v_dict == NULL)
|
||||
dict_idx = 0;
|
||||
}
|
||||
@@ -11925,16 +11928,18 @@ f_function(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
}
|
||||
|
||||
if (argvars[0].v_type == VAR_PARTIAL)
|
||||
{
|
||||
pt->pt_dict = argvars[0].vval.v_partial->pt_dict;
|
||||
++pt->pt_dict->dv_refcount;
|
||||
}
|
||||
else if (dict_idx > 0)
|
||||
/* 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 (argvars[0].v_type == VAR_PARTIAL)
|
||||
{
|
||||
pt->pt_dict = argvars[0].vval.v_partial->pt_dict;
|
||||
++pt->pt_dict->dv_refcount;
|
||||
}
|
||||
|
||||
pt->pt_refcount = 1;
|
||||
pt->pt_name = name;
|
||||
@@ -21714,7 +21719,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);
|
||||
vim_free(tofree);
|
||||
|
||||
/* Turn "dict.Func" into a partial for "Func" with "dict". */
|
||||
if (fp != NULL && (fp->uf_flags & FC_DICT))
|
||||
|
Reference in New Issue
Block a user