patch 8.2.5003: cannot do bitwise shifts

Problem:    Cannot do bitwise shifts.
Solution:   Add the >> and << operators. (Yegappan Lakshmanan, closes #8457)
diff --git a/src/vim9expr.c b/src/vim9expr.c
index eaea089..c84be87 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -1748,7 +1748,7 @@
     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 @@
 		    // 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 @@
  *  trailing ->name()	method call
  */
     static int
-compile_expr8(
+compile_expr9(
 	char_u **arg,
 	cctx_T *cctx,
 	ppconst_T *ppconst)
@@ -2389,10 +2389,10 @@
 }
 
 /*
- * <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 @@
 	    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 @@
  *	%	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 @@
 	    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 @@
  *      ..	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 @@
     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 @@
 	    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
@@ -2621,6 +2621,136 @@
 }
 
 /*
+ * 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
  * expr5a != expr5b
@@ -2652,6 +2782,7 @@
 	return FAIL;
 
     p = may_peek_next_line(cctx, *arg, &next);
+
     type = get_compare_type(p, &len, &type_is);
 
     /*