1
0
forked from aniani/vim

patch 9.0.1723: Fix regression in {func} argument of reduce()

Problem: Fix regression in {func} argument of reduce()
Solution: pass function name as string again

Before patch 9.0.0548, passing a string as {func} argument of reduce()
is treated as a function name, but after patch 9.0.0548 it is treated as
an expression instead, which is useless as reduce() doesn't set any v:
variables. This PR restores the behavior of {func} before that patch.

Also correct an emsg() call, as e_string_list_or_blob_required doesn't
contain format specifiers.

closes: #12824

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
zeertzjq
2023-08-17 22:15:47 +02:00
committed by Christian Brabandt
parent 4f389e7c0f
commit ad0c442f1f
9 changed files with 31 additions and 21 deletions

View File

@@ -769,7 +769,7 @@ blob_reduce(
argv[1].v_type = VAR_NUMBER; argv[1].v_type = VAR_NUMBER;
argv[1].vval.v_number = blob_get(b, i); argv[1].vval.v_number = blob_get(b, i);
r = eval_expr_typval(expr, argv, 2, NULL, rettv); r = eval_expr_typval(expr, TRUE, argv, 2, NULL, rettv);
clear_tv(&argv[0]); clear_tv(&argv[0]);
if (r == FAIL || called_emsg != called_emsg_start) if (r == FAIL || called_emsg != called_emsg_start)

View File

@@ -252,12 +252,14 @@ eval_expr_get_funccal(typval_T *expr, typval_T *rettv)
/* /*
* Evaluate an expression, which can be a function, partial or string. * Evaluate an expression, which can be a function, partial or string.
* Pass arguments "argv[argc]". * Pass arguments "argv[argc]".
* If "want_func" is TRUE treat a string as a function name, not an expression.
* "fc_arg" is from eval_expr_get_funccal() or NULL; * "fc_arg" is from eval_expr_get_funccal() or NULL;
* Return the result in "rettv" and OK or FAIL. * Return the result in "rettv" and OK or FAIL.
*/ */
int int
eval_expr_typval( eval_expr_typval(
typval_T *expr, typval_T *expr,
int want_func,
typval_T *argv, typval_T *argv,
int argc, int argc,
funccall_T *fc_arg, funccall_T *fc_arg,
@@ -267,17 +269,7 @@ eval_expr_typval(
char_u buf[NUMBUFLEN]; char_u buf[NUMBUFLEN];
funcexe_T funcexe; funcexe_T funcexe;
if (expr->v_type == VAR_FUNC) if (expr->v_type == VAR_PARTIAL)
{
s = expr->vval.v_string;
if (s == NULL || *s == NUL)
return FAIL;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
return FAIL;
}
else if (expr->v_type == VAR_PARTIAL)
{ {
partial_T *partial = expr->vval.v_partial; partial_T *partial = expr->vval.v_partial;
@@ -318,6 +310,18 @@ eval_expr_typval(
{ {
return exe_typval_instr(expr, rettv); return exe_typval_instr(expr, rettv);
} }
else if (expr->v_type == VAR_FUNC || want_func)
{
s = expr->v_type == VAR_FUNC
? expr->vval.v_string
: tv_get_string_buf_chk_strict(expr, buf, in_vim9script());
if (s == NULL || *s == NUL)
return FAIL;
CLEAR_FIELD(funcexe);
funcexe.fe_evaluate = TRUE;
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL)
return FAIL;
}
else else
{ {
s = tv_get_string_buf_chk_strict(expr, buf, in_vim9script()); s = tv_get_string_buf_chk_strict(expr, buf, in_vim9script());
@@ -346,7 +350,7 @@ eval_expr_to_bool(typval_T *expr, int *error)
typval_T rettv; typval_T rettv;
int res; int res;
if (eval_expr_typval(expr, NULL, 0, NULL, &rettv) == FAIL) if (eval_expr_typval(expr, FALSE, NULL, 0, NULL, &rettv) == FAIL)
{ {
*error = TRUE; *error = TRUE;
return FALSE; return FALSE;

View File

@@ -6938,7 +6938,7 @@ indexof_eval_expr(typval_T *expr)
argv[1] = *get_vim_var_tv(VV_VAL); argv[1] = *get_vim_var_tv(VV_VAL);
newtv.v_type = VAR_UNKNOWN; newtv.v_type = VAR_UNKNOWN;
if (eval_expr_typval(expr, argv, 2, NULL, &newtv) == FAIL) if (eval_expr_typval(expr, FALSE, argv, 2, NULL, &newtv) == FAIL)
return FALSE; return FALSE;
found = tv_get_bool_chk(&newtv, &error); found = tv_get_bool_chk(&newtv, &error);

View File

@@ -1616,7 +1616,7 @@ checkitem_common(void *context, char_u *name, dict_T *dict)
argv[0].vval.v_dict = dict; argv[0].vval.v_dict = dict;
} }
if (eval_expr_typval(expr, argv, 1, NULL, &rettv) == FAIL) if (eval_expr_typval(expr, FALSE, argv, 1, NULL, &rettv) == FAIL)
goto theend; goto theend;
// We want to use -1, but also true/false should be allowed. // We want to use -1, but also true/false should be allowed.

View File

@@ -2333,7 +2333,7 @@ filter_map_one(
copy_tv(tv, get_vim_var_tv(VV_VAL)); copy_tv(tv, get_vim_var_tv(VV_VAL));
argv[0] = *get_vim_var_tv(VV_KEY); argv[0] = *get_vim_var_tv(VV_KEY);
argv[1] = *get_vim_var_tv(VV_VAL); argv[1] = *get_vim_var_tv(VV_VAL);
if (eval_expr_typval(expr, argv, 2, fc, newtv) == FAIL) if (eval_expr_typval(expr, FALSE, argv, 2, fc, newtv) == FAIL)
goto theend; goto theend;
if (filtermap == FILTERMAP_FILTER) if (filtermap == FILTERMAP_FILTER)
{ {
@@ -3084,7 +3084,7 @@ list_reduce(
else else
argv[1] = li->li_tv; argv[1] = li->li_tv;
r = eval_expr_typval(expr, argv, 2, fc, rettv); r = eval_expr_typval(expr, TRUE, argv, 2, fc, rettv);
if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN) if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN)
clear_tv(&argv[0]); clear_tv(&argv[0]);
@@ -3125,7 +3125,7 @@ f_reduce(typval_T *argvars, typval_T *rettv)
&& argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_LIST
&& argvars[0].v_type != VAR_BLOB) && argvars[0].v_type != VAR_BLOB)
{ {
semsg(_(e_string_list_or_blob_required), "reduce()"); emsg(_(e_string_list_or_blob_required));
return; return;
} }

View File

@@ -7,7 +7,7 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip);
int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip, int use_simple_function); int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip, int use_simple_function);
int eval_expr_valid_arg(typval_T *tv); int eval_expr_valid_arg(typval_T *tv);
funccall_T *eval_expr_get_funccal(typval_T *expr, typval_T *rettv); funccall_T *eval_expr_get_funccal(typval_T *expr, typval_T *rettv);
int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, funccall_T *fc_arg, typval_T *rettv); int eval_expr_typval(typval_T *expr, int prefer_func, typval_T *argv, int argc, funccall_T *fc_arg, typval_T *rettv);
int eval_expr_to_bool(typval_T *expr, int *error); int eval_expr_to_bool(typval_T *expr, int *error);
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip); char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
void init_evalarg(evalarg_T *evalarg); void init_evalarg(evalarg_T *evalarg);

View File

@@ -1032,7 +1032,7 @@ string_reduce(
break; break;
len = (int)STRLEN(argv[1].vval.v_string); len = (int)STRLEN(argv[1].vval.v_string);
r = eval_expr_typval(expr, argv, 2, fc, rettv); r = eval_expr_typval(expr, TRUE, argv, 2, fc, rettv);
clear_tv(&argv[0]); clear_tv(&argv[0]);
clear_tv(&argv[1]); clear_tv(&argv[1]);

View File

@@ -1037,6 +1037,10 @@ func Test_reduce()
call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND)) call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND)) call assert_equal('Å,s,t,r,ö,m', reduce('Åström', LSTART acc, val LMIDDLE acc .. ',' .. val LEND))
call assert_equal(',a,b,c', reduce('abc', LSTART acc, val LMIDDLE acc .. ',' .. val LEND, test_null_string())) call assert_equal(',a,b,c', reduce('abc', LSTART acc, val LMIDDLE acc .. ',' .. val LEND, test_null_string()))
call assert_equal(0x7d, reduce([0x30, 0x25, 0x08, 0x61], 'or'))
call assert_equal(0x7d, reduce(0z30250861, 'or'))
call assert_equal('β', reduce('ββββ', 'matchstr'))
END END
call v9.CheckLegacyAndVim9Success(lines) call v9.CheckLegacyAndVim9Success(lines)
@@ -1052,7 +1056,7 @@ func Test_reduce()
call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E1098:') call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E1098:')
call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E1098:') call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E1098:')
call assert_fails("call reduce([1, 2], 'Xdoes_not_exist')", 'E121:') call assert_fails("call reduce([1, 2], 'Xdoes_not_exist')", 'E117:')
call assert_fails("echo reduce(0z01, { acc, val -> 2 * acc + val }, '')", 'E1210:') call assert_fails("echo reduce(0z01, { acc, val -> 2 * acc + val }, '')", 'E1210:')
call assert_fails("vim9 reduce(0, (acc, val) => (acc .. val), '')", 'E1252:') call assert_fails("vim9 reduce(0, (acc, val) => (acc .. val), '')", 'E1252:')

View File

@@ -695,6 +695,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 */
/**/
1723,
/**/ /**/
1722, 1722,
/**/ /**/