summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2022-05-22 19:13:49 +0100
committerBram Moolenaar <Bram@vim.org>2022-05-22 19:13:49 +0100
commita061f34191712df7dde7716705fe0ec074e9758e (patch)
treef8a3bf02c826aeb748d12bfa74ead3e9f74573a2 /src/eval.c
parent9b2edfd3bf2f14a1faaee9b62930598a2e77a798 (diff)
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.c163
1 files changed, 139 insertions, 24 deletions
diff --git a/src/eval.c b/src/eval.c
index ac3c998a51..0ac2dfb358 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,