diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2022-05-22 19:13:49 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-05-22 19:13:49 +0100 |
commit | a061f34191712df7dde7716705fe0ec074e9758e (patch) | |
tree | f8a3bf02c826aeb748d12bfa74ead3e9f74573a2 /src/eval.c | |
parent | 9b2edfd3bf2f14a1faaee9b62930598a2e77a798 (diff) | |
download | vim-git-a061f34191712df7dde7716705fe0ec074e9758e.tar.gz |
patch 8.2.5003: cannot do bitwise shiftsv8.2.5003
Problem: Cannot do bitwise shifts.
Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 163 |
1 files changed, 139 insertions, 24 deletions
diff --git a/src/eval.c b/src/eval.c index ac3c998a5..0ac2dfb35 100644 --- a/src/eval.c +++ b/src/eval.c @@ -49,10 +49,11 @@ static int eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg); -static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); -static int eval7t(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg); static int eval7(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); -static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp); +static int eval8(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval9(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int want_string); +static int eval9_leader(typval_T *rettv, int numeric_only, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); @@ -638,7 +639,7 @@ deref_function_name( char_u *name = *arg; ref.v_type = VAR_UNKNOWN; - if (eval7(arg, &ref, evalarg, FALSE) == FAIL) + if (eval9(arg, &ref, evalarg, FALSE) == FAIL) { dictitem_T *v; @@ -2591,7 +2592,7 @@ eval2(char_u **arg, typval_T *rettv, evalarg_T *evalarg) int getnext; /* - * Get the first variable. + * Get the first expression. */ if (eval3(arg, rettv, evalarg) == FAIL) return FAIL; @@ -2717,7 +2718,7 @@ eval3(char_u **arg, typval_T *rettv, evalarg_T *evalarg) int getnext; /* - * Get the first variable. + * Get the first expression. */ if (eval4(arg, rettv, evalarg) == FAIL) return FAIL; @@ -2856,12 +2857,13 @@ eval4(char_u **arg, typval_T *rettv, evalarg_T *evalarg) int type_is = FALSE; /* - * Get the first variable. + * Get the first expression. */ if (eval5(arg, rettv, evalarg) == FAIL) return FAIL; p = eval_next_non_blank(*arg, evalarg, &getnext); + type = get_compare_type(p, &len, &type_is); /* @@ -2991,7 +2993,120 @@ eval_addlist(typval_T *tv1, typval_T *tv2) } /* - * Handle fourth level expression: + * Handle the bitwise left/right shift operator expression: + * var1 << var2 + * var1 >> var2 + * + * "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 +eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) +{ + /* + * Get the first expression. + */ + if (eval6(arg, rettv, evalarg) == FAIL) + return FAIL; + + /* + * Repeat computing, until no '<<' or '>>' is following. + */ + for (;;) + { + char_u *p; + int getnext; + exprtype_T type; + int evaluate; + typval_T var2; + int vim9script; + + p = eval_next_non_blank(*arg, evalarg, &getnext); + if (p[0] == '<' && p[1] == '<') + type = EXPR_LSHIFT; + else if (p[0] == '>' && p[1] == '>') + type = EXPR_RSHIFT; + else + return OK; + + // Handle a bitwise left or right shift operator + if (rettv->v_type != VAR_NUMBER) + { + // left operand should be a number + emsg(_(e_bitshift_ops_must_be_number)); + clear_tv(rettv); + return FAIL; + } + + evaluate = evalarg == NULL ? 0 : (evalarg->eval_flags & EVAL_EVALUATE); + vim9script = in_vim9script(); + if (getnext) + { + *arg = eval_next_line(*arg, evalarg); + p = *arg; + } + else if (evaluate && vim9script && !VIM_ISWHITE(**arg)) + { + error_white_both(*arg, 2); + clear_tv(rettv); + return FAIL; + } + + /* + * Get the second variable. + */ + if (evaluate && vim9script && !IS_WHITE_OR_NUL(p[2])) + { + error_white_both(p, 2); + clear_tv(rettv); + return FAIL; + } + *arg = skipwhite_and_linebreak(p + 2, evalarg); + if (eval6(arg, &var2, evalarg) == FAIL) + { + clear_tv(rettv); + return FAIL; + } + + 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_postive)); + clear_tv(rettv); + clear_tv(&var2); + return FAIL; + } + + if (evaluate) + { + 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 = + rettv->vval.v_number << var2.vval.v_number; + else + { + rettv->vval.v_number = + rettv->vval.v_number >> var2.vval.v_number; + // clear the topmost sign bit + rettv->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS); + } + } + + clear_tv(&var2); + } + + return OK; +} + +/* + * Handle fifth level expression: * + number addition, concatenation of list or blob * - number subtraction * . string concatenation (if script version is 1) @@ -3003,12 +3118,12 @@ eval_addlist(typval_T *tv1, typval_T *tv2) * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) +eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg) { /* - * Get the first variable. + * Get the first expression. */ - if (eval6(arg, rettv, evalarg, FALSE) == FAIL) + if (eval7(arg, rettv, evalarg, FALSE) == FAIL) return FAIL; /* @@ -3086,7 +3201,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) return FAIL; } *arg = skipwhite_and_linebreak(*arg + oplen, evalarg); - if (eval6(arg, &var2, evalarg, !vim9script && op == '.') == FAIL) + if (eval7(arg, &var2, evalarg, !vim9script && op == '.') == FAIL) { clear_tv(rettv); return FAIL; @@ -3221,7 +3336,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) } /* - * Handle fifth level expression: + * Handle sixth level expression: * * number multiplication * / number division * % number modulo @@ -3232,7 +3347,7 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg) * Return OK or FAIL. */ static int -eval6( +eval7( char_u **arg, typval_T *rettv, evalarg_T *evalarg, @@ -3243,9 +3358,9 @@ eval6( #endif /* - * Get the first variable. + * Get the first expression. */ - if (eval7t(arg, rettv, evalarg, want_string) == FAIL) + if (eval8(arg, rettv, evalarg, want_string) == FAIL) return FAIL; /* @@ -3318,7 +3433,7 @@ eval6( return FAIL; } *arg = skipwhite_and_linebreak(*arg + 1, evalarg); - if (eval7t(arg, &var2, evalarg, FALSE) == FAIL) + if (eval8(arg, &var2, evalarg, FALSE) == FAIL) return FAIL; if (evaluate) @@ -3415,7 +3530,7 @@ eval6( * Return OK or FAIL. */ static int -eval7t( +eval8( char_u **arg, typval_T *rettv, evalarg_T *evalarg, @@ -3453,7 +3568,7 @@ eval7t( *arg = skipwhite_and_linebreak(*arg, evalarg); } - res = eval7(arg, rettv, evalarg, want_string); + res = eval9(arg, rettv, evalarg, want_string); if (want_type != NULL && evaluate) { @@ -3642,7 +3757,7 @@ handle_predefined(char_u *s, int len, typval_T *rettv) * Return OK or FAIL. */ static int -eval7( +eval9( char_u **arg, typval_T *rettv, evalarg_T *evalarg, @@ -3720,7 +3835,7 @@ eval7( // "->" follows. if (ret == OK && evaluate && end_leader > start_leader && rettv->v_type != VAR_BLOB) - ret = eval7_leader(rettv, TRUE, start_leader, &end_leader); + ret = eval9_leader(rettv, TRUE, start_leader, &end_leader); break; /* @@ -3920,19 +4035,19 @@ eval7( * Apply logical NOT and unary '-', from right to left, ignore '+'. */ if (ret == OK && evaluate && end_leader > start_leader) - ret = eval7_leader(rettv, FALSE, start_leader, &end_leader); + ret = eval9_leader(rettv, FALSE, start_leader, &end_leader); --recurse; return ret; } /* - * Apply the leading "!" and "-" before an eval7 expression to "rettv". + * Apply the leading "!" and "-" before an eval9 expression to "rettv". * When "numeric_only" is TRUE only handle "+" and "-". * Adjusts "end_leaderp" until it is at "start_leader". */ static int -eval7_leader( +eval9_leader( typval_T *rettv, int numeric_only, char_u *start_leader, |