mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.1.1816: cannot use a user defined function as a method
Problem: Cannot use a user defined function as a method.
Solution: Pass the base as the first argument to the user defined function
after "->". (partly by FUJIWARA Takuya)
fcfe1a9b89
This commit is contained in:
parent
aa2dc8b7b4
commit
8d1ca37d1f
@ -4031,7 +4031,7 @@ static int eval7(
|
||||
*arg = skipwhite(*arg);
|
||||
|
||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||
// expr(expr).
|
||||
// expr(expr), expr->name(expr)
|
||||
if (ret == OK) {
|
||||
ret = handle_subscript((const char **)arg, rettv, evaluate, true);
|
||||
}
|
||||
@ -4094,7 +4094,7 @@ static int eval_method(char_u **const arg, typval_T *const rettv,
|
||||
// Locate the method name.
|
||||
const char_u *const name = *arg;
|
||||
size_t len;
|
||||
for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; len++) {
|
||||
for (len = 0; eval_isnamec(name[len]); len++) {
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
@ -4113,6 +4113,8 @@ static int eval_method(char_u **const arg, typval_T *const rettv,
|
||||
}
|
||||
*arg += len;
|
||||
|
||||
// TODO(seandewar): if "name" is a function reference, resolve it.
|
||||
|
||||
typval_T base = *rettv;
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.evaluate = evaluate;
|
||||
|
@ -1447,7 +1447,8 @@ call_func(
|
||||
int argcount = argcount_in;
|
||||
typval_T *argvars = argvars_in;
|
||||
dict_T *selfdict = funcexe->selfdict;
|
||||
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
|
||||
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
|
||||
// "funcexe->basetv" is not NULL
|
||||
int argv_clear = 0;
|
||||
partial_T *partial = funcexe->partial;
|
||||
|
||||
@ -1514,10 +1515,7 @@ call_func(
|
||||
}
|
||||
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
|
||||
// User defined function.
|
||||
if (funcexe->basetv != NULL) {
|
||||
// TODO(seandewar): support User function: base->Method()
|
||||
fp = NULL;
|
||||
} else if (fp == NULL) {
|
||||
if (fp == NULL) {
|
||||
fp = find_func(rfname);
|
||||
}
|
||||
|
||||
@ -1546,6 +1544,16 @@ call_func(
|
||||
argcount = funcexe->argv_func(argcount, argvars, argv_clear,
|
||||
fp->uf_args.ga_len);
|
||||
}
|
||||
|
||||
if (funcexe->basetv != NULL) {
|
||||
// Method call: base->Method()
|
||||
memmove(&argv[1], argvars, sizeof(typval_T) * argcount);
|
||||
argv[0] = *funcexe->basetv;
|
||||
argcount++;
|
||||
} else {
|
||||
memcpy(argv, argvars, sizeof(typval_T) * argcount);
|
||||
}
|
||||
|
||||
if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) {
|
||||
*funcexe->doesrange = true;
|
||||
}
|
||||
@ -1557,14 +1565,15 @@ call_func(
|
||||
error = ERROR_DICT;
|
||||
} else {
|
||||
// Call the user function.
|
||||
call_user_func(fp, argcount, argvars, rettv, funcexe->firstline,
|
||||
call_user_func(fp, argcount, argv, rettv, funcexe->firstline,
|
||||
funcexe->lastline,
|
||||
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
|
||||
error = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
} else if (funcexe->basetv != NULL) {
|
||||
// Find the method name in the table, call its implementation.
|
||||
// expr->method(): Find the method name in the table, call its
|
||||
// implementation with the base as one of the arguments.
|
||||
error = call_internal_method(fname, argcount, argvars, rettv,
|
||||
funcexe->basetv);
|
||||
} else {
|
||||
|
@ -5,3 +5,7 @@ let foo#bar = {}
|
||||
func foo#bar.echo()
|
||||
let g:called_foo_bar_echo += 1
|
||||
endfunc
|
||||
|
||||
func foo#addFoo(head)
|
||||
return a:head .. 'foo'
|
||||
endfunc
|
||||
|
@ -8,6 +8,8 @@ func Test_autoload_dict_func()
|
||||
call g:foo#bar.echo()
|
||||
call assert_equal(1, g:loaded_foo_vim)
|
||||
call assert_equal(1, g:called_foo_bar_echo)
|
||||
|
||||
eval 'bar'->g:foo#addFoo()->assert_equal('barfoo')
|
||||
endfunc
|
||||
|
||||
func Test_source_autoload()
|
||||
|
@ -47,7 +47,7 @@ func FuncWithRef(a)
|
||||
endfunc
|
||||
|
||||
func Test_user_func()
|
||||
let g:FuncRef=function("FuncWithRef")
|
||||
let g:FuncRef = function("FuncWithRef")
|
||||
let g:counter = 0
|
||||
inoremap <expr> ( ListItem()
|
||||
inoremap <expr> [ ListReset()
|
||||
@ -62,6 +62,14 @@ func Test_user_func()
|
||||
call assert_equal(9, g:retval)
|
||||
call assert_equal(333, g:FuncRef(333))
|
||||
|
||||
let g:retval = "nop"
|
||||
call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf"))
|
||||
call assert_equal('fail', 45->Compute(0, "retval"))
|
||||
call assert_equal('nop', g:retval)
|
||||
call assert_equal('ok', 45->Compute(5, "retval"))
|
||||
call assert_equal(9, g:retval)
|
||||
" call assert_equal(333, 333->g:FuncRef())
|
||||
|
||||
enew
|
||||
|
||||
normal oXX+-XX
|
||||
@ -150,6 +158,14 @@ func Test_default_arg()
|
||||
\ execute('func Args2'))
|
||||
endfunc
|
||||
|
||||
func s:addFoo(lead)
|
||||
return a:lead .. 'foo'
|
||||
endfunc
|
||||
|
||||
func Test_user_method()
|
||||
eval 'bar'->s:addFoo()->assert_equal('barfoo')
|
||||
endfunc
|
||||
|
||||
func Test_failed_call_in_try()
|
||||
try | call UnknownFunc() | catch | endtry
|
||||
endfunc
|
||||
|
Loading…
Reference in New Issue
Block a user