0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 8.2.5003: cannot do bitwise shifts

Problem:    Cannot do bitwise shifts.
Solution:   Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
This commit is contained in:
Yegappan Lakshmanan
2022-05-22 19:13:49 +01:00
committed by Bram Moolenaar
parent 9b2edfd3bf
commit a061f34191
11 changed files with 554 additions and 160 deletions

View File

@@ -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,