To: vim_dev@googlegroups.com Subject: Patch 8.1.1816 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.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) Files: src/eval.c, src/userfunc.c, src/testdir/test_user_func.vim, src/testdir/test_autoload.vim, src/testdir/sautest/autoload/foo.vim *** ../vim-8.1.1815/src/eval.c 2019-08-03 21:58:17.753476626 +0200 --- src/eval.c 2019-08-04 23:03:59.314117093 +0200 *************** *** 4734,4740 **** *arg = skipwhite(*arg); /* Handle following '[', '(' and '.' for expr[expr], expr.name, ! * expr(expr). */ if (ret == OK) ret = handle_subscript(arg, rettv, evaluate, TRUE); --- 4734,4740 ---- *arg = skipwhite(*arg); /* Handle following '[', '(' and '.' for expr[expr], expr.name, ! * expr(expr), expr->name(expr) */ if (ret == OK) ret = handle_subscript(arg, rettv, evaluate, TRUE); *************** *** 4824,4830 **** // Locate the method name. name = *arg; ! for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; ++len) ; if (len == 0) { --- 4824,4830 ---- // Locate the method name. name = *arg; ! for (len = 0; eval_isnamec(name[len]); ++len) ; if (len == 0) { *************** *** 4842,4847 **** --- 4842,4849 ---- } *arg += len; + // TODO: if "name" is a function reference, resolve it. + vim_memset(&funcexe, 0, sizeof(funcexe)); funcexe.evaluate = evaluate; funcexe.basetv = &base; *** ../vim-8.1.1815/src/userfunc.c 2019-08-03 21:58:17.753476626 +0200 --- src/userfunc.c 2019-08-04 22:30:21.439145793 +0200 *************** *** 1495,1501 **** 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 */ int argv_clear = 0; partial_T *partial = funcexe->partial; --- 1495,1502 ---- int argcount = argcount_in; typval_T *argvars = argvars_in; dict_T *selfdict = funcexe->selfdict; ! 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,1563 **** /* * User defined function. */ ! if (funcexe->basetv != NULL) ! // TODO: support User function: base->Method() ! fp = NULL; ! else if (partial != NULL && partial->pt_func != NULL) fp = partial->pt_func; else fp = find_func(rfname); --- 1555,1561 ---- /* * User defined function. */ ! if (partial != NULL && partial->pt_func != NULL) fp = partial->pt_func; else fp = find_func(rfname); *************** *** 1586,1591 **** --- 1584,1599 ---- 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,1619 **** did_save_redo = TRUE; } ++fp->uf_calls; ! call_user_func(fp, argcount, argvars, rettv, funcexe->firstline, funcexe->lastline, (fp->uf_flags & FC_DICT) ? selfdict : NULL); if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) --- 1621,1627 ---- did_save_redo = TRUE; } ++fp->uf_calls; ! 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,1636 **** else if (funcexe->basetv != NULL) { /* ! * Find the method name in the table, call its implementation. */ error = call_internal_method(fname, argcount, argvars, rettv, funcexe->basetv); --- 1638,1645 ---- else if (funcexe->basetv != NULL) { /* ! * 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); *** ../vim-8.1.1815/src/testdir/test_user_func.vim 2019-05-09 21:08:53.764083394 +0200 --- src/testdir/test_user_func.vim 2019-08-04 22:39:19.696363364 +0200 *************** *** 47,53 **** endfunc func Test_user_func() ! let g:FuncRef=function("FuncWithRef") let g:counter = 0 inoremap ( ListItem() inoremap [ ListReset() --- 47,53 ---- endfunc func Test_user_func() ! let g:FuncRef = function("FuncWithRef") let g:counter = 0 inoremap ( ListItem() inoremap [ ListReset() *************** *** 62,67 **** --- 62,75 ---- 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,146 **** --- 152,162 ---- \ .. " 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 *** ../vim-8.1.1815/src/testdir/test_autoload.vim 2017-12-07 22:18:46.000000000 +0100 --- src/testdir/test_autoload.vim 2019-08-04 22:44:15.459095622 +0200 *************** *** 8,13 **** --- 8,15 ---- 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() *** ../vim-8.1.1815/src/testdir/sautest/autoload/foo.vim 2017-12-07 21:44:49.000000000 +0100 --- src/testdir/sautest/autoload/foo.vim 2019-08-04 22:44:34.831034514 +0200 *************** *** 5,7 **** --- 5,11 ---- func foo#bar.echo() let g:called_foo_bar_echo += 1 endfunc + + func foo#addFoo(head) + return a:head .. 'foo' + endfunc *** ../vim-8.1.1815/src/version.c 2019-08-04 21:35:08.035889064 +0200 --- src/version.c 2019-08-04 23:02:06.206648737 +0200 *************** *** 775,776 **** --- 775,778 ---- { /* Add new patch number below this line */ + /**/ + 1816, /**/ -- How To Keep A Healthy Level Of Insanity: 2. Page yourself over the intercom. Don't disguise your voice. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///