To: vim_dev@googlegroups.com Subject: Patch 8.2.1167 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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('\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 -- 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 ///