mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 22:18:33 +00:00
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:
156
src/nvim/eval.c
156
src/nvim/eval.c
@@ -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".
|
/// Add or subtract numbers "tv1" and "tv2" and store the result in "tv1".
|
||||||
/// The numbers can be whole numbers or floats.
|
/// 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;
|
bool error = false;
|
||||||
varnumber_T n1, n2;
|
varnumber_T n1, n2;
|
||||||
@@ -3102,7 +3102,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (eval_addsub_num(rettv, &var2, op) == FAIL) {
|
if (eval_addsub_number(rettv, &var2, op) == FAIL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3112,6 +3112,85 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
|
float_T f1 = 0;
|
||||||
|
float_T f2 = 0;
|
||||||
|
bool error = false;
|
||||||
|
if (tv1->v_type == VAR_FLOAT) {
|
||||||
|
f1 = tv1->vval.v_float;
|
||||||
|
use_float = true;
|
||||||
|
n1 = 0;
|
||||||
|
} else {
|
||||||
|
n1 = tv_get_number_chk(tv1, &error);
|
||||||
|
}
|
||||||
|
tv_clear(tv1);
|
||||||
|
if (error) {
|
||||||
|
tv_clear(tv2);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tv2->v_type == VAR_FLOAT) {
|
||||||
|
if (!use_float) {
|
||||||
|
f1 = (float_T)n1;
|
||||||
|
use_float = true;
|
||||||
|
}
|
||||||
|
f2 = tv2->vval.v_float;
|
||||||
|
n2 = 0;
|
||||||
|
} else {
|
||||||
|
n2 = tv_get_number_chk(tv2, &error);
|
||||||
|
tv_clear(tv2);
|
||||||
|
if (error) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (use_float) {
|
||||||
|
f2 = (float_T)n2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the result.
|
||||||
|
// When either side is a float the result is a float.
|
||||||
|
if (use_float) {
|
||||||
|
if (op == '*') {
|
||||||
|
f1 = f1 * f2;
|
||||||
|
} else if (op == '/') {
|
||||||
|
// uncrustify:off
|
||||||
|
|
||||||
|
// Division by zero triggers error from AddressSanitizer
|
||||||
|
f1 = (f2 == 0 ? (
|
||||||
|
#ifdef NAN
|
||||||
|
f1 == 0 ? (float_T)NAN :
|
||||||
|
#endif
|
||||||
|
(f1 > 0 ? (float_T)INFINITY : (float_T)-INFINITY)) : f1 / f2);
|
||||||
|
|
||||||
|
// uncrustify:on
|
||||||
|
} else {
|
||||||
|
emsg(_("E804: Cannot use '%' with Float"));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
tv1->v_type = VAR_FLOAT;
|
||||||
|
tv1->vval.v_float = f1;
|
||||||
|
} else {
|
||||||
|
if (op == '*') {
|
||||||
|
n1 = n1 * n2;
|
||||||
|
} else if (op == '/') {
|
||||||
|
n1 = num_divide(n1, n2);
|
||||||
|
} else {
|
||||||
|
n1 = num_modulus(n1, n2);
|
||||||
|
}
|
||||||
|
tv1->v_type = VAR_NUMBER;
|
||||||
|
tv1->vval.v_number = n1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle fifth level expression:
|
/// Handle fifth level expression:
|
||||||
/// - * number multiplication
|
/// - * number multiplication
|
||||||
/// - / number division
|
/// - / number division
|
||||||
@@ -3125,10 +3204,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg)
|
|||||||
/// float
|
/// float
|
||||||
/// @return OK or FAIL.
|
/// @return OK or FAIL.
|
||||||
static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
|
static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool want_string)
|
||||||
FUNC_ATTR_NO_SANITIZE_UNDEFINED
|
|
||||||
{
|
{
|
||||||
bool use_float = false;
|
|
||||||
|
|
||||||
// Get the first variable.
|
// Get the first variable.
|
||||||
if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
|
if (eval7(arg, rettv, evalarg, want_string) == FAIL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -3141,26 +3217,7 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
|
|||||||
break;
|
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);
|
const bool evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
if (evaluate) {
|
|
||||||
if (rettv->v_type == VAR_FLOAT) {
|
|
||||||
f1 = rettv->vval.v_float;
|
|
||||||
use_float = true;
|
|
||||||
n1 = 0;
|
|
||||||
} else {
|
|
||||||
n1 = tv_get_number_chk(rettv, &error);
|
|
||||||
}
|
|
||||||
tv_clear(rettv);
|
|
||||||
if (error) {
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
n1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the second variable.
|
// Get the second variable.
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
@@ -3170,56 +3227,9 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (evaluate) {
|
if (evaluate) {
|
||||||
if (var2.v_type == VAR_FLOAT) {
|
|
||||||
if (!use_float) {
|
|
||||||
f1 = (float_T)n1;
|
|
||||||
use_float = true;
|
|
||||||
}
|
|
||||||
f2 = var2.vval.v_float;
|
|
||||||
n2 = 0;
|
|
||||||
} else {
|
|
||||||
n2 = tv_get_number_chk(&var2, &error);
|
|
||||||
tv_clear(&var2);
|
|
||||||
if (error) {
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
if (use_float) {
|
|
||||||
f2 = (float_T)n2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the result.
|
// Compute the result.
|
||||||
// When either side is a float the result is a float.
|
if (eval_multdiv_number(rettv, &var2, op) == FAIL) {
|
||||||
if (use_float) {
|
return FAIL;
|
||||||
if (op == '*') {
|
|
||||||
f1 = f1 * f2;
|
|
||||||
} else if (op == '/') {
|
|
||||||
// uncrustify:off
|
|
||||||
|
|
||||||
// Division by zero triggers error from AddressSanitizer
|
|
||||||
f1 = (f2 == 0 ? (
|
|
||||||
#ifdef NAN
|
|
||||||
f1 == 0 ? (float_T)NAN :
|
|
||||||
#endif
|
|
||||||
(f1 > 0 ? (float_T)INFINITY : (float_T)-INFINITY)) : f1 / f2);
|
|
||||||
|
|
||||||
// uncrustify:on
|
|
||||||
} else {
|
|
||||||
emsg(_("E804: Cannot use '%' with Float"));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
rettv->v_type = VAR_FLOAT;
|
|
||||||
rettv->vval.v_float = f1;
|
|
||||||
} else {
|
|
||||||
if (op == '*') {
|
|
||||||
n1 = n1 * n2;
|
|
||||||
} else if (op == '/') {
|
|
||||||
n1 = num_divide(n1, n2);
|
|
||||||
} else {
|
|
||||||
n1 = num_modulus(n1, n2);
|
|
||||||
}
|
|
||||||
rettv->v_type = VAR_NUMBER;
|
|
||||||
rettv->vval.v_number = n1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user