diff options
Diffstat (limited to 'src/testdir/test_vim9_assign.vim')
-rw-r--r-- | src/testdir/test_vim9_assign.vim | 1546 |
1 files changed, 1546 insertions, 0 deletions
diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim new file mode 100644 index 0000000..55beffa --- /dev/null +++ b/src/testdir/test_vim9_assign.vim @@ -0,0 +1,1546 @@ +" Test Vim9 assignments + +source check.vim +source vim9.vim + +let s:appendToMe = 'xxx' +let s:addToMe = 111 +let g:existing = 'yes' +let g:inc_counter = 1 +let $SOME_ENV_VAR = 'some' +let g:alist = [7] +let g:astring = 'text' + +def Test_assignment_bool() + var bool1: bool = true + assert_equal(v:true, bool1) + var bool2: bool = false + assert_equal(v:false, bool2) + + var bool3: bool = 0 + assert_equal(false, bool3) + var bool4: bool = 1 + assert_equal(true, bool4) + + var bool5: bool = 1 && true + assert_equal(true, bool5) + var bool6: bool = 0 && 1 + assert_equal(false, bool6) + var bool7: bool = 0 || 1 && true + assert_equal(true, bool7) + + var lines =<< trim END + vim9script + def GetFlag(): bool + var flag: bool = 1 + return flag + enddef + var flag: bool = GetFlag() + assert_equal(true, flag) + flag = 0 + assert_equal(false, flag) + flag = 1 + assert_equal(true, flag) + flag = 1 || true + assert_equal(true, flag) + flag = 1 && false + assert_equal(false, flag) + + var cp: bool = &cp + var fen: bool = &l:fen + END + CheckScriptSuccess(lines) + CheckDefAndScriptFailure(['var x: bool = 2'], 'E1012:') + CheckDefAndScriptFailure(['var x: bool = -1'], 'E1012:') + CheckDefAndScriptFailure(['var x: bool = [1]'], 'E1012:') + CheckDefAndScriptFailure(['var x: bool = {}'], 'E1012:') + CheckDefAndScriptFailure(['var x: bool = "x"'], 'E1012:') + + CheckDefAndScriptFailure(['var x: bool = "x"', '', 'eval 0'], 'E1012:', 1) +enddef + +def Test_syntax() + var name = 234 + var other: list<string> = ['asdf'] +enddef + +def Test_assignment() + CheckDefFailure(['var x:string'], 'E1069:') + CheckDefFailure(['var x:string = "x"'], 'E1069:') + CheckDefFailure(['var a:string = "x"'], 'E1069:') + CheckDefFailure(['var lambda = () => "lambda"'], 'E704:') + CheckScriptFailure(['var x = "x"'], 'E1124:') + + var nr: number = 1234 + CheckDefFailure(['var nr: number = "asdf"'], 'E1012:') + + var a: number = 6 #comment + assert_equal(6, a) + + if has('channel') + var chan1: channel + assert_equal('fail', ch_status(chan1)) + + var job1: job + assert_equal('fail', job_status(job1)) + + # calling job_start() is in test_vim9_fails.vim, it causes leak reports + endif + if has('float') + var float1: float = 3.4 + endif + var Funky1: func + var Funky2: func = function('len') + var Party2: func = funcref('g:Test_syntax') + + g:newvar = 'new' #comment + assert_equal('new', g:newvar) + + assert_equal('yes', g:existing) + g:existing = 'no' + assert_equal('no', g:existing) + + v:char = 'abc' + assert_equal('abc', v:char) + + $ENVVAR = 'foobar' + assert_equal('foobar', $ENVVAR) + $ENVVAR = '' + + var lines =<< trim END + vim9script + $ENVVAR = 'barfoo' + assert_equal('barfoo', $ENVVAR) + $ENVVAR = '' + END + CheckScriptSuccess(lines) + + s:appendToMe ..= 'yyy' + assert_equal('xxxyyy', s:appendToMe) + s:addToMe += 222 + assert_equal(333, s:addToMe) + s:newVar = 'new' + assert_equal('new', s:newVar) + + set ts=7 + var ts: number = &ts + assert_equal(7, ts) + &ts += 1 + assert_equal(8, &ts) + &ts -= 3 + assert_equal(5, &ts) + &ts *= 2 + assert_equal(10, &ts) + &ts /= 3 + assert_equal(3, &ts) + set ts=10 + &ts %= 4 + assert_equal(2, &ts) + + if has('float') + var f100: float = 100.0 + f100 /= 5 + assert_equal(20.0, f100) + + var f200: float = 200.0 + f200 /= 5.0 + assert_equal(40.0, f200) + + CheckDefFailure(['var nr: number = 200', 'nr /= 5.0'], 'E1012:') + endif + + lines =<< trim END + &ts = 6 + &ts += 3 + assert_equal(9, &ts) + + &l:ts = 6 + assert_equal(6, &ts) + &l:ts += 2 + assert_equal(8, &ts) + + &g:ts = 6 + assert_equal(6, &g:ts) + &g:ts += 2 + assert_equal(8, &g:ts) + + &number = true + assert_equal(true, &number) + &number = 0 + assert_equal(false, &number) + &number = 1 + assert_equal(true, &number) + &number = false + assert_equal(false, &number) + END + CheckDefAndScriptSuccess(lines) + + CheckDefFailure(['¬ex += 3'], 'E113:') + CheckDefFailure(['&ts ..= "xxx"'], 'E1019:') + CheckDefFailure(['&ts = [7]'], 'E1012:') + CheckDefExecFailure(['&ts = g:alist'], 'E1012: Type mismatch; expected number but got list<number>') + CheckDefFailure(['&ts = "xx"'], 'E1012:') + CheckDefExecFailure(['&ts = g:astring'], 'E1012: Type mismatch; expected number but got string') + CheckDefFailure(['&path += 3'], 'E1012:') + CheckDefExecFailure(['&bs = "asdf"'], 'E474:') + # test freeing ISN_STOREOPT + CheckDefFailure(['&ts = 3', 'var asdf'], 'E1022:') + &ts = 8 + + lines =<< trim END + var save_TI = &t_TI + &t_TI = '' + assert_equal('', &t_TI) + &t_TI = 'xxx' + assert_equal('xxx', &t_TI) + &t_TI = save_TI + END + CheckDefAndScriptSuccess(lines) + + CheckDefFailure(['&t_TI = 123'], 'E1012:') + CheckScriptFailure(['vim9script', '&t_TI = 123'], 'E928:') + + CheckDefFailure(['var s:var = 123'], 'E1101:') + CheckDefFailure(['var s:var: number'], 'E1101:') + + lines =<< trim END + vim9script + def SomeFunc() + s:var = 123 + enddef + defcompile + END + CheckScriptFailure(lines, 'E1089:') + + g:inc_counter += 1 + assert_equal(2, g:inc_counter) + + $SOME_ENV_VAR ..= 'more' + assert_equal('somemore', $SOME_ENV_VAR) + CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:') + CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1012:') + + lines =<< trim END + @c = 'areg' + @c ..= 'add' + assert_equal('aregadd', @c) + END + CheckDefAndScriptSuccess(lines) + + CheckDefFailure(['@a += "more"'], 'E1051:') + CheckDefFailure(['@a += 123'], 'E1012:') + + v:errmsg = 'none' + v:errmsg ..= 'again' + assert_equal('noneagain', v:errmsg) + CheckDefFailure(['v:errmsg += "more"'], 'E1051:') + CheckDefFailure(['v:errmsg += 123'], 'E1012:') + + var text =<< trim END + some text + END +enddef + +def Test_assign_unpack() + var lines =<< trim END + var v1: number + var v2: number + [v1, v2] = [1, 2] + assert_equal(1, v1) + assert_equal(2, v2) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = + END + CheckDefFailure(lines, 'E1097:', 5) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = xxx + END + CheckDefFailure(lines, 'E1001:', 3) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = popup_clear() + END + CheckDefFailure(lines, 'E1031:', 3) + + lines =<< trim END + [v1, v2] = [1, 2] + END + CheckDefFailure(lines, 'E1089', 1) + CheckScriptFailure(['vim9script'] + lines, 'E1089', 2) + + lines =<< trim END + var v1: number + var v2: number + [v1, v2] = '' + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected list<any> but got string', 3) +enddef + +def Test_assign_linebreak() + var nr: number + nr = + 123 + assert_equal(123, nr) + + var n2: number + [nr, n2] = + [12, 34] + assert_equal(12, nr) + assert_equal(34, n2) + + CheckDefFailure(["var x = #"], 'E1097:', 3) +enddef + +def Test_assign_index() + # list of list + var l1: list<number> + l1[0] = 123 + assert_equal([123], l1) + + var l2: list<list<number>> + l2[0] = [] + l2[0][0] = 123 + assert_equal([[123]], l2) + + var l3: list<list<list<number>>> + l3[0] = [] + l3[0][0] = [] + l3[0][0][0] = 123 + assert_equal([[[123]]], l3) + + var lines =<< trim END + var l3: list<list<number>> + l3[0] = [] + l3[0][0] = [] + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3) + + # dict of dict + var d1: dict<number> + d1.one = 1 + assert_equal({one: 1}, d1) + + var d2: dict<dict<number>> + d2.one = {} + d2.one.two = 123 + assert_equal({one: {two: 123}}, d2) + + var d3: dict<dict<dict<number>>> + d3.one = {} + d3.one.two = {} + d3.one.two.three = 123 + assert_equal({one: {two: {three: 123}}}, d3) + + lines =<< trim END + var d3: dict<dict<number>> + d3.one = {} + d3.one.two = {} + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3) + + lines =<< trim END + var lines: list<string> + lines['a'] = 'asdf' + END + CheckDefFailure(lines, 'E1012:', 2) + + lines =<< trim END + var lines: string + lines[9] = 'asdf' + END + CheckDefFailure(lines, 'E1141:', 2) + + # list of dict + var ld: list<dict<number>> + ld[0] = {} + ld[0].one = 123 + assert_equal([{one: 123}], ld) + + lines =<< trim END + var ld: list<dict<number>> + ld[0] = [] + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2) + + # dict of list + var dl: dict<list<number>> + dl.one = [] + dl.one[0] = 123 + assert_equal({one: [123]}, dl) + + lines =<< trim END + var dl: dict<list<number>> + dl.one = {} + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2) +enddef + +def Test_extend_list() + var lines =<< trim END + vim9script + var l: list<number> + l += [123] + assert_equal([123], l) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var list: list<string> + extend(list, ['x']) + assert_equal(['x'], list) + END + CheckScriptSuccess(lines) + + # appending to NULL list from a function + lines =<< trim END + vim9script + var list: list<string> + def Func() + list += ['a', 'b'] + enddef + Func() + assert_equal(['a', 'b'], list) + END + CheckScriptSuccess(lines) + lines =<< trim END + vim9script + var list: list<string> + def Func() + extend(list, ['x', 'b']) + enddef + Func() + assert_equal(['x', 'b'], list) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var l: list<string> = test_null_list() + extend(l, ['x']) + assert_equal(['x'], l) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + extend(test_null_list(), ['x']) + END + CheckScriptFailure(lines, 'E1134:', 2) +enddef + +def Test_extend_dict() + var lines =<< trim END + vim9script + var d: dict<number> + extend(d, {a: 1}) + assert_equal({a: 1}, d) + + var d2: dict<number> + d2['one'] = 1 + assert_equal({one: 1}, d2) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var d: dict<string> = test_null_dict() + extend(d, {a: 'x'}) + assert_equal({a: 'x'}, d) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + extend(test_null_dict(), {a: 'x'}) + END + CheckScriptFailure(lines, 'E1133:', 2) +enddef + +def Test_single_letter_vars() + # single letter variables + var a: number = 123 + a = 123 + assert_equal(123, a) + var b: number + b = 123 + assert_equal(123, b) + var g: number + g = 123 + assert_equal(123, g) + var s: number + s = 123 + assert_equal(123, s) + var t: number + t = 123 + assert_equal(123, t) + var v: number + v = 123 + assert_equal(123, v) + var w: number + w = 123 + assert_equal(123, w) +enddef + +def Test_vim9_single_char_vars() + var lines =<< trim END + vim9script + + # single character variable declarations work + var a: string + var b: number + var l: list<any> + var s: string + var t: number + var v: number + var w: number + + # script-local variables can be used without s: prefix + a = 'script-a' + b = 111 + l = [1, 2, 3] + s = 'script-s' + t = 222 + v = 333 + w = 444 + + assert_equal('script-a', a) + assert_equal(111, b) + assert_equal([1, 2, 3], l) + assert_equal('script-s', s) + assert_equal(222, t) + assert_equal(333, v) + assert_equal(444, w) + END + writefile(lines, 'Xsinglechar') + source Xsinglechar + delete('Xsinglechar') +enddef + +def Test_assignment_list() + var list1: list<bool> = [false, true, false] + var list2: list<number> = [1, 2, 3] + var list3: list<string> = ['sdf', 'asdf'] + var list4: list<any> = ['yes', true, 1234] + var list5: list<blob> = [0z01, 0z02] + + var listS: list<string> = [] + var listN: list<number> = [] + + assert_equal([1, 2, 3], list2) + list2[-1] = 99 + assert_equal([1, 2, 99], list2) + list2[-2] = 88 + assert_equal([1, 88, 99], list2) + list2[-3] = 77 + assert_equal([77, 88, 99], list2) + list2 += [100] + assert_equal([77, 88, 99, 100], list2) + + list3 += ['end'] + assert_equal(['sdf', 'asdf', 'end'], list3) + + CheckDefExecFailure(['var ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') + CheckDefExecFailure(['var [v1, v2] = [1, 2]'], 'E1092:') + + # type becomes list<any> + var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] + + var lines =<< trim END + var d = {dd: test_null_list()} + d.dd[0] = 0 + END + CheckDefExecFailure(lines, 'E1147:', 2) +enddef + +def Test_assignment_list_any_index() + var l: list<number> = [1, 2] + for [x, y, _] + in [[0, 1, ''], [1, 3, '']] + l[x] = l[x] + y + endfor + assert_equal([2, 5], l) +enddef + +def Test_assignment_list_vim9script() + var lines =<< trim END + vim9script + var v1: number + var v2: number + var v3: number + [v1, v2, v3] = [1, 2, 3] + assert_equal([1, 2, 3], [v1, v2, v3]) + END + CheckScriptSuccess(lines) +enddef + +def Test_assignment_dict() + var dict1: dict<bool> = {one: false, two: true} + var dict2: dict<number> = {one: 1, two: 2} + var dict3: dict<string> = {key: 'value'} + var dict4: dict<any> = {one: 1, two: '2'} + var dict5: dict<blob> = {one: 0z01, two: 0z02} + + # overwrite + dict3['key'] = 'another' + assert_equal(dict3, {key: 'another'}) + dict3.key = 'yet another' + assert_equal(dict3, {key: 'yet another'}) + + # member "any" can also be a dict and assigned to + var anydict: dict<any> = {nest: {}, nr: 0} + anydict.nest['this'] = 123 + anydict.nest.that = 456 + assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict) + + var lines =<< trim END + var dd = {} + dd.two = 2 + assert_equal({two: 2}, dd) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var d = {dd: {}} + d.dd[0] = 2 + d.dd['x'] = 3 + d.dd.y = 4 + assert_equal({dd: {0: 2, x: 3, y: 4}}, d) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var dd = {one: 1} + dd.one) = 2 + END + CheckDefFailure(lines, 'E488:', 2) + + lines =<< trim END + var dd = {one: 1} + var dd.one = 2 + END + CheckDefAndScriptFailure(lines, 'E1017:', 2) + + # empty key can be used + var dd = {} + dd[""] = 6 + assert_equal({['']: 6}, dd) + + # type becomes dict<any> + var somedict = rand() > 0 ? {a: 1, b: 2} : {a: 'a', b: 'b'} + + # assignment to script-local dict + lines =<< trim END + vim9script + var test: dict<any> = {} + def FillDict(): dict<any> + test['a'] = 43 + return test + enddef + assert_equal({a: 43}, FillDict()) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var test: dict<any> + def FillDict(): dict<any> + test['a'] = 43 + return test + enddef + FillDict() + assert_equal({a: 43}, test) + END + CheckScriptSuccess(lines) + + # assignment to global dict + lines =<< trim END + vim9script + g:test = {} + def FillDict(): dict<any> + g:test['a'] = 43 + return g:test + enddef + assert_equal({a: 43}, FillDict()) + END + CheckScriptSuccess(lines) + + # assignment to buffer dict + lines =<< trim END + vim9script + b:test = {} + def FillDict(): dict<any> + b:test['a'] = 43 + return b:test + enddef + assert_equal({a: 43}, FillDict()) + END + CheckScriptSuccess(lines) + + lines =<< trim END + var d = {dd: test_null_dict()} + d.dd[0] = 0 + END + CheckDefExecFailure(lines, 'E1103:', 2) + + lines =<< trim END + var d = {dd: 'string'} + d.dd[0] = 0 + END + CheckDefExecFailure(lines, 'E1148:', 2) +enddef + +def Test_assignment_local() + # Test in a separated file in order not to the current buffer/window/tab is + # changed. + var script_lines: list<string> =<< trim END + let b:existing = 'yes' + let w:existing = 'yes' + let t:existing = 'yes' + + def Test_assignment_local_internal() + b:newvar = 'new' + assert_equal('new', b:newvar) + assert_equal('yes', b:existing) + b:existing = 'no' + assert_equal('no', b:existing) + b:existing ..= 'NO' + assert_equal('noNO', b:existing) + + w:newvar = 'new' + assert_equal('new', w:newvar) + assert_equal('yes', w:existing) + w:existing = 'no' + assert_equal('no', w:existing) + w:existing ..= 'NO' + assert_equal('noNO', w:existing) + + t:newvar = 'new' + assert_equal('new', t:newvar) + assert_equal('yes', t:existing) + t:existing = 'no' + assert_equal('no', t:existing) + t:existing ..= 'NO' + assert_equal('noNO', t:existing) + enddef + call Test_assignment_local_internal() + END + CheckScriptSuccess(script_lines) +enddef + +def Test_assignment_default() + # Test default values. + var thebool: bool + assert_equal(v:false, thebool) + + var thenumber: number + assert_equal(0, thenumber) + + if has('float') + var thefloat: float + assert_equal(0.0, thefloat) + endif + + var thestring: string + assert_equal('', thestring) + + var theblob: blob + assert_equal(0z, theblob) + + var Thefunc: func + assert_equal(test_null_function(), Thefunc) + + var thelist: list<any> + assert_equal([], thelist) + + var thedict: dict<any> + assert_equal({}, thedict) + + if has('channel') + var thejob: job + assert_equal(test_null_job(), thejob) + + var thechannel: channel + assert_equal(test_null_channel(), thechannel) + + if has('unix') && executable('cat') + # check with non-null job and channel, types must match + thejob = job_start("cat ", {}) + thechannel = job_getchannel(thejob) + job_stop(thejob, 'kill') + endif + endif + + var nr = 1234 | nr = 5678 + assert_equal(5678, nr) +enddef + +let scriptvar = 'init' + +def Test_assignment_var_list() + var lines =<< trim END + var v1: string + var v2: string + var vrem: list<string> + [v1] = ['aaa'] + assert_equal('aaa', v1) + + [v1, v2] = ['one', 'two'] + assert_equal('one', v1) + assert_equal('two', v2) + + [v1, v2; vrem] = ['one', 'two'] + assert_equal('one', v1) + assert_equal('two', v2) + assert_equal([], vrem) + + [v1, v2; vrem] = ['one', 'two', 'three'] + assert_equal('one', v1) + assert_equal('two', v2) + assert_equal(['three'], vrem) + + [&ts, &sw] = [3, 4] + assert_equal(3, &ts) + assert_equal(4, &sw) + set ts=8 sw=4 + + [@a, @z] = ['aa', 'zz'] + assert_equal('aa', @a) + assert_equal('zz', @z) + + [$SOME_VAR, $OTHER_VAR] = ['some', 'other'] + assert_equal('some', $SOME_VAR) + assert_equal('other', $OTHER_VAR) + + [g:globalvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = + ['global', 'buf', 'win', 'tab', 'error'] + assert_equal('global', g:globalvar) + assert_equal('buf', b:bufvar) + assert_equal('win', w:winvar) + assert_equal('tab', t:tabvar) + assert_equal('error', v:errmsg) + unlet g:globalvar + END + CheckDefAndScriptSuccess(lines) + + [g:globalvar, s:scriptvar, b:bufvar] = ['global', 'script', 'buf'] + assert_equal('global', g:globalvar) + assert_equal('script', s:scriptvar) + assert_equal('buf', b:bufvar) + + lines =<< trim END + vim9script + var s:scriptvar = 'init' + [g:globalvar, s:scriptvar, w:winvar] = ['global', 'script', 'win'] + assert_equal('global', g:globalvar) + assert_equal('script', s:scriptvar) + assert_equal('win', w:winvar) + END + CheckScriptSuccess(lines) +enddef + +def Test_assignment_vim9script() + var lines =<< trim END + vim9script + def Func(): list<number> + return [1, 2] + enddef + var name1: number + var name2: number + [name1, name2] = + Func() + assert_equal(1, name1) + assert_equal(2, name2) + var ll = + Func() + assert_equal([1, 2], ll) + + @/ = 'text' + assert_equal('text', @/) + @0 = 'zero' + assert_equal('zero', @0) + @1 = 'one' + assert_equal('one', @1) + @9 = 'nine' + assert_equal('nine', @9) + @- = 'minus' + assert_equal('minus', @-) + if has('clipboard_working') + @* = 'star' + assert_equal('star', @*) + @+ = 'plus' + assert_equal('plus', @+) + endif + + var a: number = 123 + assert_equal(123, a) + var s: string = 'yes' + assert_equal('yes', s) + var b: number = 42 + assert_equal(42, b) + var w: number = 43 + assert_equal(43, w) + var t: number = 44 + assert_equal(44, t) + + var to_var = 0 + to_var = 3 + assert_equal(3, to_var) + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var n: number + def Func() + n = 'string' + enddef + defcompile + END + CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string') +enddef + +def Mess(): string + v:foldstart = 123 + return 'xxx' +enddef + +def Test_assignment_failure() + CheckDefFailure(['var name=234'], 'E1004:') + CheckDefFailure(['var name =234'], 'E1004:') + CheckDefFailure(['var name= 234'], 'E1004:') + + CheckScriptFailure(['vim9script', 'var name=234'], 'E1004:') + CheckScriptFailure(['vim9script', 'var name=234'], "before and after '='") + CheckScriptFailure(['vim9script', 'var name =234'], 'E1004:') + CheckScriptFailure(['vim9script', 'var name= 234'], 'E1004:') + CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], 'E1004:') + CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], "before and after '+='") + CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], 'E1004:') + CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], "before and after '..='") + + CheckDefFailure(['var true = 1'], 'E1034:') + CheckDefFailure(['var false = 1'], 'E1034:') + + CheckDefFailure(['[a; b; c] = g:list'], 'E452:') + CheckDefExecFailure(['var a: number', + '[a] = test_null_list()'], 'E1093:') + CheckDefExecFailure(['var a: number', + '[a] = []'], 'E1093:') + CheckDefExecFailure(['var x: number', + 'var y: number', + '[x, y] = [1]'], 'E1093:') + CheckDefExecFailure(['var x: string', + 'var y: string', + '[x, y] = ["x"]'], 'E1093:') + CheckDefExecFailure(['var x: number', + 'var y: number', + 'var z: list<number>', + '[x, y; z] = [1]'], 'E1093:') + + CheckDefFailure(['var somevar'], "E1022:") + CheckDefFailure(['var &tabstop = 4'], 'E1052:') + CheckDefFailure(['&g:option = 5'], 'E113:') + CheckScriptFailure(['vim9script', 'var &tabstop = 4'], 'E1052:') + + CheckDefFailure(['var $VAR = 5'], 'E1016: Cannot declare an environment variable:') + CheckScriptFailure(['vim9script', 'var $ENV = "xxx"'], 'E1016:') + + if has('dnd') + CheckDefFailure(['var @~ = 5'], 'E1066:') + else + CheckDefFailure(['var @~ = 5'], 'E354:') + CheckDefFailure(['@~ = 5'], 'E354:') + endif + CheckDefFailure(['var @a = 5'], 'E1066:') + CheckDefFailure(['var @/ = "x"'], 'E1066:') + CheckScriptFailure(['vim9script', 'var @a = "abc"'], 'E1066:') + + CheckDefFailure(['var g:var = 5'], 'E1016: Cannot declare a global variable:') + CheckDefFailure(['var w:var = 5'], 'E1016: Cannot declare a window variable:') + CheckDefFailure(['var b:var = 5'], 'E1016: Cannot declare a buffer variable:') + CheckDefFailure(['var t:var = 5'], 'E1016: Cannot declare a tab variable:') + + CheckDefFailure(['var anr = 4', 'anr ..= "text"'], 'E1019:') + CheckDefFailure(['var xnr += 4'], 'E1020:', 1) + CheckScriptFailure(['vim9script', 'var xnr += 4'], 'E1020:') + CheckDefFailure(["var xnr = xnr + 1"], 'E1001:', 1) + CheckScriptFailure(['vim9script', 'var xnr = xnr + 4'], 'E121:') + + CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = s:notfound', 'enddef', 'defcompile'], 'E1108:') + + CheckDefFailure(['var name: list<string> = [123]'], 'expected list<string> but got list<number>') + CheckDefFailure(['var name: list<number> = ["xx"]'], 'expected list<number> but got list<string>') + + CheckDefFailure(['var name: dict<string> = {key: 123}'], 'expected dict<string> but got dict<number>') + CheckDefFailure(['var name: dict<number> = {key: "xx"}'], 'expected dict<number> but got dict<string>') + + CheckDefFailure(['var name = feedkeys("0")'], 'E1031:') + CheckDefFailure(['var name: number = feedkeys("0")'], 'expected number but got void') + + CheckDefFailure(['var name: dict <number>'], 'E1068:') + CheckDefFailure(['var name: dict<number'], 'E1009:') + + assert_fails('s/^/\=Mess()/n', 'E794:') + CheckDefFailure(['var name: dict<number'], 'E1009:') + + CheckDefFailure(['w:foo: number = 10'], + 'E488: Trailing characters: : number = 1') + CheckDefFailure(['t:foo: bool = true'], + 'E488: Trailing characters: : bool = true') + CheckDefFailure(['b:foo: string = "x"'], + 'E488: Trailing characters: : string = "x"') + CheckDefFailure(['g:foo: number = 123'], + 'E488: Trailing characters: : number = 123') +enddef + +def Test_assign_list() + var l: list<string> = [] + l[0] = 'value' + assert_equal('value', l[0]) + + l[1] = 'asdf' + assert_equal('value', l[0]) + assert_equal('asdf', l[1]) + assert_equal('asdf', l[-1]) + assert_equal('value', l[-2]) + + var nrl: list<number> = [] + for i in range(5) + nrl[i] = i + endfor + assert_equal([0, 1, 2, 3, 4], nrl) + + CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1) + CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1) +enddef + +def Test_assign_dict() + var lines =<< trim END + var d: dict<string> = {} + d['key'] = 'value' + assert_equal('value', d['key']) + + d[123] = 'qwerty' + assert_equal('qwerty', d[123]) + assert_equal('qwerty', d['123']) + + var nrd: dict<number> = {} + for i in range(3) + nrd[i] = i + endfor + assert_equal({0: 0, 1: 1, 2: 2}, nrd) + + d.somekey = 'someval' + assert_equal({key: 'value', '123': 'qwerty', somekey: 'someval'}, d) + # unlet d.somekey + # assert_equal({key: 'value', '123': 'qwerty'}, d) + END + CheckDefAndScriptSuccess(lines) + + # TODO: move to above once "unlet d.somekey" in :def is implemented + lines =<< trim END + vim9script + var d: dict<string> = {} + d['key'] = 'value' + d.somekey = 'someval' + assert_equal({key: 'value', somekey: 'someval'}, d) + unlet d.somekey + assert_equal({key: 'value'}, d) + END + CheckScriptSuccess(lines) + + CheckDefFailure(["var d: dict<number> = {a: '', b: true}"], 'E1012: Type mismatch; expected dict<number> but got dict<any>', 1) + CheckDefFailure(["var d: dict<dict<number>> = {x: {a: '', b: true}}"], 'E1012: Type mismatch; expected dict<dict<number>> but got dict<dict<any>>', 1) +enddef + +def Test_assign_dict_unknown_type() + var lines =<< trim END + vim9script + var mylist = [] + mylist += [{one: 'one'}] + def Func() + var dd = mylist[0] + assert_equal('one', dd.one) + enddef + Func() + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var mylist = [[]] + mylist[0] += [{one: 'one'}] + def Func() + var dd = mylist[0][0] + assert_equal('one', dd.one) + enddef + Func() + END + CheckScriptSuccess(lines) +enddef + +def Test_assign_lambda() + # check if assign a lambda to a variable which type is func or any. + var lines =<< trim END + vim9script + var FuncRef = () => 123 + assert_equal(123, FuncRef()) + var FuncRef_Func: func = () => 123 + assert_equal(123, FuncRef_Func()) + var FuncRef_Any: any = () => 123 + assert_equal(123, FuncRef_Any()) + END + CheckScriptSuccess(lines) + + lines =<< trim END + var Ref: func(number) + Ref = (j) => !j + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') + CheckScriptFailure(['vim9script'] + lines, 'E1012: Type mismatch; expected func(number) but got func(any): any') +enddef + +def Test_heredoc() + var lines =<< trim END # comment + text + END + assert_equal(['text'], lines) + + CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:') + CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:') + + lines =<< trim [END] + def Func() + var&lines =<< trim END + x + x + enddef + defcompile + [END] + CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') + delfunc! g:Func + + lines =<< trim [END] + def Func() + var lines =<< trim END + x + x + x + x + x + x + x + x + enddef + call Func() + [END] + CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') + delfunc! g:Func +enddef + +def Test_var_func_call() + var lines =<< trim END + vim9script + func GetValue() + if exists('g:count') + let g:count += 1 + else + let g:count = 1 + endif + return 'this' + endfunc + var val: string = GetValue() + # env var is always a string + var env = $TERM + END + writefile(lines, 'Xfinished') + source Xfinished + # GetValue() is not called during discovery phase + assert_equal(1, g:count) + + unlet g:count + delete('Xfinished') +enddef + +def Test_var_missing_type() + var lines =<< trim END + vim9script + var name = g:unknown + END + CheckScriptFailure(lines, 'E121:') + + lines =<< trim END + vim9script + var nr: number = 123 + var name = nr + END + CheckScriptSuccess(lines) +enddef + +def Test_var_declaration() + var lines =<< trim END + vim9script + var name: string + g:var_uninit = name + name = 'text' + g:var_test = name + # prefixing s: is optional + s:name = 'prefixed' + g:var_prefixed = s:name + + const FOO: number = 123 + assert_equal(123, FOO) + const FOOS = 'foos' + assert_equal('foos', FOOS) + final FLIST = [1] + assert_equal([1], FLIST) + FLIST[0] = 11 + assert_equal([11], FLIST) + + const g:FOO: number = 321 + assert_equal(321, g:FOO) + const g:FOOS = 'gfoos' + assert_equal('gfoos', g:FOOS) + final g:FLIST = [2] + assert_equal([2], g:FLIST) + g:FLIST[0] = 22 + assert_equal([22], g:FLIST) + + const w:FOO: number = 46 + assert_equal(46, w:FOO) + const w:FOOS = 'wfoos' + assert_equal('wfoos', w:FOOS) + final w:FLIST = [3] + assert_equal([3], w:FLIST) + w:FLIST[0] = 33 + assert_equal([33], w:FLIST) + + var s:other: number + other = 1234 + g:other_var = other + + # type is inferred + var s:dict = {['a']: 222} + def GetDictVal(key: any) + g:dict_val = s:dict[key] + enddef + GetDictVal('a') + + final adict: dict<string> = {} + def ChangeAdict() + adict.foo = 'foo' + enddef + ChangeAdict() + END + CheckScriptSuccess(lines) + assert_equal('', g:var_uninit) + assert_equal('text', g:var_test) + assert_equal('prefixed', g:var_prefixed) + assert_equal(1234, g:other_var) + assert_equal(222, g:dict_val) + + unlet g:var_uninit + unlet g:var_test + unlet g:var_prefixed + unlet g:other_var + unlet g:FOO + unlet g:FOOS + unlet g:FLIST + unlet w:FOO + unlet w:FOOS + unlet w:FLIST +enddef + +def Test_var_declaration_fails() + var lines =<< trim END + vim9script + final var: string + END + CheckScriptFailure(lines, 'E1125:') + + lines =<< trim END + vim9script + const g:constvar = 'string' + g:constvar = 'xx' + END + CheckScriptFailure(lines, 'E741:') + unlet g:constvar + + lines =<< trim END + vim9script + const cdict: dict<string> = {} + def Change() + cdict.foo = 'foo' + enddef + defcompile + END + CheckScriptFailure(lines, 'E46:') + + lines =<< trim END + vim9script + final w:finalvar = [9] + w:finalvar = [8] + END + CheckScriptFailure(lines, 'E1122:') + unlet w:finalvar + + lines =<< trim END + vim9script + const var: string + END + CheckScriptFailure(lines, 'E1021:') + + lines =<< trim END + vim9script + var 9var: string + END + CheckScriptFailure(lines, 'E475:') + + CheckDefFailure(['var foo.bar = 2'], 'E1087:') + CheckDefFailure(['var foo[3] = 2'], 'E1087:') + CheckDefFailure(['const foo: number'], 'E1021:') +enddef + +def Test_var_type_check() + var lines =<< trim END + vim9script + var name: string + name = 1234 + END + CheckScriptFailure(lines, 'E1012:') + + lines =<< trim END + vim9script + var name:string + END + CheckScriptFailure(lines, 'E1069:') + + lines =<< trim END + vim9script + var name: asdf + END + CheckScriptFailure(lines, 'E1010:') + + lines =<< trim END + vim9script + var s:l: list<number> + s:l = [] + END + CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + var s:d: dict<number> + s:d = {} + END + CheckScriptSuccess(lines) +enddef + +let g:dict_number = #{one: 1, two: 2} + +def Test_var_list_dict_type() + var ll: list<number> + ll = [1, 2, 2, 3, 3, 3]->uniq() + ll->assert_equal([1, 2, 3]) + + var dd: dict<number> + dd = g:dict_number + dd->assert_equal(g:dict_number) + + var lines =<< trim END + var ll: list<number> + ll = [1, 2, 3]->map('"one"') + END + CheckDefExecFailure(lines, 'E1012: Type mismatch; expected number but got string') +enddef + +def Test_cannot_use_let() + CheckDefAndScriptFailure(['let a = 34'], 'E1126:', 1) +enddef + +def Test_unlet() + g:somevar = 'yes' + assert_true(exists('g:somevar')) + unlet g:somevar + assert_false(exists('g:somevar')) + unlet! g:somevar + + # also works for script-local variable in legacy Vim script + s:somevar = 'legacy' + assert_true(exists('s:somevar')) + unlet s:somevar + assert_false(exists('s:somevar')) + unlet! s:somevar + + CheckDefExecFailure([ + 'var dd = 111', + 'unlet dd', + ], 'E1081:', 2) + + # dict unlet + var dd = {a: 1, b: 2, c: 3} + unlet dd['a'] + unlet dd.c + assert_equal({b: 2}, dd) + + # list unlet + var ll = [1, 2, 3, 4] + unlet ll[1] + unlet ll[-1] + assert_equal([1, 3], ll) + + # list of dict unlet + var dl = [{a: 1, b: 2}, {c: 3}] + unlet dl[0]['b'] + assert_equal([{a: 1}, {c: 3}], dl) + + CheckDefExecFailure([ + 'var ll = test_null_list()', + 'unlet ll[0]', + ], 'E684:', 2) + CheckDefExecFailure([ + 'var ll = [1]', + 'unlet ll[2]', + ], 'E684:', 2) + CheckDefExecFailure([ + 'var ll = [1]', + 'unlet ll[g:astring]', + ], 'E1012:', 2) + CheckDefExecFailure([ + 'var dd = test_null_dict()', + 'unlet dd["a"]', + ], 'E716:', 2) + CheckDefExecFailure([ + 'var dd = {a: 1}', + 'unlet dd["b"]', + ], 'E716:', 2) + CheckDefExecFailure([ + 'var dd = {a: 1}', + 'unlet dd[g:alist]', + ], 'E1105:', 2) + + # can compile unlet before variable exists + g:someDict = {key: 'val'} + var k = 'key' + unlet g:someDict[k] + assert_equal({}, g:someDict) + unlet g:someDict + assert_false(exists('g:someDict')) + + CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'unlet svar', + ], 'E1081:') + CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'unlet s:svar', + ], 'E1081:') + CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'def Func()', + ' unlet svar', + 'enddef', + 'defcompile', + ], 'E1081:') + CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'func Func()', + ' unlet s:svar', + 'endfunc', + 'Func()', + ], 'E1081:') + CheckScriptFailure([ + 'vim9script', + 'var svar = 123', + 'def Func()', + ' unlet s:svar', + 'enddef', + 'defcompile', + ], 'E1081:') + + writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim') + var lines =<< trim END + vim9script + import svar from './XunletExport.vim' + def UnletSvar() + unlet svar + enddef + defcompile + END + CheckScriptFailure(lines, 'E1081:', 1) + delete('XunletExport.vim') + + $ENVVAR = 'foobar' + assert_equal('foobar', $ENVVAR) + unlet $ENVVAR + assert_equal('', $ENVVAR) +enddef + +def Test_expr_error_no_assign() + var lines =<< trim END + vim9script + var x = invalid + echo x + END + CheckScriptFailureList(lines, ['E121:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 / 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 % 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) +enddef + + +def Test_assign_command_modifier() + var lines =<< trim END + var verbose = 0 + verbose = 1 + assert_equal(1, verbose) + silent verbose = 2 + assert_equal(2, verbose) + silent verbose += 2 + assert_equal(4, verbose) + silent verbose -= 1 + assert_equal(3, verbose) + + var topleft = {one: 1} + sandbox topleft.one = 3 + assert_equal({one: 3}, topleft) + leftabove topleft[' '] = 4 + assert_equal({one: 3, ' ': 4}, topleft) + + var x: number + var y: number + silent [x, y] = [1, 2] + assert_equal(1, x) + assert_equal(2, y) + END + CheckDefAndScriptSuccess(lines) +enddef + + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker |