summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-08-04 23:04:39 +0200
committerBram Moolenaar <Bram@vim.org>2019-08-04 23:04:39 +0200
commitfcfe1a9b8950b8b211ab3b24d84b17c6847ea43f (patch)
treedaeeffb4dd96cdd7744597d9623d222404edd8e2 /src
parent7a4ea1df2f85e00286c49db1145e3a38b35557f4 (diff)
downloadvim-git-fcfe1a9b8950b8b211ab3b24d84b17c6847ea43f.tar.gz
patch 8.1.1816: cannot use a user defined function as a methodv8.1.1816
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)
Diffstat (limited to 'src')
-rw-r--r--src/eval.c6
-rw-r--r--src/testdir/sautest/autoload/foo.vim4
-rw-r--r--src/testdir/test_autoload.vim2
-rw-r--r--src/testdir/test_user_func.vim18
-rw-r--r--src/userfunc.c23
-rw-r--r--src/version.c2
6 files changed, 45 insertions, 10 deletions
diff --git a/src/eval.c b/src/eval.c
index 7875edeaf..16ced4060 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -4734,7 +4734,7 @@ 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(arg, rettv, evaluate, TRUE);
@@ -4824,7 +4824,7 @@ eval_method(
// Locate the method name.
name = *arg;
- for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; ++len)
+ for (len = 0; eval_isnamec(name[len]); ++len)
;
if (len == 0)
{
@@ -4842,6 +4842,8 @@ eval_method(
}
*arg += len;
+ // TODO: if "name" is a function reference, resolve it.
+
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.evaluate = evaluate;
funcexe.basetv = &base;
diff --git a/src/testdir/sautest/autoload/foo.vim b/src/testdir/sautest/autoload/foo.vim
index d7dcd5ce3..298e7275d 100644
--- a/src/testdir/sautest/autoload/foo.vim
+++ b/src/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/testdir/test_autoload.vim b/src/testdir/test_autoload.vim
index 7396c227c..b8c4fa251 100644
--- a/src/testdir/test_autoload.vim
+++ b/src/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/testdir/test_user_func.vim b/src/testdir/test_user_func.vim
index 666c06c13..4b4a2766f 100644
--- a/src/testdir/test_user_func.vim
+++ b/src/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
@@ -144,3 +152,11 @@ func Test_default_arg()
\ .. " endfunction",
\ 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
diff --git a/src/userfunc.c b/src/userfunc.c
index 8e834a3e5..a60919618 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -1495,7 +1495,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;
@@ -1554,10 +1555,7 @@ call_func(
/*
* User defined function.
*/
- if (funcexe->basetv != NULL)
- // TODO: support User function: base->Method()
- fp = NULL;
- else if (partial != NULL && partial->pt_func != NULL)
+ if (partial != NULL && partial->pt_func != NULL)
fp = partial->pt_func;
else
fp = find_func(rfname);
@@ -1586,6 +1584,16 @@ call_func(
argcount = funcexe->argv_func(argcount, argvars,
fp->uf_args.ga_len);
+ if (funcexe->basetv != NULL)
+ {
+ // Method call: base->Method()
+ mch_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;
if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len)
@@ -1613,7 +1621,7 @@ call_func(
did_save_redo = TRUE;
}
++fp->uf_calls;
- call_user_func(fp, argcount, argvars, rettv,
+ call_user_func(fp, argcount, argv, rettv,
funcexe->firstline, funcexe->lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0)
@@ -1630,7 +1638,8 @@ call_func(
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);
diff --git a/src/version.c b/src/version.c
index 43e692a2b..5c806a855 100644
--- a/src/version.c
+++ b/src/version.c
@@ -774,6 +774,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1816,
+/**/
1815,
/**/
1814,