Patch 8.2.1167
Problem:    Vim9: builtin function method call only supports first argument.
Solution:   Shift arguments when needed. (closes #6305, closes #6419)
Files:      src/evalfunc.c, src/vim9compile.c, src/vim9execute.c,
            src/vim9.h, src/testdir/test_vim9_expr.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.1166/src/evalfunc.c      2020-07-05 21:10:20.869634742 +0200
--- src/evalfunc.c      2020-07-09 21:09:50.158780775 +0200
***************
*** 465,472 ****
      {"acos",          1, 1, FEARG_1,    ret_float,    FLOAT_FUNC(f_acos)},
      {"add",           2, 2, FEARG_1,    ret_first_arg, f_add},
      {"and",           2, 2, FEARG_1,    ret_number,   f_and},
!     {"append",                2, 2, FEARG_LAST, ret_number,   f_append},
!     {"appendbufline", 3, 3, FEARG_LAST, ret_number,   f_appendbufline},
      {"argc",          0, 1, 0,          ret_number,   f_argc},
      {"argidx",                0, 0, 0,          ret_number,   f_argidx},
      {"arglistid",     0, 2, 0,          ret_number,   f_arglistid},
--- 465,472 ----
      {"acos",          1, 1, FEARG_1,    ret_float,    FLOAT_FUNC(f_acos)},
      {"add",           2, 2, FEARG_1,    ret_first_arg, f_add},
      {"and",           2, 2, FEARG_1,    ret_number,   f_and},
!     {"append",                2, 2, FEARG_2,    ret_number,   f_append},
!     {"appendbufline", 3, 3, FEARG_2,    ret_number,   f_appendbufline},
      {"argc",          0, 1, 0,          ret_number,   f_argc},
      {"argidx",                0, 0, 0,          ret_number,   f_argidx},
      {"arglistid",     0, 2, 0,          ret_number,   f_arglistid},
***************
*** 1191,1197 ****
  
  /*
   * Check the argument count to use for internal function "idx".
!  * Returns OK or FAIL;
   */
      int
  check_internal_func(int idx, int argcount)
--- 1191,1199 ----
  
  /*
   * Check the argument count to use for internal function "idx".
!  * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
!  * first argument, 2 if method base is second argument, etc.  9 if method base
!  * is last argument.
   */
      int
  check_internal_func(int idx, int argcount)
***************
*** 1204,1217 ****
      else if (argcount > global_functions[idx].f_max_argc)
        res = FCERR_TOOMANY;
      else
!       return OK;
  
      name = internal_func_name(idx);
      if (res == FCERR_TOOMANY)
        semsg(_(e_toomanyarg), name);
      else
        semsg(_(e_toofewarg), name);
!     return FAIL;
  }
  
      int
--- 1206,1219 ----
      else if (argcount > global_functions[idx].f_max_argc)
        res = FCERR_TOOMANY;
      else
!       return global_functions[idx].f_argtype;
  
      name = internal_func_name(idx);
      if (res == FCERR_TOOMANY)
        semsg(_(e_toomanyarg), name);
      else
        semsg(_(e_toofewarg), name);
!     return -1;
  }
  
      int
*** ../vim-8.2.1166/src/vim9compile.c   2020-07-08 22:01:43.792114669 +0200
--- src/vim9compile.c   2020-07-09 20:14:15.274276474 +0200
***************
*** 1445,1464 ****
  
  /*
   * Generate an ISN_BCALL instruction.
   * Return FAIL if the number of arguments is wrong.
   */
      static int
! generate_BCALL(cctx_T *cctx, int func_idx, int argcount)
  {
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
      type_T    *argtypes[MAX_FUNC_ARGS];
      int               i;
  
      RETURN_OK_IF_SKIP(cctx);
!     if (check_internal_func(func_idx, argcount) == FAIL)
        return FAIL;
  
      if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
        return FAIL;
      isn->isn_arg.bfunc.cbf_idx = func_idx;
--- 1445,1475 ----
  
  /*
   * Generate an ISN_BCALL instruction.
+  * "method_call" is TRUE for "value->method()"
   * Return FAIL if the number of arguments is wrong.
   */
      static int
! generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
  {
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
+     int               argoff;
      type_T    *argtypes[MAX_FUNC_ARGS];
      int               i;
  
      RETURN_OK_IF_SKIP(cctx);
!     argoff = check_internal_func(func_idx, argcount);
!     if (argoff < 0)
        return FAIL;
  
+     if (method_call && argoff > 1)
+     {
+       if ((isn = generate_instr(cctx, ISN_SHUFFLE)) == NULL)
+           return FAIL;
+       isn->isn_arg.shuffle.shfl_item = argcount;
+       isn->isn_arg.shuffle.shfl_up = argoff - 1;
+     }
+ 
      if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
        return FAIL;
      isn->isn_arg.bfunc.cbf_idx = func_idx;
***************
*** 2930,2936 ****
        // builtin function
        idx = find_internal_func(name);
        if (idx >= 0)
!           res = generate_BCALL(cctx, idx, argcount);
        else
            semsg(_(e_unknownfunc), namebuf);
        goto theend;
--- 2941,2947 ----
        // builtin function
        idx = find_internal_func(name);
        if (idx >= 0)
!           res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
        else
            semsg(_(e_unknownfunc), namebuf);
        goto theend;
***************
*** 7397,7402 ****
--- 7408,7414 ----
        case ISN_COMPARESTRING:
        case ISN_CONCAT:
        case ISN_DCALL:
+       case ISN_SHUFFLE:
        case ISN_DROP:
        case ISN_ECHO:
        case ISN_ECHOERR:
*** ../vim-8.2.1166/src/vim9execute.c   2020-07-08 15:16:15.534128895 +0200
--- src/vim9execute.c   2020-07-09 20:33:20.619153675 +0200
***************
*** 554,560 ****
  
        if (func_idx < 0)
            return FAIL;
!       if (check_internal_func(func_idx, argcount) == FAIL)
            return FAIL;
        return call_bfunc(func_idx, argcount, ectx);
      }
--- 554,560 ----
  
        if (func_idx < 0)
            return FAIL;
!       if (check_internal_func(func_idx, argcount) < 0)
            return FAIL;
        return call_bfunc(func_idx, argcount, ectx);
      }
