forked from aniani/vim
patch 8.2.1167: Vim9: builtin function method call only supports first arg
Problem: Vim9: builtin function method call only supports first argument. Solution: Shift arguments when needed. (closes #6305, closes #6419)
This commit is contained in:
@@ -465,8 +465,8 @@ static funcentry_T global_functions[] =
|
|||||||
{"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
|
{"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
|
||||||
{"add", 2, 2, FEARG_1, ret_first_arg, f_add},
|
{"add", 2, 2, FEARG_1, ret_first_arg, f_add},
|
||||||
{"and", 2, 2, FEARG_1, ret_number, f_and},
|
{"and", 2, 2, FEARG_1, ret_number, f_and},
|
||||||
{"append", 2, 2, FEARG_LAST, ret_number, f_append},
|
{"append", 2, 2, FEARG_2, ret_number, f_append},
|
||||||
{"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
|
{"appendbufline", 3, 3, FEARG_2, ret_number, f_appendbufline},
|
||||||
{"argc", 0, 1, 0, ret_number, f_argc},
|
{"argc", 0, 1, 0, ret_number, f_argc},
|
||||||
{"argidx", 0, 0, 0, ret_number, f_argidx},
|
{"argidx", 0, 0, 0, ret_number, f_argidx},
|
||||||
{"arglistid", 0, 2, 0, ret_number, f_arglistid},
|
{"arglistid", 0, 2, 0, ret_number, f_arglistid},
|
||||||
@@ -1191,7 +1191,9 @@ internal_func_ret_type(int idx, int argcount, type_T **argtypes)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the argument count to use for internal function "idx".
|
* Check the argument count to use for internal function "idx".
|
||||||
* Returns OK or FAIL;
|
* 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
|
int
|
||||||
check_internal_func(int idx, int argcount)
|
check_internal_func(int idx, int argcount)
|
||||||
@@ -1204,14 +1206,14 @@ check_internal_func(int idx, int argcount)
|
|||||||
else if (argcount > global_functions[idx].f_max_argc)
|
else if (argcount > global_functions[idx].f_max_argc)
|
||||||
res = FCERR_TOOMANY;
|
res = FCERR_TOOMANY;
|
||||||
else
|
else
|
||||||
return OK;
|
return global_functions[idx].f_argtype;
|
||||||
|
|
||||||
name = internal_func_name(idx);
|
name = internal_func_name(idx);
|
||||||
if (res == FCERR_TOOMANY)
|
if (res == FCERR_TOOMANY)
|
||||||
semsg(_(e_toomanyarg), name);
|
semsg(_(e_toomanyarg), name);
|
||||||
else
|
else
|
||||||
semsg(_(e_toofewarg), name);
|
semsg(_(e_toofewarg), name);
|
||||||
return FAIL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@@ -1278,4 +1278,22 @@ def Test_simplify_const_expr()
|
|||||||
res)
|
res)
|
||||||
enddef
|
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: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -1411,6 +1411,28 @@ def Test_expr7_subscript_linebreak()
|
|||||||
one)
|
one)
|
||||||
enddef
|
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()
|
func Test_expr7_trailing_fails()
|
||||||
call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107')
|
call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107')
|
||||||
|
@@ -754,6 +754,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1167,
|
||||||
/**/
|
/**/
|
||||||
1166,
|
1166,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -124,6 +124,7 @@ typedef enum {
|
|||||||
ISN_CHECKTYPE, // check value type is isn_arg.type.tc_type
|
ISN_CHECKTYPE, // check value type is isn_arg.type.tc_type
|
||||||
ISN_CHECKLEN, // check list length is isn_arg.checklen.cl_min_len
|
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
|
ISN_DROP // pop stack and discard value
|
||||||
} isntype_T;
|
} isntype_T;
|
||||||
|
|
||||||
@@ -237,6 +238,12 @@ typedef struct {
|
|||||||
int cl_more_OK; // longer is allowed
|
int cl_more_OK; // longer is allowed
|
||||||
} checklen_T;
|
} 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
|
* Instruction
|
||||||
*/
|
*/
|
||||||
@@ -270,6 +277,7 @@ struct isn_S {
|
|||||||
unlet_T unlet;
|
unlet_T unlet;
|
||||||
funcref_T funcref;
|
funcref_T funcref;
|
||||||
checklen_T checklen;
|
checklen_T checklen;
|
||||||
|
shuffle_T shuffle;
|
||||||
} isn_arg;
|
} isn_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1445,20 +1445,31 @@ generate_FOR(cctx_T *cctx, int loop_idx)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate an ISN_BCALL instruction.
|
* Generate an ISN_BCALL instruction.
|
||||||
|
* "method_call" is TRUE for "value->method()"
|
||||||
* Return FAIL if the number of arguments is wrong.
|
* Return FAIL if the number of arguments is wrong.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
generate_BCALL(cctx_T *cctx, int func_idx, int argcount)
|
generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
int argoff;
|
||||||
type_T *argtypes[MAX_FUNC_ARGS];
|
type_T *argtypes[MAX_FUNC_ARGS];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if (check_internal_func(func_idx, argcount) == FAIL)
|
argoff = check_internal_func(func_idx, argcount);
|
||||||
|
if (argoff < 0)
|
||||||
return FAIL;
|
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)
|
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.bfunc.cbf_idx = func_idx;
|
isn->isn_arg.bfunc.cbf_idx = func_idx;
|
||||||
@@ -2930,7 +2941,7 @@ compile_call(
|
|||||||
// builtin function
|
// builtin function
|
||||||
idx = find_internal_func(name);
|
idx = find_internal_func(name);
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
res = generate_BCALL(cctx, idx, argcount);
|
res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
|
||||||
else
|
else
|
||||||
semsg(_(e_unknownfunc), namebuf);
|
semsg(_(e_unknownfunc), namebuf);
|
||||||
goto theend;
|
goto theend;
|
||||||
@@ -7397,6 +7408,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_COMPARESTRING:
|
case ISN_COMPARESTRING:
|
||||||
case ISN_CONCAT:
|
case ISN_CONCAT:
|
||||||
case ISN_DCALL:
|
case ISN_DCALL:
|
||||||
|
case ISN_SHUFFLE:
|
||||||
case ISN_DROP:
|
case ISN_DROP:
|
||||||
case ISN_ECHO:
|
case ISN_ECHO:
|
||||||
case ISN_ECHOERR:
|
case ISN_ECHOERR:
|
||||||
|
@@ -554,7 +554,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr)
|
|||||||
|
|
||||||
if (func_idx < 0)
|
if (func_idx < 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (check_internal_func(func_idx, argcount) == FAIL)
|
if (check_internal_func(func_idx, argcount) < 0)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
return call_bfunc(func_idx, argcount, ectx);
|
return call_bfunc(func_idx, argcount, ectx);
|
||||||
}
|
}
|
||||||
@@ -2333,6 +2333,22 @@ call_def_function(
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case ISN_DROP:
|
||||||
--ectx.ec_stack.ga_len;
|
--ectx.ec_stack.ga_len;
|
||||||
clear_tv(STACK_TV_BOT(0));
|
clear_tv(STACK_TV_BOT(0));
|
||||||
@@ -2900,8 +2916,12 @@ ex_disassemble(exarg_T *eap)
|
|||||||
break;
|
break;
|
||||||
case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
|
case ISN_2STRING: smsg("%4d 2STRING stack[%lld]", current,
|
||||||
(long long)(iptr->isn_arg.number));
|
(long long)(iptr->isn_arg.number));
|
||||||
break;
|
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;
|
case ISN_DROP: smsg("%4d DROP", current); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user