patch 9.1.0462: eval5() and eval7 are too complex

Problem:  eval5() and eval7 are too complex
Solution: Refactor eval5() and eval7() in eval.c
          (Yegappan Lakshmanan)

closes: #14900

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2024-06-03 18:52:22 +02:00
committed by Christian Brabandt
parent f51ff96532
commit 734286e4c6
3 changed files with 154 additions and 127 deletions

View File

@ -3946,6 +3946,40 @@ eval_addlist(typval_T *tv1, typval_T *tv2)
return OK;
}
/*
* Left or right shift the number "tv1" by the number "tv2" and store the
* result in "tv1".
*
* Return OK or FAIL.
*/
static int
eval_shift_number(typval_T *tv1, typval_T *tv2, int shift_type)
{
if (tv2->v_type != VAR_NUMBER || tv2->vval.v_number < 0)
{
// right operand should be a positive number
if (tv2->v_type != VAR_NUMBER)
emsg(_(e_bitshift_ops_must_be_number));
else
emsg(_(e_bitshift_ops_must_be_positive));
clear_tv(tv1);
clear_tv(tv2);
return FAIL;
}
if (tv2->vval.v_number > MAX_LSHIFT_BITS)
// shifting more bits than we have always results in zero
tv1->vval.v_number = 0;
else if (shift_type == EXPR_LSHIFT)
tv1->vval.v_number =
(uvarnumber_T)tv1->vval.v_number << tv2->vval.v_number;
else
tv1->vval.v_number =
(uvarnumber_T)tv1->vval.v_number >> tv2->vval.v_number;
return OK;
}
/*
* Handle the bitwise left/right shift operator expression:
* var1 << var2
@ -3972,16 +4006,16 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
char_u *p;
int getnext;
exprtype_T type;
exprtype_T exprtype;
int evaluate;
typval_T var2;
int vim9script;
p = eval_next_non_blank(*arg, evalarg, &getnext);
if (p[0] == '<' && p[1] == '<')
type = EXPR_LSHIFT;
exprtype = EXPR_LSHIFT;
else if (p[0] == '>' && p[1] == '>')
type = EXPR_RSHIFT;
exprtype = EXPR_RSHIFT;
else
return OK;
@ -4026,29 +4060,10 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
if (evaluate)
{
if (var2.v_type != VAR_NUMBER || var2.vval.v_number < 0)
{
// right operand should be a positive number
if (var2.v_type != VAR_NUMBER)
emsg(_(e_bitshift_ops_must_be_number));
else
emsg(_(e_bitshift_ops_must_be_positive));
clear_tv(rettv);
clear_tv(&var2);
if (eval_shift_number(rettv, &var2, exprtype) == FAIL)
return FAIL;
}
if (var2.vval.v_number > MAX_LSHIFT_BITS)
// shifting more bits than we have always results in zero
rettv->vval.v_number = 0;
else if (type == EXPR_LSHIFT)
rettv->vval.v_number =
(uvarnumber_T)rettv->vval.v_number << var2.vval.v_number;
else
rettv->vval.v_number =
(uvarnumber_T)rettv->vval.v_number >> var2.vval.v_number;
}
clear_tv(&var2);
}
@ -4100,7 +4115,7 @@ eval_concat_str(typval_T *tv1, typval_T *tv2)
* The numbers can be whole numbers or floats.
*/
static int
eval_addsub_num(typval_T *tv1, typval_T *tv2, int op)
eval_addsub_number(typval_T *tv1, typval_T *tv2, int op)
{
int error = FALSE;
varnumber_T n1, n2;
@ -4290,7 +4305,7 @@ eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
}
else
{
if (eval_addsub_num(rettv, &var2, op) == FAIL)
if (eval_addsub_number(rettv, &var2, op) == FAIL)
return FAIL;
}
clear_tv(&var2);
@ -4300,114 +4315,49 @@ eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
}
/*
* Handle sixth level expression:
* * number multiplication
* / number division
* % number modulo
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to just after the recognized expression.
*
* Return OK or FAIL.
* Multiply or divide or compute the modulo of numbers "tv1" and "tv2" and
* store the result in "tv1". The numbers can be whole numbers or floats.
*/
static int
eval7(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
int want_string) // after "." operator
eval_multdiv_number(typval_T *tv1, typval_T *tv2, int op)
{
int use_float = FALSE;
/*
* Get the first expression.
*/
if (eval8(arg, rettv, evalarg, want_string) == FAIL)
return FAIL;
/*
* Repeat computing, until no '*', '/' or '%' is following.
*/
for (;;)
{
int evaluate;
int getnext;
typval_T var2;
char_u *p;
int op;
varnumber_T n1, n2;
float_T f1, f2;
int error;
// "*=", "/=" and "%=" are assignments
p = eval_next_non_blank(*arg, evalarg, &getnext);
op = *p;
if ((op != '*' && op != '/' && op != '%') || p[1] == '=')
break;
evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
if (getnext)
*arg = eval_next_line(*arg, evalarg);
else
{
if (evaluate && in_vim9script() && !VIM_ISWHITE(**arg))
{
error_white_both(*arg, 1);
clear_tv(rettv);
return FAIL;
}
*arg = p;
}
int use_float = FALSE;
f1 = 0;
f2 = 0;
error = FALSE;
if (evaluate)
if (tv1->v_type == VAR_FLOAT)
{
if (rettv->v_type == VAR_FLOAT)
{
f1 = rettv->vval.v_float;
f1 = tv1->vval.v_float;
use_float = TRUE;
n1 = 0;
}
else
n1 = tv_get_number_chk(rettv, &error);
clear_tv(rettv);
n1 = tv_get_number_chk(tv1, &error);
clear_tv(tv1);
if (error)
{
clear_tv(tv2);
return FAIL;
}
else
n1 = 0;
/*
* Get the second variable.
*/
if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
{
error_white_both(*arg, 1);
clear_tv(rettv);
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
if (eval8(arg, &var2, evalarg, FALSE) == FAIL)
return FAIL;
if (evaluate)
{
if (var2.v_type == VAR_FLOAT)
if (tv2->v_type == VAR_FLOAT)
{
if (!use_float)
{
f1 = n1;
use_float = TRUE;
}
f2 = var2.vval.v_float;
f2 = tv2->vval.v_float;
n2 = 0;
}
else
{
n2 = tv_get_number_chk(&var2, &error);
clear_tv(&var2);
n2 = tv_get_number_chk(tv2, &error);
clear_tv(tv2);
if (error)
return FAIL;
if (use_float)
@ -4448,8 +4398,8 @@ eval7(
emsg(_(e_cannot_use_percent_with_float));
return FAIL;
}
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f1;
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f1;
}
else
{
@ -4464,10 +4414,85 @@ eval7(
if (failed)
return FAIL;
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n1;
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n1;
}
return OK;
}
/*
* Handle sixth level expression:
* * number multiplication
* / number division
* % number modulo
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to just after the recognized expression.
*
* Return OK or FAIL.
*/
static int
eval7(
char_u **arg,
typval_T *rettv,
evalarg_T *evalarg,
int want_string) // after "." operator
{
/*
* Get the first expression.
*/
if (eval8(arg, rettv, evalarg, want_string) == FAIL)
return FAIL;
/*
* Repeat computing, until no '*', '/' or '%' is following.
*/
for (;;)
{
int evaluate;
int getnext;
typval_T var2;
char_u *p;
int op;
// "*=", "/=" and "%=" are assignments
p = eval_next_non_blank(*arg, evalarg, &getnext);
op = *p;
if ((op != '*' && op != '/' && op != '%') || p[1] == '=')
break;
evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
if (getnext)
*arg = eval_next_line(*arg, evalarg);
else
{
if (evaluate && in_vim9script() && !VIM_ISWHITE(**arg))
{
error_white_both(*arg, 1);
clear_tv(rettv);
return FAIL;
}
*arg = p;
}
/*
* Get the second variable.
*/
if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
{
error_white_both(*arg, 1);
clear_tv(rettv);
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
if (eval8(arg, &var2, evalarg, FALSE) == FAIL)
return FAIL;
if (evaluate)
// Compute the result.
if (eval_multdiv_number(rettv, &var2, op) == FAIL)
return FAIL;
}
return OK;

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
462,
/**/
461,
/**/