From a061f34191712df7dde7716705fe0ec074e9758e Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sun, 22 May 2022 19:13:49 +0100 Subject: patch 8.2.5003: cannot do bitwise shifts Problem: Cannot do bitwise shifts. Solution: Add the >> and << operators. (Yegappan Lakshmanan, closes #8457) --- src/vim9expr.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 12 deletions(-) (limited to 'src/vim9expr.c') diff --git a/src/vim9expr.c b/src/vim9expr.c index eaea089f9..c84be874a 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -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( } /* - * expr8: runtime type check / conversion + * 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); /* -- cgit v1.2.1