Merge remote-tracking branch 'vim/master'

This commit is contained in:
Kazuki Sakamoto
2016-03-16 18:39:30 -07:00
5 changed files with 185 additions and 104 deletions
+135 -100
View File
@@ -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"
@@ -867,7 +866,7 @@ static int valid_varname(char_u *varname);
static int tv_check_lock(int lock, char_u *name, int use_gettext);
static int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
static char_u *find_option_end(char_u **arg, int *opt_flags);
static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd);
static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial);
static int eval_fname_script(char_u *p);
static int eval_fname_sid(char_u *p);
static void list_func_head(ufunc_T *fp, int indent);
@@ -3476,7 +3475,7 @@ ex_call(exarg_T *eap)
return;
}
tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
if (fudi.fd_newkey != NULL)
{
/* Still need to give an error message for missing key. */
@@ -3491,9 +3490,18 @@ ex_call(exarg_T *eap)
if (fudi.fd_dict != NULL)
++fudi.fd_dict->dv_refcount;
/* If it is the name of a variable of type VAR_FUNC use its contents. */
/* If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
* contents. For VAR_PARTIAL get its partial, unless we already have one
* from trans_function_name(). */
len = (int)STRLEN(tofree);
name = deref_func_name(tofree, &len, &partial, FALSE);
name = deref_func_name(tofree, &len,
partial != NULL ? NULL : &partial, FALSE);
/* When calling fdict.func(), where "func" is a partial, use "fdict"
* instead of the dict in the partial, for backwards compatibility.
* TODO: Do use the arguments in the partial? */
if (fudi.fd_dict != NULL)
partial = NULL;
/* Skip white space to allow ":call func ()". Not good, but required for
* backward compatibility. */
@@ -8561,15 +8569,17 @@ find_internal_func(
/*
* Check if "name" is a variable of type VAR_FUNC. If so, return the function
* name it contains, otherwise return "name".
* If "name" is of type VAR_PARTIAL also return "partial"
* If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set
* "partialp".
*/
static char_u *
deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload)
{
dictitem_T *v;
int cc;
*partial = NULL;
if (partialp != NULL)
*partialp = NULL;
cc = name[*lenp];
name[*lenp] = NUL;
@@ -8588,14 +8598,17 @@ deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload)
if (v != NULL && v->di_tv.v_type == VAR_PARTIAL)
{
*partial = v->di_tv.vval.v_partial;
if (*partial == NULL)
partial_T *pt = v->di_tv.vval.v_partial;
if (pt == NULL)
{
*lenp = 0;
return (char_u *)""; /* just in case */
}
*lenp = (int)STRLEN((*partial)->pt_name);
return (*partial)->pt_name;
if (partialp != NULL)
*partialp = pt;
*lenp = (int)STRLEN(pt->pt_name);
return pt->pt_name;
}
return name;
@@ -8664,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
@@ -8686,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;
@@ -8714,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;
@@ -8762,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)
{
@@ -8920,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;
@@ -11862,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;
}
@@ -11911,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;
@@ -21727,17 +21746,33 @@ handle_subscript(
if (rettv->v_type == VAR_FUNC && selfdict != NULL)
{
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
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 (pt != NULL)
if (fp != NULL && (fp->uf_flags & FC_DICT))
{
pt->pt_dict = selfdict;
selfdict = NULL;
pt->pt_name = rettv->vval.v_string;
func_ref(pt->pt_name);
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = pt;
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
if (pt != NULL)
{
pt->pt_refcount = 1;
pt->pt_dict = selfdict;
selfdict = NULL;
pt->pt_name = rettv->vval.v_string;
func_ref(pt->pt_name);
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = pt;
}
}
}
@@ -23246,7 +23281,7 @@ ex_function(exarg_T *eap)
* g:func global function name, same as "func"
*/
p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi);
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
paren = (vim_strchr(p, '(') != NULL);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
{
@@ -23559,7 +23594,7 @@ ex_function(exarg_T *eap)
if (*p == '!')
p = skipwhite(p + 1);
p += eval_fname_script(p);
vim_free(trans_function_name(&p, TRUE, 0, NULL));
vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL));
if (*skipwhite(p) == '(')
{
++nesting;
@@ -23814,7 +23849,8 @@ trans_function_name(
char_u **pp,
int skip, /* only find the end, don't evaluate */
int flags,
funcdict_T *fdp) /* return: info about dictionary used */
funcdict_T *fdp, /* return: info about dictionary used */
partial_T **partial) /* return: partial of a FuncRef */
{
char_u *name = NULL;
char_u *start;
@@ -23823,7 +23859,6 @@ trans_function_name(
char_u sid_buf[20];
int len;
lval_T lv;
partial_T *partial;
if (fdp != NULL)
vim_memset(fdp, 0, sizeof(funcdict_T));
@@ -23908,7 +23943,7 @@ trans_function_name(
if (lv.ll_exp_name != NULL)
{
len = (int)STRLEN(lv.ll_exp_name);
name = deref_func_name(lv.ll_exp_name, &len, &partial,
name = deref_func_name(lv.ll_exp_name, &len, partial,
flags & TFN_NO_AUTOLOAD);
if (name == lv.ll_exp_name)
name = NULL;
@@ -23916,7 +23951,7 @@ trans_function_name(
else
{
len = (int)(end - *pp);
name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD);
name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD);
if (name == *pp)
name = NULL;
}
@@ -24141,7 +24176,7 @@ function_exists(char_u *name)
int n = FALSE;
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET|TFN_NO_AUTOLOAD,
NULL);
NULL, NULL);
nm = skipwhite(nm);
/* Only accept "funcname", "funcname ", "funcname (..." and
@@ -24158,7 +24193,7 @@ get_expanded_name(char_u *name, int check)
char_u *nm = name;
char_u *p;
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL);
p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL);
if (p != NULL && *nm == NUL)
if (!check || translated_function_exists(p))
@@ -24514,7 +24549,7 @@ ex_delfunction(exarg_T *eap)
funcdict_T fudi;
p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi);
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
vim_free(fudi.fd_newkey);
if (name == NULL)
{
+1 -1
View File
@@ -1179,7 +1179,7 @@ check_due_timer()
{
timer_T *timer;
long this_due;
long next_due;
long next_due = -1;
proftime_T now;
int did_one = FALSE;
# ifdef WIN3264
+1 -1
View File
@@ -44,7 +44,7 @@ NONE 2999
{'33': 999}
len: 3
again: 3
Vim(call):E725:
xxx3
g:dict.func-4
a:function('3')
Vim(let):E698:
+40 -2
View File
@@ -16,6 +16,8 @@ endfunc
func Test_partial_args()
let Cb = function('MyFunc', ["foo", "bar"])
call Cb("zzz")
call assert_equal("foo/bar/xxx", Cb("xxx"))
call assert_equal("foo/bar/yyy", call(Cb, ["yyy"]))
@@ -49,6 +51,9 @@ func Test_partial_dict()
let Cb = function('MyDictFunc', dict)
call assert_equal("hello/xxx/yyy", Cb("xxx", "yyy"))
call assert_fails('Cb("fff")', 'E492:')
let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
call assert_equal("Hello", dict.tr())
endfunc
func Test_partial_implicit()
@@ -65,6 +70,39 @@ func Test_partial_implicit()
let Func = function(dict.MyFunc, ['bbb'])
call assert_equal('foo/bbb', Func())
call assert_fails('call function(dict.MyFunc, ["bbb"], dict)', 'E924:')
endfunc
fun InnerCall(funcref)
return a:funcref
endfu
fun OuterCall()
let opt = { 'func' : function('sin') }
call InnerCall(opt.func)
endfu
func Test_function_in_dict()
call OuterCall()
endfunc
function! s:cache_clear() dict
return self.name
endfunction
func Test_script_function_in_dict()
let s:obj = {'name': 'foo'}
let s:obj2 = {'name': 'bar'}
let s:obj['clear'] = function('s:cache_clear')
call assert_equal('foo', s:obj.clear())
let F = s:obj.clear
call assert_equal('foo', F())
call assert_equal('foo', call(s:obj.clear, [], s:obj))
call assert_equal('bar', call(s:obj.clear, [], s:obj2))
let s:obj2['clear'] = function('s:cache_clear')
call assert_equal('bar', s:obj2.clear())
let B = s:obj2.clear
call assert_equal('bar', B())
endfunc
+8
View File
@@ -763,6 +763,14 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1583,
/**/
1582,
/**/
1581,
/**/
1580,
/**/
1579,
/**/