1
0
forked from aniani/vim

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

@@ -1748,7 +1748,7 @@ compile_parenthesis(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return ret;
}
static int compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
static int compile_expr9(char_u **arg, cctx_T *cctx, ppconst_T *ppconst);
/*
* Compile whatever comes after "name" or "name()".
@@ -1909,7 +1909,7 @@ compile_subscript(
// do not look in the next line
cctx->ctx_ufunc->uf_lines.ga_len = 1;
fail = compile_expr8(arg, cctx, ppconst) == FAIL
fail = compile_expr9(arg, cctx, ppconst) == FAIL
|| *skipwhite(*arg) != NUL;
*paren = '(';
--paren_follows_after_expr;
@@ -2143,7 +2143,7 @@ compile_subscript(
* trailing ->name() method call
*/
static int
compile_expr8(
compile_expr9(
char_u **arg,
cctx_T *cctx,
ppconst_T *ppconst)
@@ -2389,10 +2389,10 @@ compile_expr8(
}
/*
* <type>expr8: runtime type check / conversion
* <type>expr9: runtime type check / conversion
*/
static int
compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
compile_expr8(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
type_T *want_type = NULL;
@@ -2417,7 +2417,7 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return FAIL;
}
if (compile_expr8(arg, cctx, ppconst) == FAIL)
if (compile_expr9(arg, cctx, ppconst) == FAIL)
return FAIL;
if (want_type != NULL)
@@ -2444,14 +2444,14 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
* % number modulo
*/
static int
compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
int ppconst_used = ppconst->pp_used;
// get the first expression
if (compile_expr7(arg, cctx, ppconst) == FAIL)
if (compile_expr8(arg, cctx, ppconst) == FAIL)
return FAIL;
/*
@@ -2477,7 +2477,7 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return FAIL;
// get the second expression
if (compile_expr7(arg, cctx, ppconst) == FAIL)
if (compile_expr8(arg, cctx, ppconst) == FAIL)
return FAIL;
if (ppconst->pp_used == ppconst_used + 2
@@ -2522,7 +2522,7 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
* .. string concatenation
*/
static int
compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
char_u *op;
char_u *next;
@@ -2530,7 +2530,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
int ppconst_used = ppconst->pp_used;
// get the first variable
if (compile_expr6(arg, cctx, ppconst) == FAIL)
if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;
/*
@@ -2562,7 +2562,7 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return FAIL;
// get the second expression
if (compile_expr6(arg, cctx, ppconst) == FAIL)
if (compile_expr7(arg, cctx, ppconst) == FAIL)
return FAIL;
if (ppconst->pp_used == ppconst_used + 2
@@ -2620,6 +2620,136 @@ compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return OK;
}
/*
* expr6a >> expr6b
* expr6a << expr6b
*
* Produces instructions:
* OPNR bitwise left or right shift
*/
static int
compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
{
exprtype_T type = EXPR_UNKNOWN;
char_u *p;
char_u *next;
int len = 2;
int ppconst_used = ppconst->pp_used;
typval_T *tv1;
typval_T *tv2;
isn_T *isn;
// get the first variable
if (compile_expr6(arg, cctx, ppconst) == FAIL)
return FAIL;
/*
* Repeat computing, until no "+", "-" or ".." is following.
*/
for (;;)
{
type = EXPR_UNKNOWN;
p = may_peek_next_line(cctx, *arg, &next);
if (p[0] == '<' && p[1] == '<')
type = EXPR_LSHIFT;
else if (p[0] == '>' && p[1] == '>')
type = EXPR_RSHIFT;
if (type == EXPR_UNKNOWN)
return OK;
// Handle a bitwise left or right shift operator
if (ppconst->pp_used == ppconst_used + 1)
{
tv1 = &ppconst->pp_tv[ppconst->pp_used - 1];
if (tv1->v_type != VAR_NUMBER)
{
// left operand should be a number
emsg(_(e_bitshift_ops_must_be_number));
return FAIL;
}
}
else
{
type_T *t = get_type_on_stack(cctx, 0);
if (need_type(t, &t_number, 0, 0, cctx, FALSE, FALSE) == FAIL)
{
emsg(_(e_bitshift_ops_must_be_number));
return FAIL;
}
}
if (next != NULL)
{
*arg = next_line_from_context(cctx, TRUE);
p = skipwhite(*arg);
}
if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[len]))
{
error_white_both(p, len);
return FAIL;
}
// get the second variable
if (may_get_next_line_error(p + len, arg, cctx) == FAIL)
return FAIL;
if (compile_expr6(arg, cctx, ppconst) == FAIL)
return FAIL;
if (ppconst->pp_used == ppconst_used + 2)
{
// Both sides are a constant, compute the result now.
tv2 = &ppconst->pp_tv[ppconst->pp_used - 1];
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_postive));
return FAIL;
}
if (tv2->vval.v_number > MAX_LSHIFT_BITS)
tv1->vval.v_number = 0;
else if (type == EXPR_LSHIFT)
tv1->vval.v_number = tv1->vval.v_number << tv2->vval.v_number;
else
{
tv1->vval.v_number = tv1->vval.v_number >> tv2->vval.v_number;
// clear the topmost sign bit
tv1->vval.v_number &= ~((uvarnumber_T)1 << MAX_LSHIFT_BITS);
}
clear_tv(tv2);
--ppconst->pp_used;
}
else
{
if (need_type(get_type_on_stack(cctx, 0), &t_number, 0, 0, cctx,
FALSE, FALSE) == FAIL)
{
emsg(_(e_bitshift_ops_must_be_number));
return FAIL;
}
generate_ppconst(cctx, ppconst);
isn = generate_instr_drop(cctx, ISN_OPNR, 1);
if (isn == NULL)
return FAIL;
if (isn != NULL)
isn->isn_arg.op.op_type = type;
}
}
return OK;
}
/*
* expr5a == expr5b
* expr5a =~ expr5b
@@ -2652,6 +2782,7 @@ compile_expr4(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
return FAIL;
p = may_peek_next_line(cctx, *arg, &next);
type = get_compare_type(p, &len, &type_is);
/*