diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 156 |
1 files changed, 83 insertions, 73 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index fa519ad701..b8c3df5688 100644 --- a/src/nvim/eval.c +++ b/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". /// 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,6 +3112,85 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) 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: /// - * number multiplication /// - / number division @@ -3125,10 +3204,7 @@ static int eval5(char **arg, typval_T *rettv, evalarg_T *const evalarg) /// float /// @return OK or FAIL. 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. if (eval7(arg, rettv, evalarg, want_string) == FAIL) { return FAIL; @@ -3141,26 +3217,7 @@ static int eval6(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan 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; - 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. *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 (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. - // 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; - } - 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; + if (eval_multdiv_number(rettv, &var2, op) == FAIL) { + return FAIL; } } } |