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/testdir/test_expr.vim b/src/testdir/test_expr.vim
index 0b6b57e..24daeb6 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -946,4 +946,66 @@
   call v9.CheckDefAndScriptSuccess(lines)
 endfunc
 
+" Test for bitwise left and right shift (<< and >>)
+func Test_bitwise_shift()
+  let lines =<< trim END
+    call assert_equal(16, 1 << 4)
+    call assert_equal(2, 16 >> 3)
+    call assert_equal(0, 0 << 2)
+    call assert_equal(0, 0 >> 4)
+    call assert_equal(3, 3 << 0)
+    call assert_equal(3, 3 >> 0)
+    call assert_equal(0, 0 >> 4)
+    call assert_equal(0, 999999 >> 100)
+    call assert_equal(0, 999999 << 100)
+    VAR a = 8
+    VAR b = 2
+    call assert_equal(2, a >> b)
+    call assert_equal(32, a << b)
+    #" operator precedence
+    call assert_equal(48, 1 + 2 << 5 - 1)
+    call assert_equal(3, 8 + 4 >> 4 - 2)
+    call assert_true(1 << 2 < 1 << 3)
+    call assert_true(1 << 4 > 1 << 3)
+    VAR val = 0
+    for i in range(0, v:numbersize - 2)
+        LET val = or(val, 1 << i)
+    endfor
+    call assert_equal(v:numbermax, val)
+    LET val = v:numbermax
+    for i in range(0, v:numbersize - 2)
+        LET val = and(val, invert(1 << i))
+    endfor
+    call assert_equal(0, val)
+    #" multiple operators
+    call assert_equal(16, 1 << 2 << 2)
+    call assert_equal(4, 64 >> 2 >> 2)
+    call assert_true(1 << 2 << 2 == 256 >> 2 >> 2)
+  END
+  call v9.CheckLegacyAndVim9Success(lines)
+
+  call v9.CheckLegacyAndVim9Failure(['VAR v = 2 << -1'], ['E1283:', 'E1283:', 'E1283:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR a = 2', 'VAR b = -1', 'VAR v = a << b'], ['E1283:', 'E1283:', 'E1283:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = "8" >> 2'], ['E1282:', 'E1282:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << "2"'], ['E1282:', 'E1282:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR a = "8"', 'VAR b = 2', 'VAR v = a << b'], ['E1282:', 'E1012:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR a = 8', 'VAR b = "2"', 'VAR v = a >> b'], ['E1282:', 'E1012:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = ![] << 1'], ['E745:', 'E1012:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 << ![]'], ['E745:', 'E1012:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = ![] >> 1'], ['E745:', 'E1012:', 'E1282:'])
+  call v9.CheckLegacyAndVim9Failure(['VAR v = 1 >> ![]'], ['E745:', 'E1012:', 'E1282:'])
+  call v9.CheckDefAndScriptFailure(['echo 1<< 2'], ['E1004:', 'E1004:'])
+  call v9.CheckDefAndScriptFailure(['echo 1 <<2'], ['E1004:', 'E1004:'])
+  call v9.CheckDefAndScriptFailure(['echo 1>> 2'], ['E1004:', 'E1004:'])
+  call v9.CheckDefAndScriptFailure(['echo 1 >>2'], ['E1004:', 'E1004:'])
+
+  let lines =<< trim END
+     var a = 1
+             <<
+             4
+     assert_equal(16, a)
+  END
+  call v9.CheckDefAndScriptSuccess(lines)
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 7860495..c1800c3 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -2864,4 +2864,31 @@
         instr)
 enddef
 
+def BitShift()
+  var a = 1 << 2
+  var b = 8 >> 1
+  var c = a << b
+  var d = b << a
+enddef
+
+def Test_disassemble_bitshift()
+  var instr = execute('disassemble BitShift')
+  assert_match('BitShift\_s*' ..
+               'var a = 1 << 2\_s*' ..
+               '0 STORE 4 in $0\_s*' ..
+               'var b = 8 >> 1\_s*' ..
+               '1 STORE 4 in $1\_s*' ..
+               'var c = a << b\_s*' ..
+               '2 LOAD $0\_s*' ..
+               '3 LOAD $1\_s*' ..
+               '4 OPNR <<\_s*' ..
+               '5 STORE $2\_s*' ..
+               'var d = b << a\_s*' ..
+               '6 LOAD $1\_s*' ..
+               '7 LOAD $0\_s*' ..
+               '8 OPNR <<\_s*' ..
+               '9 STORE $3\_s*' ..
+               '10 RETURN void', instr)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index 401ab07..df65d72 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -1483,8 +1483,13 @@
   endif
 endfunc
 
