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 <expr> ( ListItem()
    inoremap <expr> [ ListReset()
--- 47,53 ----
  endfunc
  
  func Test_user_func()
!   let g:FuncRef = function("FuncWithRef")
    let g:counter = 0
    inoremap <expr> ( ListItem()
    inoremap <expr> [ 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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201908042105.x74L5KQh017930%40masaka.moolenaar.net.

Raspunde prin e-mail lui