vim-patch:partial: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: vim/vim#14900

734286e4c6

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
zeertzjq
2024-08-01 08:57:48 +08:00
parent 8f47a95add
commit 7f1ba04421

View File

@@ -2974,7 +2974,7 @@ static int eval_concat_str(typval_T *tv1, typval_T *tv2)
/// Add or subtract numbers "tv1" and "tv2" and store the result in "tv1".
/// The numbers can be whole numbers or floats.
static int eval_addsub_num(typval_T *tv1, typval_T *tv2, int op)
static int eval_addsub_number(typval_T *tv1, typval_T *tv2, int op)
{
bool error = false;
varnumber_T n1, n2;
@@ -3102,7 +3102,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
return FAIL;
}
} else {
if (eval_addsub_num(rettv, &var2, op) == FAIL) {
if (eval_addsub_number(rettv, &var2, op) == FAIL) {
return FAIL;
}
}
@@ -3112,74 +3112,40 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
return OK;
}
/// Handle fifth level expression:
/// - * number multiplication
/// - / number division
/// - % number modulo
///
/// @param[in,out] arg Points to the first non-whitespace character of the
/// expression. Is advanced to the next non-whitespace
/// character after the recognized expression.
/// @param[out] rettv Location where result is saved.
/// @param[in] want_string True if "." is string_concatenation, otherwise
/// float
/// @return OK or FAIL.
static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
/// 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 eval_multdiv_number(typval_T *tv1, typval_T *tv2, int op)
FUNC_ATTR_NO_SANITIZE_UNDEFINED
{
varnumber_T n1, n2;
bool use_float = false;
// Get the first variable.
if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
return FAIL;
}
// Repeat computing, until no '*', '/' or '%' is following.
while (true) {
int op = (uint8_t)(**arg);
if (op != '*' && op != '/' && op != '%') {
break;
}
varnumber_T n1, n2;
float_T f1 = 0;
float_T f2 = 0;
bool error = false;
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
if (evaluate) {
if (rettv->v_type == VAR_FLOAT) {
f1 = rettv->vval.v_float;
if (tv1->v_type == VAR_FLOAT) {
f1 = tv1->vval.v_float;
use_float = true;
n1 = 0;
} else {
n1 = tv_get_number_chk(rettv, &error);
n1 = tv_get_number_chk(tv1, &error);
}
tv_clear(rettv);
tv_clear(tv1);
if (error) {
return FAIL;
}
} else {
n1 = 0;
}
// Get the second variable.
*arg = skipwhite(*arg + 1);
typval_T var2;
if (eval7(arg, &var2, evalarg, false) == FAIL) {
tv_clear(tv2);
return FAIL;
}
if (evaluate) {
if (var2.v_type == VAR_FLOAT) {
if (tv2->v_type == VAR_FLOAT) {
if (!use_float) {
f1 = (float_T)n1;
use_float = true;
}
f2 = var2.vval.v_float;
f2 = tv2->vval.v_float;
n2 = 0;
} else {
n2 = tv_get_number_chk(&var2, &error);
tv_clear(&var2);
n2 = tv_get_number_chk(tv2, &error);
tv_clear(tv2);
if (error) {
return FAIL;
}
@@ -3208,8 +3174,8 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
emsg(_("E804: Cannot use '%' 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 {
if (op == '*') {
n1 = n1 * n2;
@@ -3218,8 +3184,52 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
} else {
n1 = num_modulus(n1, n2);
}
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n1;
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n1;
}
return OK;
}
/// Handle fifth level expression:
/// - * number multiplication
/// - / number division
/// - % number modulo
///
/// @param[in,out] arg Points to the first non-whitespace character of the
/// expression. Is advanced to the next non-whitespace
/// character after the recognized expression.
/// @param[out] rettv Location where result is saved.
/// @param[in] want_string True if "." is string_concatenation, otherwise
/// float
/// @return OK or FAIL.
static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
{
// Get the first variable.
if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
return FAIL;
}
// Repeat computing, until no '*', '/' or '%' is following.
while (true) {
int op = (uint8_t)(**arg);
if (op != '*' && op != '/' && op != '%') {
break;
}
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
// Get the second variable.
*arg = skipwhite(*arg + 1);
typval_T var2;
if (eval7(arg, &var2, evalarg, false) == FAIL) {
return FAIL;
}
if (evaluate) {
// Compute the result.
if (eval_multdiv_number(rettv, &var2, op) == FAIL) {
return FAIL;
}
}
}