From 734286e4c626f80ace27eeb252a5e384e798aebf Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Mon, 3 Jun 2024 18:52:22 +0200 Subject: 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 Signed-off-by: Christian Brabandt --- src/eval.c | 275 ++++++++++++++++++++++++++++++------------------------- src/scriptfile.c | 4 +- src/version.c | 2 + 3 files changed, 154 insertions(+), 127 deletions(-) (limited to 'src') diff --git a/src/eval.c b/src/eval.c index 4a039792c8..7848feaa87 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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,27 +4060,8 @@ 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); @@ -4299,6 +4314,113 @@ eval6(char_u **arg, typval_T *rettv, evalarg_T *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) +{ + varnumber_T n1, n2; + float_T f1, f2; + int error; + int use_float = FALSE; + + f1 = 0; + f2 = 0; + 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); + clear_tv(tv1); + if (error) + { + clear_tv(tv2); + return FAIL; + } + + if (tv2->v_type == VAR_FLOAT) + { + if (!use_float) + { + f1 = n1; + use_float = TRUE; + } + f2 = tv2->vval.v_float; + n2 = 0; + } + else + { + n2 = tv_get_number_chk(tv2, &error); + clear_tv(tv2); + if (error) + return FAIL; + if (use_float) + f2 = 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 == '/') + { +#ifdef VMS + // VMS crashes on divide by zero, work around it + if (f2 == 0.0) + { + if (f1 == 0) + f1 = -1 * __F_FLT_MAX - 1L; // similar to NaN + else if (f1 < 0) + f1 = -1 * __F_FLT_MAX; + else + f1 = __F_FLT_MAX; + } + else + f1 = f1 / f2; +#else + // We rely on the floating point library to handle divide + // by zero to result in "inf" and not a crash. + f1 = f1 / f2; +#endif + } + else + { + emsg(_(e_cannot_use_percent_with_float)); + return FAIL; + } + tv1->v_type = VAR_FLOAT; + tv1->vval.v_float = f1; + } + else + { + int failed = FALSE; + + if (op == '*') + n1 = n1 * n2; + else if (op == '/') + n1 = num_divide(n1, n2, &failed); + else + n1 = num_modulus(n1, n2, &failed); + if (failed) + return FAIL; + + tv1->v_type = VAR_NUMBER; + tv1->vval.v_number = n1; + } + + return OK; +} + /* * Handle sixth level expression: * * number multiplication @@ -4317,8 +4439,6 @@ eval7( evalarg_T *evalarg, int want_string) // after "." operator { - int use_float = FALSE; - /* * Get the first expression. */ @@ -4335,9 +4455,6 @@ eval7( 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); @@ -4359,26 +4476,6 @@ eval7( *arg = p; } - f1 = 0; - f2 = 0; - error = FALSE; - 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); - clear_tv(rettv); - if (error) - return FAIL; - } - else - n1 = 0; - /* * Get the second variable. */ @@ -4393,81 +4490,9 @@ eval7( return FAIL; if (evaluate) - { - if (var2.v_type == VAR_FLOAT) - { - if (!use_float) - { - f1 = n1; - use_float = TRUE; - } - f2 = var2.vval.v_float; - n2 = 0; - } - else - { - n2 = tv_get_number_chk(&var2, &error); - clear_tv(&var2); - if (error) - return FAIL; - if (use_float) - f2 = 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 == '/') - { -#ifdef VMS - // VMS crashes on divide by zero, work around it - if (f2 == 0.0) - { - if (f1 == 0) - f1 = -1 * __F_FLT_MAX - 1L; // similar to NaN - else if (f1 < 0) - f1 = -1 * __F_FLT_MAX; - else - f1 = __F_FLT_MAX; - } - else - f1 = f1 / f2; -#else - // We rely on the floating point library to handle divide - // by zero to result in "inf" and not a crash. - f1 = f1 / f2; -#endif - } - else - { - emsg(_(e_cannot_use_percent_with_float)); - return FAIL; - } - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = f1; - } - else - { - int failed = FALSE; - - if (op == '*') - n1 = n1 * n2; - else if (op == '/') - n1 = num_divide(n1, n2, &failed); - else - n1 = num_modulus(n1, n2, &failed); - if (failed) - return FAIL; - - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = n1; - } - } + // Compute the result. + if (eval_multdiv_number(rettv, &var2, op) == FAIL) + return FAIL; } return OK; diff --git a/src/scriptfile.c b/src/scriptfile.c index 6a6a037e32..711f576c09 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -439,8 +439,8 @@ check_script_symlink(int sid) SCRIPT_ITEM(real_sid)->sn_import_autoload = si->sn_import_autoload; if (si->sn_autoload_prefix != NULL) - SCRIPT_ITEM(real_sid)->sn_autoload_prefix = - vim_strsave(si->sn_autoload_prefix); + SCRIPT_ITEM(real_sid)->sn_autoload_prefix = + vim_strsave(si->sn_autoload_prefix); } } } diff --git a/src/version.c b/src/version.c index 13010a386d..55282ab82b 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 462, /**/ 461, /**/ -- cgit v1.2.3