+" test bitwise left and right shift operators
+" The tests for this is in test_expr.vim (Test_bitwise_shift)
+" def Test_expr5()
+" enddef
+
 " test addition, subtraction, concatenation
-def Test_expr5()
+def Test_expr6()
   var lines =<< trim END
       assert_equal(66, 60 + 6)
       assert_equal(70, 60 +
@@ -1549,7 +1554,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr5_vim9script()
+def Test_expr6_vim9script()
   # check line continuation
   var lines =<< trim END
       var name = 11
@@ -1698,7 +1703,7 @@
   endfor
 enddef
 
-def Test_expr5_vim9script_channel()
+def Test_expr6_vim9script_channel()
   if !has('channel')
     MissingFeature 'channel'
   else
@@ -1713,7 +1718,7 @@
   endif
 enddef
 
-def Test_expr5_float()
+def Test_expr6_float()
   if !has('float')
     MissingFeature 'float'
   else
@@ -1741,7 +1746,7 @@
   endif
 enddef
 
-func Test_expr5_fails()
+func Test_expr6_fails()
   let msg = "White space required before and after '+'"
   call v9.CheckDefAndScriptFailure(["var x = 1+2"], msg, 1)
   call v9.CheckDefAndScriptFailure(["var x = 1 +2"], msg, 1)
@@ -1780,14 +1785,14 @@
   call v9.CheckDefAndScriptFailure(['var x = 1 + false'], ['E1051:', 'E1138:'], 1)
 endfunc
 
-func Test_expr5_fails_channel()
+func Test_expr6_fails_channel()
   CheckFeature channel
 
   call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_job()"], ['E1105:', 'E908:'], 1)
   call v9.CheckDefAndScriptFailure(["var x = 'a' .. test_null_channel()"], ['E1105:', 'E908:'], 1)
 endfunc
 
-def Test_expr5_list_add()
+def Test_expr6_list_add()
   var lines =<< trim END
       # concatenating two lists with same member types is OK
       var d = {}
@@ -1818,7 +1823,7 @@
 enddef
 
 " test multiply, divide, modulo
-def Test_expr6()
+def Test_expr7()
   var lines =<< trim END
       assert_equal(36, 6 * 6)
       assert_equal(24, 6 *
@@ -1890,7 +1895,7 @@
   v9.CheckDefExecAndScriptFailure(lines, 'E1154', 2)
 enddef
 
-def Test_expr6_vim9script()
+def Test_expr7_vim9script()
   # check line continuation
   var lines =<< trim END
       var name = 11
@@ -1942,7 +1947,7 @@
   v9.CheckDefAndScriptFailure(lines, 'E1004:', 1)
 enddef
 
-def Test_expr6_float()
+def Test_expr7_float()
   if !has('float')
     MissingFeature 'float'
   else
@@ -1975,7 +1980,7 @@
   endif
 enddef
 
-func Test_expr6_fails()
+func Test_expr7_fails()
   let msg = "White space required before and after '*'"
   call v9.CheckDefAndScriptFailure(["var x = 1*2"], msg, 1)
   call v9.CheckDefAndScriptFailure(["var x = 1 *2"], msg, 1)
@@ -2019,7 +2024,7 @@
   endfor
 endfunc
 
-func Test_expr6_float_fails()
+func Test_expr7_float_fails()
   CheckFeature float
   call v9.CheckDefAndScriptFailure(["var x = 1.0 % 2"], ['E1035:', 'E804:'], 1)
 endfunc
@@ -2053,7 +2058,7 @@
 let $TESTVAR = 'testvar'
 
 " type casts
-def Test_expr7()
+def Test_expr8()
   var lines =<< trim END
       var ls: list<string> = ['a', <string>g:string_empty]
       var ln: list<number> = [<number>g:anint, <number>g:thefour]
@@ -2079,7 +2084,7 @@
 enddef
 
 " test low level expression
-def Test_expr8_number()
+def Test_expr9_number()
   # number constant
   var lines =<< trim END
       assert_equal(0, 0)
@@ -2092,7 +2097,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_float()
+def Test_expr9_float()
   # float constant
   if !has('float')
     MissingFeature 'float'
@@ -2107,7 +2112,7 @@
   endif
 enddef
 
-def Test_expr8_blob()
+def Test_expr9_blob()
   # blob constant
   var lines =<< trim END
       assert_equal(g:blob_empty, 0z)
@@ -2139,7 +2144,7 @@
   v9.CheckDefAndScriptFailure(["var x = 0z123"], 'E973:', 1)
 enddef
 
-def Test_expr8_string()
+def Test_expr9_string()
   # string constant
   var lines =<< trim END
       assert_equal(g:string_empty, '')
@@ -2180,7 +2185,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_vimvar()
+def Test_expr9_vimvar()
   v:errors = []
   var errs: list<string> = v:errors
   v9.CheckDefFailure(['var errs: list<number> = v:errors'], 'E1012:')
@@ -2205,7 +2210,7 @@
   bwipe!
 enddef
 
-def Test_expr8_special()
+def Test_expr9_special()
   # special constant
   var lines =<< trim END
       assert_equal(g:special_true, true)
@@ -2242,7 +2247,7 @@
   v9.CheckDefAndScriptFailure(['v:none = 22'], 'E46:', 1)
 enddef
 
-def Test_expr8_list()
+def Test_expr9_list()
   # list
   var lines =<< trim END
       assert_equal(g:list_empty, [])
@@ -2320,7 +2325,7 @@
   v9.CheckDefAndScriptFailure(lines + ['echo numbers[a :b]'], 'E1004:', 4)
 enddef
 
-def Test_expr8_list_vim9script()
+def Test_expr9_list_vim9script()
   var lines =<< trim END
       var l = [
 		11,
@@ -2408,7 +2413,7 @@
             x == 2
 enddef
 
-def Test_expr8_lambda()
+def Test_expr9_lambda()
   var lines =<< trim END
       var La = () => 'result'
       # comment
@@ -2494,7 +2499,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_lambda_block()
+def Test_expr9_lambda_block()
   var lines =<< trim END
       var Func = (s: string): string => {
                       return 'hello ' .. s
@@ -2574,7 +2579,7 @@
             x == 2
 enddef
 
-def Test_expr8_new_lambda()
+def Test_expr9_new_lambda()
   var lines =<< trim END
       var La = () => 'result'
       assert_equal('result', La())
@@ -2659,7 +2664,7 @@
   v9.CheckDefAndScriptFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
 enddef
 
-def Test_expr8_lambda_vim9script()
+def Test_expr9_lambda_vim9script()
   var lines =<< trim END
       var v = 10->((a) =>
 	    a
@@ -2678,7 +2683,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8funcref()
+def Test_expr9funcref()
   var lines =<< trim END
       def RetNumber(): number
         return 123
@@ -2730,7 +2735,7 @@
 let g:test_space_dict = {'': 'empty', ' ': 'space'}
 let g:test_hash_dict = #{one: 1, two: 2}
 
-def Test_expr8_dict()
+def Test_expr9_dict()
   # dictionary
   var lines =<< trim END
       assert_equal(g:dict_empty, {})
@@ -2850,7 +2855,7 @@
   v9.CheckDefExecAndScriptFailure(['{}[getftype("file")]'], 'E716: Key not present in Dictionary: ""', 1)
 enddef
 
-def Test_expr8_dict_vim9script()
+def Test_expr9_dict_vim9script()
   var lines =<< trim END
       var d = {
 		['one']:
@@ -2981,7 +2986,7 @@
   v9.CheckScriptSuccess(lines)
 enddef
 
-def Test_expr8_dict_in_block()
+def Test_expr9_dict_in_block()
   var lines =<< trim END
       vim9script
       command MyCommand {
@@ -3004,7 +3009,7 @@
   delcommand YourCommand
 enddef
 
-def Test_expr8_call_2bool()
+def Test_expr9_call_2bool()
   var lines =<< trim END
       vim9script
 
@@ -3052,7 +3057,7 @@
   v9.CheckDefExecAndScriptFailure(["var d: dict<number>", "d = g:list_empty"], 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2)
 enddef
 
-def Test_expr8_any_index_slice()
+def Test_expr9_any_index_slice()
   var lines =<< trim END
     # getting the one member should clear the list only after getting the item
     assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
@@ -3223,7 +3228,7 @@
   b:someVar = &fdm
 enddef
 
-def Test_expr8_option()
+def Test_expr9_option()
   var lines =<< trim END
       # option
       set ts=11
@@ -3250,7 +3255,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_environment()
+def Test_expr9_environment()
   var lines =<< trim END
       # environment variable
       assert_equal('testvar', $TESTVAR)
@@ -3262,7 +3267,7 @@
   v9.CheckDefAndScriptFailure(["$"], ['E1002:', 'E15:'], 1)
 enddef
 
-def Test_expr8_register()
+def Test_expr9_register()
   var lines =<< trim END
       @a = 'register a'
       assert_equal('register a', @a)
@@ -3288,7 +3293,7 @@
 enddef
 
 " This is slow when run under valgrind.
-def Test_expr8_namespace()
+def Test_expr9_namespace()
   var lines =<< trim END
       g:some_var = 'some'
       assert_equal('some', get(g:, 'some_var'))
@@ -3317,7 +3322,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_namespace_loop_def()
+def Test_expr9_namespace_loop_def()
   var lines =<< trim END
       # check using g: in a for loop more than DO_NOT_FREE_CNT times
       var exists = 0
@@ -3336,8 +3341,8 @@
 enddef
 
 " NOTE: this is known to be slow.  To skip use:
-"   :let $TEST_SKIP_PAT = 'Test_expr8_namespace_loop_script'
-def Test_expr8_namespace_loop_script()
+"   :let $TEST_SKIP_PAT = 'Test_expr9_namespace_loop_script'
+def Test_expr9_namespace_loop_script()
   var lines =<< trim END
       vim9script
       # check using g: in a for loop more than DO_NOT_FREE_CNT times
@@ -3356,7 +3361,7 @@
   v9.CheckScriptSuccess(lines)
 enddef
 
-def Test_expr8_parens()
+def Test_expr9_parens()
   # (expr)
   var lines =<< trim END
       assert_equal(4, (6 * 4) / 6)
@@ -3403,7 +3408,7 @@
   unlet g:result
 enddef
 
-def Test_expr8_negate_add()
+def Test_expr9_negate_add()
   var lines =<< trim END
       assert_equal(-99, -99)
       assert_equal(-99, - 99)
@@ -3452,7 +3457,7 @@
   legacy return #{key: 'ok'}.key
 enddef
 
-def Test_expr8_legacy_script()
+def Test_expr9_legacy_script()
   var lines =<< trim END
       let s:legacy = 'legacy'
       def GetLocal(): string
@@ -3495,7 +3500,7 @@
   return arg
 enddef
 
-def Test_expr8_call()
+def Test_expr9_call()
   var lines =<< trim END
       assert_equal('yes', 'yes'->g:Echo())
       assert_equal(true, !range(5)->empty())
@@ -3518,7 +3523,7 @@
   return 'existing'
 enddef
 
-def Test_expr8_call_global()
+def Test_expr9_call_global()
   assert_equal('existing', g:ExistingGlobal())
 
   def g:DefinedLater(): string
@@ -3532,7 +3537,7 @@
   v9.CheckDefAndScriptFailure(lines, 'E117: Unknown function: ExistingGlobal')
 enddef
 
-def Test_expr8_autoload_var()
+def Test_expr9_autoload_var()
   var auto_lines =<< trim END
       let autofile#var = 'found'
   END
@@ -3555,7 +3560,7 @@
   delete('Xruntime', 'rf')
 enddef
 
-def Test_expr8_call_autoload()
+def Test_expr9_call_autoload()
   var auto_lines =<< trim END
       def g:some#func(): string
 	return 'found'
@@ -3572,7 +3577,7 @@
   delete('Xruntime', 'rf')
 enddef
 
-def Test_expr8_method_call()
+def Test_expr9_method_call()
   var lines =<< trim END
       new
       setline(1, ['first', 'last'])
@@ -3663,7 +3668,7 @@
   v9.CheckDefFailure(lines, 'E15: Invalid expression: "->SetList[0]x()"')
 enddef
 
-def Test_expr8_method_call_linebreak()
+def Test_expr9_method_call_linebreak()
   # this was giving an error when skipping over the expression
   var lines =<< trim END
       vim9script
@@ -3679,7 +3684,7 @@
   v9.CheckScriptSuccess(lines)
 enddef
 
-def Test_expr8_method_call_import()
+def Test_expr9_method_call_import()
   var lines =<< trim END
       vim9script
       export def Square(items: list<number>): list<number>
@@ -3714,7 +3719,7 @@
 enddef
 
 
-def Test_expr8_not()
+def Test_expr9_not()
   var lines =<< trim END
       assert_equal(true, !'')
       assert_equal(true, ![])
@@ -3766,7 +3771,7 @@
 
 let g:anumber = 42
 
-def Test_expr8_negate()
+def Test_expr9_negate()
   var lines =<< trim END
       var nr = 1
       assert_equal(-1, -nr)
@@ -3775,7 +3780,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-func Test_expr8_fails()
+func Test_expr9_fails()
   call v9.CheckDefFailure(["var x = (12"], "E1097:", 3)
   call v9.CheckScriptFailure(['vim9script', "var x = (12"], 'E110:', 2)
 
@@ -3837,7 +3842,7 @@
   return a:one .. a:two
 endfunc
 
-def Test_expr8_trailing()
+def Test_expr9_trailing()
   var lines =<< trim END
       # user function call
       assert_equal(123, g:CallMe(123))
@@ -3873,7 +3878,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_string_subscript()
+def Test_expr9_string_subscript()
   var lines =<< trim END
     var text = 'abcdef'
     assert_equal('f', text[-1])
@@ -3972,7 +3977,7 @@
   v9.CheckDefAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "2"'], 1)
 enddef
 
-def Test_expr8_list_subscript()
+def Test_expr9_list_subscript()
   var lines =<< trim END
       var list = [0, 1, 2, 3, 4]
       assert_equal(0, list[0])
@@ -4015,7 +4020,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_dict_subscript()
+def Test_expr9_dict_subscript()
   var lines =<< trim END
       var l = [{lnum: 2}, {lnum: 1}]
       var res = l[0].lnum > l[1].lnum
@@ -4036,7 +4041,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_blob_subscript()
+def Test_expr9_blob_subscript()
   var lines =<< trim END
       var b = 0z112233
       assert_equal(0x11, b[0])
@@ -4048,7 +4053,7 @@
   v9.CheckDefAndScriptSuccess(lines)
 enddef
 
-def Test_expr8_funcref_subscript()
+def Test_expr9_funcref_subscript()
   var lines =<< trim END
       var l = function('len')("abc")
       assert_equal(3, l)
@@ -4058,7 +4063,7 @@
   v9.CheckDefAndScriptFailure(["var l = function('len')(xxx)"], ['E1001: Variable not found: xxx', 'E121: Undefined variable: xxx'], 1)
 enddef
 
-def Test_expr8_subscript_linebreak()
+def Test_expr9_subscript_linebreak()
   var lines =<< trim END
       var range = range(
                     3)
@@ -4101,7 +4106,7 @@
   v9.CheckDefAndScriptFailure(lines, ['E1127:', 'E116:'], 2)
 enddef
 
-func Test_expr8_trailing_fails()
+func Test_expr9_trailing_fails()
   call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8))'], 'E107:', 2)
   call v9.CheckDefAndScriptFailure(['var l = [2]', 'l->((ll) => add(ll, 8)) ()'], 'E274:', 2)
 endfunc