mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.4115: cannot use a method with a complex expression
Problem: Cannot use a method with a complex expression. Solution: Evaluate the expression after "->" and use the result.
This commit is contained in:
@@ -3212,4 +3212,6 @@ EXTERN char e_using_autoload_in_script_not_under_autoload_directory[]
|
|||||||
INIT(= N_("E1263: Using autoload in a script not under an autoload directory"));
|
INIT(= N_("E1263: Using autoload in a script not under an autoload directory"));
|
||||||
EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[]
|
EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[]
|
||||||
INIT(= N_("E1264: Autoload import cannot use absolute or relative path: %s"));
|
INIT(= N_("E1264: Autoload import cannot use absolute or relative path: %s"));
|
||||||
|
EXTERN char e_cannot_use_partial_here[]
|
||||||
|
INIT(= N_("E1265: Cannot use a partial here"));
|
||||||
#endif
|
#endif
|
||||||
|
93
src/eval.c
93
src/eval.c
@@ -3948,6 +3948,7 @@ eval_method(
|
|||||||
char_u *name;
|
char_u *name;
|
||||||
long len;
|
long len;
|
||||||
char_u *alias;
|
char_u *alias;
|
||||||
|
char_u *tofree = NULL;
|
||||||
typval_T base = *rettv;
|
typval_T base = *rettv;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
int evaluate = evalarg != NULL
|
int evaluate = evalarg != NULL
|
||||||
@@ -3968,67 +3969,68 @@ eval_method(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (**arg == '.')
|
char_u *paren;
|
||||||
{
|
|
||||||
int len2;
|
|
||||||
char_u *fname;
|
|
||||||
int idx;
|
|
||||||
imported_T *import = find_imported(name, len, TRUE,
|
|
||||||
evalarg == NULL ? NULL : evalarg->eval_cctx);
|
|
||||||
type_T *type;
|
|
||||||
|
|
||||||
// value->import.func()
|
// If there is no "(" immediately following, but there is further on,
|
||||||
if (import != NULL)
|
// it can be "import.Func()", "dict.Func()", "list[nr]", etc.
|
||||||
|
// Does not handle anything where "(" is part of the expression.
|
||||||
|
*arg = skipwhite(*arg);
|
||||||
|
|
||||||
|
if (**arg != '(' && alias == NULL
|
||||||
|
&& (paren = vim_strchr(*arg, '(')) != NULL)
|
||||||
{
|
{
|
||||||
name = NULL;
|
typval_T ref;
|
||||||
++*arg;
|
|
||||||
fname = *arg;
|
*arg = name;
|
||||||
len2 = get_name_len(arg, &alias, evaluate, TRUE);
|
*paren = NUL;
|
||||||
if (len2 <= 0)
|
ref.v_type = VAR_UNKNOWN;
|
||||||
|
if (eval7(arg, &ref, evalarg, FALSE) == FAIL)
|
||||||
{
|
{
|
||||||
if (verbose)
|
*arg = name + len;
|
||||||
emsg(_(e_missing_name_after_dot));
|
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
}
|
}
|
||||||
else if (evaluate)
|
else if (*skipwhite(*arg) != NUL)
|
||||||
{
|
{
|
||||||
int cc = fname[len2];
|
if (verbose)
|
||||||
ufunc_T *ufunc;
|
semsg(_(e_trailing_characters_str), *arg);
|
||||||
|
ret = FAIL;
|
||||||
fname[len2] = NUL;
|
}
|
||||||
idx = find_exported(import->imp_sid, fname, &ufunc, &type,
|
else if (ref.v_type == VAR_FUNC && ref.vval.v_string != NULL)
|
||||||
evalarg->eval_cctx, verbose);
|
|
||||||
fname[len2] = cc;
|
|
||||||
|
|
||||||
if (idx >= 0)
|
|
||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
|
name = ref.vval.v_string;
|
||||||
svar_T *sv =
|
ref.vval.v_string = NULL;
|
||||||
((svar_T *)si->sn_var_vals.ga_data) + idx;
|
tofree = name;
|
||||||
|
|
||||||
if (sv->sv_tv->v_type == VAR_FUNC
|
|
||||||
&& sv->sv_tv->vval.v_string != NULL)
|
|
||||||
{
|
|
||||||
name = sv->sv_tv->vval.v_string;
|
|
||||||
len = STRLEN(name);
|
len = STRLEN(name);
|
||||||
}
|
}
|
||||||
|
else if (ref.v_type == VAR_PARTIAL && ref.vval.v_partial != NULL)
|
||||||
|
{
|
||||||
|
if (ref.vval.v_partial->pt_argc > 0
|
||||||
|
|| ref.vval.v_partial->pt_dict != NULL)
|
||||||
|
{
|
||||||
|
emsg(_(e_cannot_use_partial_here));
|
||||||
|
ret = FAIL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: how about a partial?
|
name = vim_strsave(partial_name(ref.vval.v_partial));
|
||||||
if (verbose)
|
tofree = name;
|
||||||
semsg(_(e_not_callable_type_str), fname);
|
if (name == NULL)
|
||||||
ret = FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ufunc != NULL)
|
|
||||||
{
|
{
|
||||||
name = ufunc->uf_name;
|
ret = FAIL;
|
||||||
len = STRLEN(name);
|
name = *arg;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
len = STRLEN(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
semsg(_(e_not_callable_type_str), name);
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
}
|
}
|
||||||
}
|
clear_tv(&ref);
|
||||||
|
*paren = '(';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == OK)
|
if (ret == OK)
|
||||||
@@ -4057,6 +4059,7 @@ eval_method(
|
|||||||
// evaluating the arguments is possible (see test55).
|
// evaluating the arguments is possible (see test55).
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
clear_tv(&base);
|
clear_tv(&base);
|
||||||
|
vim_free(tofree);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@@ -3136,16 +3136,37 @@ def Test_expr7_method_call()
|
|||||||
var sorted = [3, 1, 2]
|
var sorted = [3, 1, 2]
|
||||||
-> sort()
|
-> sort()
|
||||||
assert_equal([1, 2, 3], sorted)
|
assert_equal([1, 2, 3], sorted)
|
||||||
|
END
|
||||||
|
CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
def SetNumber(n: number)
|
def SetNumber(n: number)
|
||||||
g:number = n
|
g:number = n
|
||||||
enddef
|
enddef
|
||||||
const Setit = SetNumber
|
const Setit = SetNumber
|
||||||
len('text')->Setit()
|
len('text')->Setit()
|
||||||
assert_equal(4, g:number)
|
assert_equal(4, g:number)
|
||||||
|
|
||||||
|
const SetFuncref = funcref(SetNumber)
|
||||||
|
len('longer')->SetFuncref()
|
||||||
|
assert_equal(6, g:number)
|
||||||
|
|
||||||
|
const SetList = [SetNumber, SetFuncref]
|
||||||
|
len('xx')->SetList[0]()
|
||||||
|
assert_equal(2, g:number)
|
||||||
|
len('xxx')->SetList[1]()
|
||||||
|
assert_equal(3, g:number)
|
||||||
|
|
||||||
|
const SetDict = {key: SetNumber}
|
||||||
|
len('xxxx')->SetDict['key']()
|
||||||
|
assert_equal(4, g:number)
|
||||||
|
len('xxxxx')->SetDict.key()
|
||||||
|
assert_equal(5, g:number)
|
||||||
|
|
||||||
unlet g:number
|
unlet g:number
|
||||||
END
|
END
|
||||||
CheckDefAndScriptSuccess(lines)
|
CheckScriptSuccess(lines) # TODO: CheckDefAndScriptSuccess()
|
||||||
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
def RetVoid()
|
def RetVoid()
|
||||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
4115,
|
||||||
/**/
|
/**/
|
||||||
4114,
|
4114,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user