diff options
-rw-r--r-- | src/nvim/eval.c | 6 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 23 | ||||
-rw-r--r-- | src/nvim/testdir/sautest/autoload/foo.vim | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_autoload.vim | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_user_func.vim | 18 |
5 files changed, 43 insertions, 10 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 39e8686580..021a9a75b8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -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; diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index ec43987b07..3c0c0091f2 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -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 { diff --git a/src/nvim/testdir/sautest/autoload/foo.vim b/src/nvim/testdir/sautest/autoload/foo.vim index d7dcd5ce3d..298e7275d8 100644 --- a/src/nvim/testdir/sautest/autoload/foo.vim +++ b/src/nvim/testdir/sautest/autoload/foo.vim @@ -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 diff --git a/src/nvim/testdir/test_autoload.vim b/src/nvim/testdir/test_autoload.vim index 7396c227c9..b8c4fa251f 100644 --- a/src/nvim/testdir/test_autoload.vim +++ b/src/nvim/testdir/test_autoload.vim @@ -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() diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim index 7dcd92a54b..5231ef7b4f 100644 --- a/src/nvim/testdir/test_user_func.vim +++ b/src/nvim/testdir/test_user_func.vim @@ -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 |