***************
*** 2333,2338 ****
--- 2333,2354 ----
                }
                break;
  
+           case ISN_SHUFFLE:
+               {
+                   typval_T        tmp_tv;
+                   int             item = iptr->isn_arg.shuffle.shfl_item;
+                   int             up = iptr->isn_arg.shuffle.shfl_up;
+ 
+                   tmp_tv = *STACK_TV_BOT(-item);
+                   for ( ; up > 0 && item > 1; --up)
+                   {
+                       *STACK_TV_BOT(-item) = *STACK_TV_BOT(-item + 1);
+                       --item;
+                   }
+                   *STACK_TV_BOT(-item) = tmp_tv;
+               }
+               break;
+ 
            case ISN_DROP:
                --ectx.ec_stack.ga_len;
                clear_tv(STACK_TV_BOT(0));
***************
*** 2900,2907 ****
                            break;
            case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
                                         (long long)(iptr->isn_arg.number));
!                               break;
  
            case ISN_DROP: smsg("%4d DROP", current); break;
        }
      }
--- 2916,2927 ----
                            break;
            case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
                                         (long long)(iptr->isn_arg.number));
!                             break;
  
+           case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
+                                        iptr->isn_arg.shuffle.shfl_item,
+                                        iptr->isn_arg.shuffle.shfl_up);
+                             break;
            case ISN_DROP: smsg("%4d DROP", current); break;
        }
      }
*** ../vim-8.2.1166/src/vim9.h  2020-06-16 11:34:38.314223444 +0200
--- src/vim9.h  2020-07-09 20:09:04.187467831 +0200
***************
*** 124,129 ****
--- 124,130 ----
      ISN_CHECKTYPE,  // check value type is isn_arg.type.tc_type
      ISN_CHECKLEN,   // check list length is isn_arg.checklen.cl_min_len
  
+     ISN_SHUFFLE,    // move item on stack up or down
      ISN_DROP      // pop stack and discard value
  } isntype_T;
  
***************
*** 237,242 ****
--- 238,249 ----
      int               cl_more_OK;     // longer is allowed
  } checklen_T;
  
+ // arguments to ISN_SHUFFLE
+ typedef struct {
+     int               shfl_item;      // item to move (relative to top of 
stack)
+     int               shfl_up;        // places to move upwards
+ } shuffle_T;
+ 
  /*
   * Instruction
   */
***************
*** 270,275 ****
--- 277,283 ----
        unlet_T             unlet;
        funcref_T           funcref;
        checklen_T          checklen;
+       shuffle_T           shuffle;
      } isn_arg;
  };
  
*** ../vim-8.2.1166/src/testdir/test_vim9_expr.vim      2020-07-08 
18:38:05.649287913 +0200
--- src/testdir/test_vim9_expr.vim      2020-07-09 20:55:14.582176180 +0200
***************
*** 1411,1416 ****
--- 1411,1438 ----
        one)
  enddef
  
+ def Test_expr7_method_call()
+   new
+   setline(1, ['first', 'last'])
+   eval 'second'->append(1)
+   assert_equal(['first', 'second', 'last'], getline(1, '$'))
+   bwipe!
+ 
+   let bufnr = bufnr()
+   let loclist = [#{bufnr: bufnr, lnum: 42, col: 17, text: 'wrong'}]
+   loclist->setloclist(0)
+   assert_equal([#{bufnr: bufnr,
+               lnum: 42,
+               col: 17,
+               text: 'wrong',
+               pattern: '',
+               valid: 1,
+               vcol: 0,
+               nr: 0,
+               type: '',
+               module: ''}
+               ], getloclist(0))
+ enddef
  
  func Test_expr7_trailing_fails()
    call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107')
*** ../vim-8.2.1166/src/testdir/test_vim9_disassemble.vim       2020-07-05 
21:38:07.857431843 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-07-09 21:10:44.178562748 
+0200
***************
*** 1278,1281 ****
--- 1278,1299 ----
          res)
  enddef
  
+ def s:CallAppend()
+   eval "some text"->append(2)
+ enddef
+ 
+ def Test_shuffle()
+   let res = execute('disass s:CallAppend')
+   assert_match('<SNR>\d*_CallAppend\_s*' ..
+         'eval "some text"->append(2)\_s*' ..
+         '\d PUSHS "some text"\_s*' ..
+         '\d PUSHNR 2\_s*' ..
+         '\d SHUFFLE 2 up 1\_s*' ..
+         '\d BCALL append(argc 2)\_s*' ..
+         '\d DROP\_s*' ..
+         '\d PUSHNR 0\_s*' ..
+         '\d RETURN',
+         res)
+ enddef
+ 
  " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
*** ../vim-8.2.1166/src/version.c       2020-07-09 19:16:31.378955705 +0200
--- src/version.c       2020-07-09 20:22:22.673416291 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1167,
  /**/

-- 
If someone questions your market projections, simply point out that your
target market is "People who are nuts" and "People who will buy any damn
thing".  Nobody is going to tell you there aren't enough of those people
to go around.
                                (Scott Adams - The Dilbert principle)

 /// 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/202007091921.069JLGma1719612%40masaka.moolenaar.net.

Raspunde prin e-mail lui