1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source term_util.vim
5source view_util.vim
6source vim9.vim
7source shared.vim
8
9def Test_range_only()
10  new
11  setline(1, ['blah', 'Blah'])
12  :/Blah/
13  assert_equal(2, getcurpos()[1])
14  bwipe!
15
16  # without range commands use current line
17  new
18  setline(1, ['one', 'two', 'three'])
19  :2
20  print
21  assert_equal('two', Screenline(&lines))
22  :3
23  list
24  assert_equal('three$', Screenline(&lines))
25  bwipe!
26
27  # won't generate anything
28  if false
29    :123
30  endif
31enddef
32
33let g:alist = [7]
34let g:astring = 'text'
35let g:anumber = 123
36
37def Test_delfunction()
38  # Check function is defined in script namespace
39  CheckScriptSuccess([
40      'vim9script',
41      'func CheckMe()',
42      '  return 123',
43      'endfunc',
44      'assert_equal(123, s:CheckMe())',
45      ])
46
47  # Check function in script namespace cannot be deleted
48  CheckScriptFailure([
49      'vim9script',
50      'func DeleteMe1()',
51      'endfunc',
52      'delfunction DeleteMe1',
53      ], 'E1084:')
54  CheckScriptFailure([
55      'vim9script',
56      'func DeleteMe2()',
57      'endfunc',
58      'def DoThat()',
59      '  delfunction DeleteMe2',
60      'enddef',
61      'DoThat()',
62      ], 'E1084:')
63  CheckScriptFailure([
64      'vim9script',
65      'def DeleteMe3()',
66      'enddef',
67      'delfunction DeleteMe3',
68      ], 'E1084:')
69  CheckScriptFailure([
70      'vim9script',
71      'def DeleteMe4()',
72      'enddef',
73      'def DoThat()',
74      '  delfunction DeleteMe4',
75      'enddef',
76      'DoThat()',
77      ], 'E1084:')
78
79  # Check that global :def function can be replaced and deleted
80  var lines =<< trim END
81      vim9script
82      def g:Global(): string
83        return "yes"
84      enddef
85      assert_equal("yes", g:Global())
86      def! g:Global(): string
87        return "no"
88      enddef
89      assert_equal("no", g:Global())
90      delfunc g:Global
91      assert_false(exists('*g:Global'))
92  END
93  CheckScriptSuccess(lines)
94
95  # Check that global function can be replaced by a :def function and deleted
96  lines =<< trim END
97      vim9script
98      func g:Global()
99        return "yes"
100      endfunc
101      assert_equal("yes", g:Global())
102      def! g:Global(): string
103        return "no"
104      enddef
105      assert_equal("no", g:Global())
106      delfunc g:Global
107      assert_false(exists('*g:Global'))
108  END
109  CheckScriptSuccess(lines)
110
111  # Check that global :def function can be replaced by a function and deleted
112  lines =<< trim END
113      vim9script
114      def g:Global(): string
115        return "yes"
116      enddef
117      assert_equal("yes", g:Global())
118      func! g:Global()
119        return "no"
120      endfunc
121      assert_equal("no", g:Global())
122      delfunc g:Global
123      assert_false(exists('*g:Global'))
124  END
125  CheckScriptSuccess(lines)
126enddef
127
128def Test_wrong_type()
129  CheckDefFailure(['var name: list<nothing>'], 'E1010:')
130  CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
131  CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
132  CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
133
134  CheckDefFailure(['var name: dict<number'], 'E1009:')
135  CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
136
137  CheckDefFailure(['var name: ally'], 'E1010:')
138  CheckDefFailure(['var name: bram'], 'E1010:')
139  CheckDefFailure(['var name: cathy'], 'E1010:')
140  CheckDefFailure(['var name: dom'], 'E1010:')
141  CheckDefFailure(['var name: freddy'], 'E1010:')
142  CheckDefFailure(['var name: john'], 'E1010:')
143  CheckDefFailure(['var name: larry'], 'E1010:')
144  CheckDefFailure(['var name: ned'], 'E1010:')
145  CheckDefFailure(['var name: pam'], 'E1010:')
146  CheckDefFailure(['var name: sam'], 'E1010:')
147  CheckDefFailure(['var name: vim'], 'E1010:')
148
149  CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
150  CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
151enddef
152
153def Test_script_wrong_type()
154  var lines =<< trim END
155      vim9script
156      var s:dict: dict<string>
157      s:dict['a'] = ['x']
158  END
159  CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
160enddef
161
162def Test_const()
163  CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
164  CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
165  CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
166  CheckDefFailure(['final two'], 'E1125:')
167  CheckDefFailure(['final &option'], 'E996:')
168
169  var lines =<< trim END
170    final list = [1, 2, 3]
171    list[0] = 4
172    list->assert_equal([4, 2, 3])
173    const other = [5, 6, 7]
174    other->assert_equal([5, 6, 7])
175
176    var varlist = [7, 8]
177    const constlist = [1, varlist, 3]
178    varlist[0] = 77
179    # TODO: does not work yet
180    # constlist[1][1] = 88
181    var cl = constlist[1]
182    cl[1] = 88
183    constlist->assert_equal([1, [77, 88], 3])
184
185    var vardict = {five: 5, six: 6}
186    const constdict = {one: 1, two: vardict, three: 3}
187    vardict['five'] = 55
188    # TODO: does not work yet
189    # constdict['two']['six'] = 66
190    var cd = constdict['two']
191    cd['six'] = 66
192    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
193  END
194  CheckDefAndScriptSuccess(lines)
195enddef
196
197def Test_const_bang()
198  var lines =<< trim END
199      const var = 234
200      var = 99
201  END
202  CheckDefExecFailure(lines, 'E1018:', 2)
203  CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
204
205  lines =<< trim END
206      const ll = [2, 3, 4]
207      ll[0] = 99
208  END
209  CheckDefExecFailure(lines, 'E1119:', 2)
210  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
211
212  lines =<< trim END
213      const ll = [2, 3, 4]
214      ll[3] = 99
215  END
216  CheckDefExecFailure(lines, 'E1118:', 2)
217  CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
218
219  lines =<< trim END
220      const dd = {one: 1, two: 2}
221      dd["one"] = 99
222  END
223  CheckDefExecFailure(lines, 'E1121:', 2)
224  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
225
226  lines =<< trim END
227      const dd = {one: 1, two: 2}
228      dd["three"] = 99
229  END
230  CheckDefExecFailure(lines, 'E1120:')
231  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
232enddef
233
234def Test_range_no_colon()
235  CheckDefFailure(['%s/a/b/'], 'E1050:')
236  CheckDefFailure(['+ s/a/b/'], 'E1050:')
237  CheckDefFailure(['- s/a/b/'], 'E1050:')
238  CheckDefFailure(['. s/a/b/'], 'E1050:')
239enddef
240
241
242def Test_block()
243  var outer = 1
244  {
245    var inner = 2
246    assert_equal(1, outer)
247    assert_equal(2, inner)
248  }
249  assert_equal(1, outer)
250enddef
251
252def Test_block_failure()
253  CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
254  CheckDefFailure(['}'], 'E1025:')
255  CheckDefFailure(['{', 'echo 1'], 'E1026:')
256enddef
257
258def Test_block_local_vars()
259  var lines =<< trim END
260      vim9script
261      v:testing = 1
262      if true
263        var text = ['hello']
264        def SayHello(): list<string>
265          return text
266        enddef
267        def SetText(v: string)
268          text = [v]
269        enddef
270      endif
271
272      if true
273        var text = ['again']
274        def SayAgain(): list<string>
275          return text
276        enddef
277      endif
278
279      # test that the "text" variables are not cleaned up
280      test_garbagecollect_now()
281
282      defcompile
283
284      assert_equal(['hello'], SayHello())
285      assert_equal(['again'], SayAgain())
286
287      SetText('foobar')
288      assert_equal(['foobar'], SayHello())
289
290      call writefile(['ok'], 'Xdidit')
291      qall!
292  END
293
294  # need to execute this with a separate Vim instance to avoid the current
295  # context gets garbage collected.
296  writefile(lines, 'Xscript')
297  RunVim([], [], '-S Xscript')
298  assert_equal(['ok'], readfile('Xdidit'))
299
300  delete('Xscript')
301  delete('Xdidit')
302enddef
303
304def Test_block_local_vars_with_func()
305  var lines =<< trim END
306      vim9script
307      if true
308        var foo = 'foo'
309        if true
310          var bar = 'bar'
311          def Func(): list<string>
312            return [foo, bar]
313          enddef
314        endif
315      endif
316      # function is compiled here, after blocks have finished, can still access
317      # "foo" and "bar"
318      assert_equal(['foo', 'bar'], Func())
319  END
320  CheckScriptSuccess(lines)
321enddef
322
323func g:NoSuchFunc()
324  echo 'none'
325endfunc
326
327def Test_try_catch()
328  var l = []
329  try # comment
330    add(l, '1')
331    throw 'wrong'
332    add(l, '2')
333  catch # comment
334    add(l, v:exception)
335  finally # comment
336    add(l, '3')
337  endtry # comment
338  assert_equal(['1', 'wrong', '3'], l)
339
340  l = []
341  try
342    try
343      add(l, '1')
344      throw 'wrong'
345      add(l, '2')
346    catch /right/
347      add(l, v:exception)
348    endtry
349  catch /wrong/
350    add(l, 'caught')
351  fina
352    add(l, 'finally')
353  endtry
354  assert_equal(['1', 'caught', 'finally'], l)
355
356  var n: number
357  try
358    n = l[3]
359  catch /E684:/
360    n = 99
361  endtry
362  assert_equal(99, n)
363
364  try
365    # string slice returns a string, not a number
366    n = g:astring[3]
367  catch /E1012:/
368    n = 77
369  endtry
370  assert_equal(77, n)
371
372  try
373    n = l[g:astring]
374  catch /E1012:/
375    n = 88
376  endtry
377  assert_equal(88, n)
378
379  try
380    n = s:does_not_exist
381  catch /E121:/
382    n = 111
383  endtry
384  assert_equal(111, n)
385
386  try
387    n = g:does_not_exist
388  catch /E121:/
389    n = 121
390  endtry
391  assert_equal(121, n)
392
393  var d = {one: 1}
394  try
395    n = d[g:astring]
396  catch /E716:/
397    n = 222
398  endtry
399  assert_equal(222, n)
400
401  try
402    n = -g:astring
403  catch /E39:/
404    n = 233
405  endtry
406  assert_equal(233, n)
407
408  try
409    n = +g:astring
410  catch /E1030:/
411    n = 244
412  endtry
413  assert_equal(244, n)
414
415  try
416    n = +g:alist
417  catch /E745:/
418    n = 255
419  endtry
420  assert_equal(255, n)
421
422  var nd: dict<any>
423  try
424    nd = {[g:anumber]: 1}
425  catch /E1012:/
426    n = 266
427  endtry
428  assert_equal(266, n)
429
430  try
431    [n] = [1, 2, 3]
432  catch /E1093:/
433    n = 277
434  endtry
435  assert_equal(277, n)
436
437  try
438    &ts = g:astring
439  catch /E1012:/
440    n = 288
441  endtry
442  assert_equal(288, n)
443
444  try
445    &backspace = 'asdf'
446  catch /E474:/
447    n = 299
448  endtry
449  assert_equal(299, n)
450
451  l = [1]
452  try
453    l[3] = 3
454  catch /E684:/
455    n = 300
456  endtry
457  assert_equal(300, n)
458
459  try
460    unlet g:does_not_exist
461  catch /E108:/
462    n = 322
463  endtry
464  assert_equal(322, n)
465
466  try
467    d = {text: 1, [g:astring]: 2}
468  catch /E721:/
469    n = 333
470  endtry
471  assert_equal(333, n)
472
473  try
474    l = DeletedFunc()
475  catch /E933:/
476    n = 344
477  endtry
478  assert_equal(344, n)
479
480  try
481    echo len(v:true)
482  catch /E701:/
483    n = 355
484  endtry
485  assert_equal(355, n)
486
487  var P = function('g:NoSuchFunc')
488  delfunc g:NoSuchFunc
489  try
490    echo P()
491  catch /E117:/
492    n = 366
493  endtry
494  assert_equal(366, n)
495
496  try
497    echo g:NoSuchFunc()
498  catch /E117:/
499    n = 377
500  endtry
501  assert_equal(377, n)
502
503  try
504    echo g:alist + 4
505  catch /E745:/
506    n = 388
507  endtry
508  assert_equal(388, n)
509
510  try
511    echo 4 + g:alist
512  catch /E745:/
513    n = 399
514  endtry
515  assert_equal(399, n)
516
517  try
518    echo g:alist.member
519  catch /E715:/
520    n = 400
521  endtry
522  assert_equal(400, n)
523
524  try
525    echo d.member
526  catch /E716:/
527    n = 411
528  endtry
529  assert_equal(411, n)
530enddef
531
532def DeletedFunc(): list<any>
533  return ['delete me']
534enddef
535defcompile
536delfunc DeletedFunc
537
538def ThrowFromDef()
539  throw "getout" # comment
540enddef
541
542func CatchInFunc()
543  try
544    call ThrowFromDef()
545  catch
546    let g:thrown_func = v:exception
547  endtry
548endfunc
549
550def CatchInDef()
551  try
552    ThrowFromDef()
553  catch
554    g:thrown_def = v:exception
555  endtry
556enddef
557
558def ReturnFinally(): string
559  try
560    return 'intry'
561  finall
562    g:in_finally = 'finally'
563  endtry
564  return 'end'
565enddef
566
567def Test_try_catch_nested()
568  CatchInFunc()
569  assert_equal('getout', g:thrown_func)
570
571  CatchInDef()
572  assert_equal('getout', g:thrown_def)
573
574  assert_equal('intry', ReturnFinally())
575  assert_equal('finally', g:in_finally)
576enddef
577
578def TryOne(): number
579  try
580    return 0
581  catch
582  endtry
583  return 0
584enddef
585
586def TryTwo(n: number): string
587  try
588    var x = {}
589  catch
590  endtry
591  return 'text'
592enddef
593
594def Test_try_catch_twice()
595  assert_equal('text', TryOne()->TryTwo())
596enddef
597
598def Test_try_catch_match()
599  var seq = 'a'
600  try
601    throw 'something'
602  catch /nothing/
603    seq ..= 'x'
604  catch /some/
605    seq ..= 'b'
606  catch /asdf/
607    seq ..= 'x'
608  catch ?a\?sdf?
609    seq ..= 'y'
610  finally
611    seq ..= 'c'
612  endtry
613  assert_equal('abc', seq)
614enddef
615
616def Test_try_catch_fails()
617  CheckDefFailure(['catch'], 'E603:')
618  CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
619  CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
620  CheckDefFailure(['finally'], 'E606:')
621  CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
622  CheckDefFailure(['endtry'], 'E602:')
623  CheckDefFailure(['while 1', 'endtry'], 'E170:')
624  CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
625  CheckDefFailure(['if 1', 'endtry'], 'E171:')
626  CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
627
628  CheckDefFailure(['throw'], 'E1143:')
629  CheckDefFailure(['throw xxx'], 'E1001:')
630enddef
631
632def Test_throw_vimscript()
633  # only checks line continuation
634  var lines =<< trim END
635      vim9script
636      try
637        throw 'one'
638              .. 'two'
639      catch
640        assert_equal('onetwo', v:exception)
641      endtry
642  END
643  CheckScriptSuccess(lines)
644
645  lines =<< trim END
646    vim9script
647    @r = ''
648    def Func()
649      throw @r
650    enddef
651    var result = ''
652    try
653      Func()
654    catch /E1129:/
655      result = 'caught'
656    endtry
657    assert_equal('caught', result)
658  END
659  CheckScriptSuccess(lines)
660enddef
661
662def Test_error_in_nested_function()
663  # an error in a nested :function aborts executin in the calling :def function
664  var lines =<< trim END
665      vim9script
666      def Func()
667        Error()
668        g:test_var = 1
669      enddef
670      func Error() abort
671        eval [][0]
672      endfunc
673      Func()
674  END
675  g:test_var = 0
676  CheckScriptFailure(lines, 'E684:')
677  assert_equal(0, g:test_var)
678enddef
679
680def Test_cexpr_vimscript()
681  # only checks line continuation
682  set errorformat=File\ %f\ line\ %l
683  var lines =<< trim END
684      vim9script
685      cexpr 'File'
686                .. ' someFile' ..
687                   ' line 19'
688      assert_equal(19, getqflist()[0].lnum)
689  END
690  CheckScriptSuccess(lines)
691  set errorformat&
692enddef
693
694def Test_statusline_syntax()
695  # legacy syntax is used for 'statusline'
696  var lines =<< trim END
697      vim9script
698      func g:Status()
699        return '%{"x" is# "x"}'
700      endfunc
701      set laststatus=2 statusline=%!Status()
702      redrawstatus
703      set laststatus statusline=
704  END
705  CheckScriptSuccess(lines)
706enddef
707
708def Test_list_vimscript()
709  # checks line continuation and comments
710  var lines =<< trim END
711      vim9script
712      var mylist = [
713            'one',
714            # comment
715            'two', # empty line follows
716
717            'three',
718            ]
719      assert_equal(['one', 'two', 'three'], mylist)
720  END
721  CheckScriptSuccess(lines)
722
723  # check all lines from heredoc are kept
724  lines =<< trim END
725      # comment 1
726      two
727      # comment 3
728
729      five
730      # comment 6
731  END
732  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
733enddef
734
735if has('channel')
736  let someJob = test_null_job()
737
738  def FuncWithError()
739    echomsg g:someJob
740  enddef
741
742  func Test_convert_emsg_to_exception()
743    try
744      call FuncWithError()
745    catch
746      call assert_match('Vim:E908:', v:exception)
747    endtry
748  endfunc
749endif
750
751let s:export_script_lines =<< trim END
752  vim9script
753  var name: string = 'bob'
754  def Concat(arg: string): string
755    return name .. arg
756  enddef
757  g:result = Concat('bie')
758  g:localname = name
759
760  export const CONST = 1234
761  export var exported = 9876
762  export var exp_name = 'John'
763  export def Exported(): string
764    return 'Exported'
765  enddef
766END
767
768def Undo_export_script_lines()
769  unlet g:result
770  unlet g:localname
771enddef
772
773def Test_vim9_import_export()
774  var import_script_lines =<< trim END
775    vim9script
776    import {exported, Exported} from './Xexport.vim'
777    g:imported = exported
778    exported += 3
779    g:imported_added = exported
780    g:imported_func = Exported()
781
782    def GetExported(): string
783      var local_dict = {ref: Exported}
784      return local_dict.ref()
785    enddef
786    g:funcref_result = GetExported()
787
788    import {exp_name} from './Xexport.vim'
789    g:imported_name = exp_name
790    exp_name ..= ' Doe'
791    g:imported_name_appended = exp_name
792    g:imported_later = exported
793  END
794
795  writefile(import_script_lines, 'Ximport.vim')
796  writefile(s:export_script_lines, 'Xexport.vim')
797
798  source Ximport.vim
799
800  assert_equal('bobbie', g:result)
801  assert_equal('bob', g:localname)
802  assert_equal(9876, g:imported)
803  assert_equal(9879, g:imported_added)
804  assert_equal(9879, g:imported_later)
805  assert_equal('Exported', g:imported_func)
806  assert_equal('Exported', g:funcref_result)
807  assert_equal('John', g:imported_name)
808  assert_equal('John Doe', g:imported_name_appended)
809  assert_false(exists('g:name'))
810
811  Undo_export_script_lines()
812  unlet g:imported
813  unlet g:imported_added
814  unlet g:imported_later
815  unlet g:imported_func
816  unlet g:imported_name g:imported_name_appended
817  delete('Ximport.vim')
818
819  # similar, with line breaks
820  var import_line_break_script_lines =<< trim END
821    vim9script
822    import {
823        exported,
824        Exported,
825        }
826        from
827        './Xexport.vim'
828    g:imported = exported
829    exported += 5
830    g:imported_added = exported
831    g:imported_func = Exported()
832  END
833  writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
834  source Ximport_lbr.vim
835
836  assert_equal(9876, g:imported)
837  assert_equal(9881, g:imported_added)
838  assert_equal('Exported', g:imported_func)
839
840  # exported script not sourced again
841  assert_false(exists('g:result'))
842  unlet g:imported
843  unlet g:imported_added
844  unlet g:imported_func
845  delete('Ximport_lbr.vim')
846
847  # import inside :def function
848  var import_in_def_lines =<< trim END
849    vim9script
850    def ImportInDef()
851      import exported from './Xexport.vim'
852      g:imported = exported
853      exported += 7
854      g:imported_added = exported
855    enddef
856    ImportInDef()
857  END
858  writefile(import_in_def_lines, 'Ximport2.vim')
859  source Ximport2.vim
860  # TODO: this should be 9879
861  assert_equal(9876, g:imported)
862  assert_equal(9883, g:imported_added)
863  unlet g:imported
864  unlet g:imported_added
865  delete('Ximport2.vim')
866
867  var import_star_as_lines =<< trim END
868    vim9script
869    import * as Export from './Xexport.vim'
870    def UseExport()
871      g:imported = Export.exported
872    enddef
873    UseExport()
874  END
875  writefile(import_star_as_lines, 'Ximport.vim')
876  source Ximport.vim
877  assert_equal(9883, g:imported)
878
879  var import_star_as_lines_no_dot =<< trim END
880    vim9script
881    import * as Export from './Xexport.vim'
882    def Func()
883      var dummy = 1
884      var imported = Export + dummy
885    enddef
886    defcompile
887  END
888  writefile(import_star_as_lines_no_dot, 'Ximport.vim')
889  assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func')
890
891  var import_star_as_lines_dot_space =<< trim END
892    vim9script
893    import * as Export from './Xexport.vim'
894    def Func()
895      var imported = Export . exported
896    enddef
897    defcompile
898  END
899  writefile(import_star_as_lines_dot_space, 'Ximport.vim')
900  assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
901
902  var import_star_as_lines_missing_name =<< trim END
903    vim9script
904    import * as Export from './Xexport.vim'
905    def Func()
906      var imported = Export.
907    enddef
908    defcompile
909  END
910  writefile(import_star_as_lines_missing_name, 'Ximport.vim')
911  assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func')
912
913  var import_star_as_lbr_lines =<< trim END
914    vim9script
915    import *
916        as Export
917        from
918        './Xexport.vim'
919    def UseExport()
920      g:imported = Export.exported
921    enddef
922    UseExport()
923  END
924  writefile(import_star_as_lbr_lines, 'Ximport.vim')
925  source Ximport.vim
926  assert_equal(9883, g:imported)
927
928  var import_star_lines =<< trim END
929    vim9script
930    import * from './Xexport.vim'
931  END
932  writefile(import_star_lines, 'Ximport.vim')
933  assert_fails('source Ximport.vim', 'E1045:', '', 2, 'Ximport.vim')
934
935  # try to import something that exists but is not exported
936  var import_not_exported_lines =<< trim END
937    vim9script
938    import name from './Xexport.vim'
939  END
940  writefile(import_not_exported_lines, 'Ximport.vim')
941  assert_fails('source Ximport.vim', 'E1049:', '', 2, 'Ximport.vim')
942
943  # try to import something that is already defined
944  var import_already_defined =<< trim END
945    vim9script
946    var exported = 'something'
947    import exported from './Xexport.vim'
948  END
949  writefile(import_already_defined, 'Ximport.vim')
950  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
951
952  # try to import something that is already defined
953  import_already_defined =<< trim END
954    vim9script
955    var exported = 'something'
956    import * as exported from './Xexport.vim'
957  END
958  writefile(import_already_defined, 'Ximport.vim')
959  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
960
961  # try to import something that is already defined
962  import_already_defined =<< trim END
963    vim9script
964    var exported = 'something'
965    import {exported} from './Xexport.vim'
966  END
967  writefile(import_already_defined, 'Ximport.vim')
968  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
969
970  # try changing an imported const
971  var import_assign_to_const =<< trim END
972    vim9script
973    import CONST from './Xexport.vim'
974    def Assign()
975      CONST = 987
976    enddef
977    defcompile
978  END
979  writefile(import_assign_to_const, 'Ximport.vim')
980  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
981
982  # import a very long name, requires making a copy
983  var import_long_name_lines =<< trim END
984    vim9script
985    import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim'
986  END
987  writefile(import_long_name_lines, 'Ximport.vim')
988  assert_fails('source Ximport.vim', 'E1048:', '', 2, 'Ximport.vim')
989
990  var import_no_from_lines =<< trim END
991    vim9script
992    import name './Xexport.vim'
993  END
994  writefile(import_no_from_lines, 'Ximport.vim')
995  assert_fails('source Ximport.vim', 'E1070:', '', 2, 'Ximport.vim')
996
997  var import_invalid_string_lines =<< trim END
998    vim9script
999    import name from Xexport.vim
1000  END
1001  writefile(import_invalid_string_lines, 'Ximport.vim')
1002  assert_fails('source Ximport.vim', 'E1071:', '', 2, 'Ximport.vim')
1003
1004  var import_wrong_name_lines =<< trim END
1005    vim9script
1006    import name from './XnoExport.vim'
1007  END
1008  writefile(import_wrong_name_lines, 'Ximport.vim')
1009  assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
1010
1011  var import_missing_comma_lines =<< trim END
1012    vim9script
1013    import {exported name} from './Xexport.vim'
1014  END
1015  writefile(import_missing_comma_lines, 'Ximport3.vim')
1016  assert_fails('source Ximport3.vim', 'E1046:', '', 2, 'Ximport3.vim')
1017
1018  delete('Ximport.vim')
1019  delete('Ximport3.vim')
1020  delete('Xexport.vim')
1021
1022  # Check that in a Vim9 script 'cpo' is set to the Vim default.
1023  set cpo&vi
1024  var cpo_before = &cpo
1025  var lines =<< trim END
1026    vim9script
1027    g:cpo_in_vim9script = &cpo
1028  END
1029  writefile(lines, 'Xvim9_script')
1030  source Xvim9_script
1031  assert_equal(cpo_before, &cpo)
1032  set cpo&vim
1033  assert_equal(&cpo, g:cpo_in_vim9script)
1034  delete('Xvim9_script')
1035enddef
1036
1037func g:Trigger()
1038  source Ximport.vim
1039  return "echo 'yes'\<CR>"
1040endfunc
1041
1042def Test_import_export_expr_map()
1043  # check that :import and :export work when buffer is locked
1044  var export_lines =<< trim END
1045    vim9script
1046    export def That(): string
1047      return 'yes'
1048    enddef
1049  END
1050  writefile(export_lines, 'Xexport_that.vim')
1051
1052  var import_lines =<< trim END
1053    vim9script
1054    import That from './Xexport_that.vim'
1055    assert_equal('yes', That())
1056  END
1057  writefile(import_lines, 'Ximport.vim')
1058
1059  nnoremap <expr> trigger g:Trigger()
1060  feedkeys('trigger', "xt")
1061
1062  delete('Xexport_that.vim')
1063  delete('Ximport.vim')
1064  nunmap trigger
1065enddef
1066
1067def Test_import_in_filetype()
1068  # check that :import works when the buffer is locked
1069  mkdir('ftplugin', 'p')
1070  var export_lines =<< trim END
1071    vim9script
1072    export var That = 'yes'
1073  END
1074  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1075
1076  var import_lines =<< trim END
1077    vim9script
1078    import That from './Xexport_ft.vim'
1079    assert_equal('yes', That)
1080    g:did_load_mytpe = 1
1081  END
1082  writefile(import_lines, 'ftplugin/qf.vim')
1083
1084  var save_rtp = &rtp
1085  &rtp = getcwd() .. ',' .. &rtp
1086
1087  filetype plugin on
1088  copen
1089  assert_equal(1, g:did_load_mytpe)
1090
1091  quit!
1092  delete('Xexport_ft.vim')
1093  delete('ftplugin', 'rf')
1094  &rtp = save_rtp
1095enddef
1096
1097def Test_use_import_in_mapping()
1098  var lines =<< trim END
1099      vim9script
1100      export def Funcx()
1101        g:result = 42
1102      enddef
1103  END
1104  writefile(lines, 'XsomeExport.vim')
1105  lines =<< trim END
1106      vim9script
1107      import Funcx from './XsomeExport.vim'
1108      nnoremap <F3> :call <sid>Funcx()<cr>
1109  END
1110  writefile(lines, 'Xmapscript.vim')
1111
1112  source Xmapscript.vim
1113  feedkeys("\<F3>", "xt")
1114  assert_equal(42, g:result)
1115
1116  unlet g:result
1117  delete('XsomeExport.vim')
1118  delete('Xmapscript.vim')
1119  nunmap <F3>
1120enddef
1121
1122def Test_vim9script_fails()
1123  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1124  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1125  CheckScriptFailure(['export var some = 123'], 'E1042:')
1126  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1127  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1128  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1129
1130  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1131  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1132
1133  assert_fails('vim9script', 'E1038:')
1134  assert_fails('export something', 'E1043:')
1135enddef
1136
1137func Test_import_fails_without_script()
1138  CheckRunVimInTerminal
1139
1140  " call indirectly to avoid compilation error for missing functions
1141  call Run_Test_import_fails_on_command_line()
1142endfunc
1143
1144def Run_Test_import_fails_on_command_line()
1145  var export =<< trim END
1146    vim9script
1147    export def Foo(): number
1148        return 0
1149    enddef
1150  END
1151  writefile(export, 'XexportCmd.vim')
1152
1153  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1154                rows: 6, wait_for_ruler: 0})
1155  WaitForAssert({-> assert_match('^E1094:', term_getline(buf, 5))})
1156
1157  delete('XexportCmd.vim')
1158  StopVimInTerminal(buf)
1159enddef
1160
1161def Test_vim9script_reload_import()
1162  var lines =<< trim END
1163    vim9script
1164    const var = ''
1165    var valone = 1234
1166    def MyFunc(arg: string)
1167       valone = 5678
1168    enddef
1169  END
1170  var morelines =<< trim END
1171    var valtwo = 222
1172    export def GetValtwo(): number
1173      return valtwo
1174    enddef
1175  END
1176  writefile(lines + morelines, 'Xreload.vim')
1177  source Xreload.vim
1178  source Xreload.vim
1179  source Xreload.vim
1180
1181  var testlines =<< trim END
1182    vim9script
1183    def TheFunc()
1184      import GetValtwo from './Xreload.vim'
1185      assert_equal(222, GetValtwo())
1186    enddef
1187    TheFunc()
1188  END
1189  writefile(testlines, 'Ximport.vim')
1190  source Ximport.vim
1191
1192  # Test that when not using "morelines" GetValtwo() and valtwo are still
1193  # defined, because import doesn't reload a script.
1194  writefile(lines, 'Xreload.vim')
1195  source Ximport.vim
1196
1197  # cannot declare a var twice
1198  lines =<< trim END
1199    vim9script
1200    var valone = 1234
1201    var valone = 5678
1202  END
1203  writefile(lines, 'Xreload.vim')
1204  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1205
1206  delete('Xreload.vim')
1207  delete('Ximport.vim')
1208enddef
1209
1210def s:RetSome(): string
1211  return 'some'
1212enddef
1213
1214" Not exported function that is referenced needs to be accessed by the
1215" script-local name.
1216def Test_vim9script_funcref()
1217  var sortlines =<< trim END
1218      vim9script
1219      def Compare(i1: number, i2: number): number
1220        return i2 - i1
1221      enddef
1222
1223      export def FastSort(): list<number>
1224        return range(5)->sort(Compare)
1225      enddef
1226  END
1227  writefile(sortlines, 'Xsort.vim')
1228
1229  var lines =<< trim END
1230    vim9script
1231    import FastSort from './Xsort.vim'
1232    def Test()
1233      g:result = FastSort()
1234    enddef
1235    Test()
1236  END
1237  writefile(lines, 'Xscript.vim')
1238
1239  source Xscript.vim
1240  assert_equal([4, 3, 2, 1, 0], g:result)
1241
1242  unlet g:result
1243  delete('Xsort.vim')
1244  delete('Xscript.vim')
1245
1246  var Funcref = function('s:RetSome')
1247  assert_equal('some', Funcref())
1248enddef
1249
1250" Check that when searching for "FilterFunc" it finds the import in the
1251" script where FastFilter() is called from, both as a string and as a direct
1252" function reference.
1253def Test_vim9script_funcref_other_script()
1254  var filterLines =<< trim END
1255    vim9script
1256    export def FilterFunc(idx: number, val: number): bool
1257      return idx % 2 == 1
1258    enddef
1259    export def FastFilter(): list<number>
1260      return range(10)->filter('FilterFunc')
1261    enddef
1262    export def FastFilterDirect(): list<number>
1263      return range(10)->filter(FilterFunc)
1264    enddef
1265  END
1266  writefile(filterLines, 'Xfilter.vim')
1267
1268  var lines =<< trim END
1269    vim9script
1270    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1271    def Test()
1272      var x: list<number> = FastFilter()
1273    enddef
1274    Test()
1275    def TestDirect()
1276      var x: list<number> = FastFilterDirect()
1277    enddef
1278    TestDirect()
1279  END
1280  CheckScriptSuccess(lines)
1281  delete('Xfilter.vim')
1282enddef
1283
1284def Test_vim9script_reload_delfunc()
1285  var first_lines =<< trim END
1286    vim9script
1287    def FuncYes(): string
1288      return 'yes'
1289    enddef
1290  END
1291  var withno_lines =<< trim END
1292    def FuncNo(): string
1293      return 'no'
1294    enddef
1295    def g:DoCheck(no_exists: bool)
1296      assert_equal('yes', FuncYes())
1297      assert_equal('no', FuncNo())
1298    enddef
1299  END
1300  var nono_lines =<< trim END
1301    def g:DoCheck(no_exists: bool)
1302      assert_equal('yes', FuncYes())
1303      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
1304    enddef
1305  END
1306
1307  # FuncNo() is defined
1308  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1309  source Xreloaded.vim
1310  g:DoCheck(true)
1311
1312  # FuncNo() is not redefined
1313  writefile(first_lines + nono_lines, 'Xreloaded.vim')
1314  source Xreloaded.vim
1315  g:DoCheck()
1316
1317  # FuncNo() is back
1318  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1319  source Xreloaded.vim
1320  g:DoCheck()
1321
1322  delete('Xreloaded.vim')
1323enddef
1324
1325def Test_vim9script_reload_delvar()
1326  # write the script with a script-local variable
1327  var lines =<< trim END
1328    vim9script
1329    var name = 'string'
1330  END
1331  writefile(lines, 'XreloadVar.vim')
1332  source XreloadVar.vim
1333
1334  # now write the script using the same variable locally - works
1335  lines =<< trim END
1336    vim9script
1337    def Func()
1338      var name = 'string'
1339    enddef
1340  END
1341  writefile(lines, 'XreloadVar.vim')
1342  source XreloadVar.vim
1343
1344  delete('XreloadVar.vim')
1345enddef
1346
1347def Test_import_absolute()
1348  var import_lines = [
1349        'vim9script',
1350        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
1351        'def UseExported()',
1352        '  g:imported_abs = exported',
1353        '  exported = 8888',
1354        '  g:imported_after = exported',
1355        'enddef',
1356        'UseExported()',
1357        'g:import_disassembled = execute("disass UseExported")',
1358        ]
1359  writefile(import_lines, 'Ximport_abs.vim')
1360  writefile(s:export_script_lines, 'Xexport_abs.vim')
1361
1362  source Ximport_abs.vim
1363
1364  assert_equal(9876, g:imported_abs)
1365  assert_equal(8888, g:imported_after)
1366  assert_match('<SNR>\d\+_UseExported\_s*' ..
1367          'g:imported_abs = exported\_s*' ..
1368          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1369          '1 STOREG g:imported_abs\_s*' ..
1370          'exported = 8888\_s*' ..
1371          '2 PUSHNR 8888\_s*' ..
1372          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
1373          'g:imported_after = exported\_s*' ..
1374          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1375          '5 STOREG g:imported_after',
1376        g:import_disassembled)
1377
1378  Undo_export_script_lines()
1379  unlet g:imported_abs
1380  unlet g:import_disassembled
1381
1382  delete('Ximport_abs.vim')
1383  delete('Xexport_abs.vim')
1384enddef
1385
1386def Test_import_rtp()
1387  var import_lines = [
1388        'vim9script',
1389        'import exported from "Xexport_rtp.vim"',
1390        'g:imported_rtp = exported',
1391        ]
1392  writefile(import_lines, 'Ximport_rtp.vim')
1393  mkdir('import')
1394  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
1395
1396  var save_rtp = &rtp
1397  &rtp = getcwd()
1398  source Ximport_rtp.vim
1399  &rtp = save_rtp
1400
1401  assert_equal(9876, g:imported_rtp)
1402
1403  Undo_export_script_lines()
1404  unlet g:imported_rtp
1405  delete('Ximport_rtp.vim')
1406  delete('import', 'rf')
1407enddef
1408
1409def Test_import_compile_error()
1410  var export_lines = [
1411        'vim9script',
1412        'export def ExpFunc(): string',
1413        '  return notDefined',
1414        'enddef',
1415        ]
1416  writefile(export_lines, 'Xexported.vim')
1417
1418  var import_lines = [
1419        'vim9script',
1420        'import ExpFunc from "./Xexported.vim"',
1421        'def ImpFunc()',
1422        '  echo ExpFunc()',
1423        'enddef',
1424        'defcompile',
1425        ]
1426  writefile(import_lines, 'Ximport.vim')
1427
1428  try
1429    source Ximport.vim
1430  catch /E1001/
1431    # Error should be fore the Xexported.vim file.
1432    assert_match('E1001: Variable not found: notDefined', v:exception)
1433    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
1434  endtry
1435
1436  delete('Xexported.vim')
1437  delete('Ximport.vim')
1438enddef
1439
1440def Test_func_redefine_error()
1441  var lines = [
1442        'vim9script',
1443        'def Func()',
1444        '  eval [][0]',
1445        'enddef',
1446        'Func()',
1447        ]
1448  writefile(lines, 'Xtestscript.vim')
1449
1450  for count in range(3)
1451    try
1452      source Xtestscript.vim
1453    catch /E684/
1454      # function name should contain <SNR> every time
1455      assert_match('E684: list index out of range', v:exception)
1456      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
1457    endtry
1458  endfor
1459
1460  delete('Xtestscript.vim')
1461enddef
1462
1463def Test_func_overrules_import_fails()
1464  var export_lines =<< trim END
1465      vim9script
1466      export def Func()
1467        echo 'imported'
1468      enddef
1469  END
1470  writefile(export_lines, 'XexportedFunc.vim')
1471
1472  var lines =<< trim END
1473    vim9script
1474    import Func from './XexportedFunc.vim'
1475    def Func()
1476      echo 'local to function'
1477    enddef
1478  END
1479  CheckScriptFailure(lines, 'E1073:')
1480
1481  lines =<< trim END
1482    vim9script
1483    import Func from './XexportedFunc.vim'
1484    def Outer()
1485      def Func()
1486        echo 'local to function'
1487      enddef
1488    enddef
1489    defcompile
1490  END
1491  CheckScriptFailure(lines, 'E1073:')
1492
1493  delete('XexportedFunc.vim')
1494enddef
1495
1496def Test_func_redefine_fails()
1497  var lines =<< trim END
1498    vim9script
1499    def Func()
1500      echo 'one'
1501    enddef
1502    def Func()
1503      echo 'two'
1504    enddef
1505  END
1506  CheckScriptFailure(lines, 'E1073:')
1507
1508  lines =<< trim END
1509    vim9script
1510    def Foo(): string
1511      return 'foo'
1512      enddef
1513    def Func()
1514      var  Foo = {-> 'lambda'}
1515    enddef
1516    defcompile
1517  END
1518  CheckScriptFailure(lines, 'E1073:')
1519enddef
1520
1521def Test_fixed_size_list()
1522  # will be allocated as one piece of memory, check that changes work
1523  var l = [1, 2, 3, 4]
1524  l->remove(0)
1525  l->add(5)
1526  l->insert(99, 1)
1527  assert_equal([2, 99, 3, 4, 5], l)
1528enddef
1529
1530def Test_no_insert_xit()
1531  CheckDefExecFailure(['a = 1'], 'E1100:')
1532  CheckDefExecFailure(['c = 1'], 'E1100:')
1533  CheckDefExecFailure(['i = 1'], 'E1100:')
1534  CheckDefExecFailure(['t = 1'], 'E1100:')
1535  CheckDefExecFailure(['x = 1'], 'E1100:')
1536
1537  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
1538  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
1539  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
1540  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
1541  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
1542  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
1543  CheckScriptFailure(['vim9script', 't'], 'E1100:')
1544  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
1545  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
1546enddef
1547
1548def IfElse(what: number): string
1549  var res = ''
1550  if what == 1
1551    res = "one"
1552  elseif what == 2
1553    res = "two"
1554  else
1555    res = "three"
1556  endif
1557  return res
1558enddef
1559
1560def Test_if_elseif_else()
1561  assert_equal('one', IfElse(1))
1562  assert_equal('two', IfElse(2))
1563  assert_equal('three', IfElse(3))
1564enddef
1565
1566def Test_if_elseif_else_fails()
1567  CheckDefFailure(['elseif true'], 'E582:')
1568  CheckDefFailure(['else'], 'E581:')
1569  CheckDefFailure(['endif'], 'E580:')
1570  CheckDefFailure(['if true', 'elseif xxx'], 'E1001:')
1571  CheckDefFailure(['if true', 'echo 1'], 'E171:')
1572enddef
1573
1574let g:bool_true = v:true
1575let g:bool_false = v:false
1576
1577def Test_if_const_expr()
1578  var res = false
1579  if true ? true : false
1580    res = true
1581  endif
1582  assert_equal(true, res)
1583
1584  g:glob = 2
1585  if false
1586    execute('g:glob = 3')
1587  endif
1588  assert_equal(2, g:glob)
1589  if true
1590    execute('g:glob = 3')
1591  endif
1592  assert_equal(3, g:glob)
1593
1594  res = false
1595  if g:bool_true ? true : false
1596    res = true
1597  endif
1598  assert_equal(true, res)
1599
1600  res = false
1601  if true ? g:bool_true : false
1602    res = true
1603  endif
1604  assert_equal(true, res)
1605
1606  res = false
1607  if true ? true : g:bool_false
1608    res = true
1609  endif
1610  assert_equal(true, res)
1611
1612  res = false
1613  if true ? false : true
1614    res = true
1615  endif
1616  assert_equal(false, res)
1617
1618  res = false
1619  if false ? false : true
1620    res = true
1621  endif
1622  assert_equal(true, res)
1623
1624  res = false
1625  if false ? true : false
1626    res = true
1627  endif
1628  assert_equal(false, res)
1629
1630  res = false
1631  if has('xyz') ? true : false
1632    res = true
1633  endif
1634  assert_equal(false, res)
1635
1636  res = false
1637  if true && true
1638    res = true
1639  endif
1640  assert_equal(true, res)
1641
1642  res = false
1643  if true && false
1644    res = true
1645  endif
1646  assert_equal(false, res)
1647
1648  res = false
1649  if g:bool_true && false
1650    res = true
1651  endif
1652  assert_equal(false, res)
1653
1654  res = false
1655  if true && g:bool_false
1656    res = true
1657  endif
1658  assert_equal(false, res)
1659
1660  res = false
1661  if false && false
1662    res = true
1663  endif
1664  assert_equal(false, res)
1665
1666  res = false
1667  if true || false
1668    res = true
1669  endif
1670  assert_equal(true, res)
1671
1672  res = false
1673  if g:bool_true || false
1674    res = true
1675  endif
1676  assert_equal(true, res)
1677
1678  res = false
1679  if true || g:bool_false
1680    res = true
1681  endif
1682  assert_equal(true, res)
1683
1684  res = false
1685  if false || false
1686    res = true
1687  endif
1688  assert_equal(false, res)
1689
1690  # with constant "false" expression may be invalid so long as the syntax is OK
1691  if false | eval 0 | endif
1692  if false | eval burp + 234 | endif
1693  if false | echo burp 234 'asd' | endif
1694  if false
1695    burp
1696  endif
1697enddef
1698
1699def Test_if_const_expr_fails()
1700  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
1701  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
1702  CheckDefFailure(["if has('aaa'"], 'E110:')
1703  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
1704enddef
1705
1706def RunNested(i: number): number
1707  var x: number = 0
1708  if i % 2
1709    if 1
1710      # comment
1711    else
1712      # comment
1713    endif
1714    x += 1
1715  else
1716    x += 1000
1717  endif
1718  return x
1719enddef
1720
1721def Test_nested_if()
1722  assert_equal(1, RunNested(1))
1723  assert_equal(1000, RunNested(2))
1724enddef
1725
1726def Test_execute_cmd()
1727  # missing argument is ignored
1728  execute
1729  execute # comment
1730
1731  new
1732  setline(1, 'default')
1733  execute 'setline(1, "execute-string")'
1734  assert_equal('execute-string', getline(1))
1735
1736  execute "setline(1, 'execute-string')"
1737  assert_equal('execute-string', getline(1))
1738
1739  var cmd1 = 'setline(1,'
1740  var cmd2 = '"execute-var")'
1741  execute cmd1 cmd2 # comment
1742  assert_equal('execute-var', getline(1))
1743
1744  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
1745  assert_equal('execute-var-string', getline(1))
1746
1747  var cmd_first = 'call '
1748  var cmd_last = 'setline(1, "execute-var-var")'
1749  execute cmd_first .. cmd_last
1750  assert_equal('execute-var-var', getline(1))
1751  bwipe!
1752
1753  var n = true
1754  execute 'echomsg' (n ? '"true"' : '"no"')
1755  assert_match('^true$', Screenline(&lines))
1756
1757  echomsg [1, 2, 3] {a: 1, b: 2}
1758  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
1759
1760  CheckDefFailure(['execute xxx'], 'E1001:', 1)
1761  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
1762  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
1763enddef
1764
1765def Test_execute_cmd_vimscript()
1766  # only checks line continuation
1767  var lines =<< trim END
1768      vim9script
1769      execute 'g:someVar'
1770                .. ' = ' ..
1771                   '28'
1772      assert_equal(28, g:someVar)
1773      unlet g:someVar
1774  END
1775  CheckScriptSuccess(lines)
1776enddef
1777
1778def Test_echo_cmd()
1779  echo 'some' # comment
1780  echon 'thing'
1781  assert_match('^something$', Screenline(&lines))
1782
1783  echo "some" # comment
1784  echon "thing"
1785  assert_match('^something$', Screenline(&lines))
1786
1787  var str1 = 'some'
1788  var str2 = 'more'
1789  echo str1 str2
1790  assert_match('^some more$', Screenline(&lines))
1791
1792  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
1793enddef
1794
1795def Test_echomsg_cmd()
1796  echomsg 'some' 'more' # comment
1797  assert_match('^some more$', Screenline(&lines))
1798  echo 'clear'
1799  :1messages
1800  assert_match('^some more$', Screenline(&lines))
1801
1802  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
1803enddef
1804
1805def Test_echomsg_cmd_vimscript()
1806  # only checks line continuation
1807  var lines =<< trim END
1808      vim9script
1809      echomsg 'here'
1810                .. ' is ' ..
1811                   'a message'
1812      assert_match('^here is a message$', Screenline(&lines))
1813  END
1814  CheckScriptSuccess(lines)
1815enddef
1816
1817def Test_echoerr_cmd()
1818  try
1819    echoerr 'something' 'wrong' # comment
1820  catch
1821    assert_match('something wrong', v:exception)
1822  endtry
1823enddef
1824
1825def Test_echoerr_cmd_vimscript()
1826  # only checks line continuation
1827  var lines =<< trim END
1828      vim9script
1829      try
1830        echoerr 'this'
1831                .. ' is ' ..
1832                   'wrong'
1833      catch
1834        assert_match('this is wrong', v:exception)
1835      endtry
1836  END
1837  CheckScriptSuccess(lines)
1838enddef
1839
1840def Test_for_outside_of_function()
1841  var lines =<< trim END
1842    vim9script
1843    new
1844    for var in range(0, 3)
1845      append(line('$'), var)
1846    endfor
1847    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
1848    bwipe!
1849  END
1850  writefile(lines, 'Xvim9for.vim')
1851  source Xvim9for.vim
1852  delete('Xvim9for.vim')
1853enddef
1854
1855def Test_for_loop()
1856  var result = ''
1857  for cnt in range(7)
1858    if cnt == 4
1859      break
1860    endif
1861    if cnt == 2
1862      continue
1863    endif
1864    result ..= cnt .. '_'
1865  endfor
1866  assert_equal('0_1_3_', result)
1867
1868  var concat = ''
1869  for str in eval('["one", "two"]')
1870    concat ..= str
1871  endfor
1872  assert_equal('onetwo', concat)
1873
1874  var total = 0
1875  for nr in
1876      [1, 2, 3]
1877    total += nr
1878  endfor
1879  assert_equal(6, total)
1880
1881  total = 0
1882  for nr
1883    in [1, 2, 3]
1884    total += nr
1885  endfor
1886  assert_equal(6, total)
1887
1888  total = 0
1889  for nr
1890    in
1891    [1, 2, 3]
1892    total += nr
1893  endfor
1894  assert_equal(6, total)
1895enddef
1896
1897def Test_for_loop_fails()
1898  CheckDefFailure(['for '], 'E1097:')
1899  CheckDefFailure(['for x'], 'E1097:')
1900  CheckDefFailure(['for x in'], 'E1097:')
1901  CheckDefFailure(['for # in range(5)'], 'E690:')
1902  CheckDefFailure(['for i In range(5)'], 'E690:')
1903  CheckDefFailure(['var x = 5', 'for x in range(5)'], 'E1017:')
1904  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
1905  delfunc! g:Func
1906  CheckDefFailure(['for i in "text"'], 'E1012:')
1907  CheckDefFailure(['for i in xxx'], 'E1001:')
1908  CheckDefFailure(['endfor'], 'E588:')
1909  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
1910enddef
1911
1912def Test_for_loop_script_var()
1913  # cannot use s:var in a :def function
1914  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
1915
1916  # can use s:var in Vim9 script, with or without s:
1917  var lines =<< trim END
1918    vim9script
1919    var total = 0
1920    for s:var in [1, 2, 3]
1921      total += s:var
1922    endfor
1923    assert_equal(6, total)
1924
1925    total = 0
1926    for var in [1, 2, 3]
1927      total += var
1928    endfor
1929    assert_equal(6, total)
1930  END
1931enddef
1932
1933def Test_for_loop_unpack()
1934  var lines =<< trim END
1935      var result = []
1936      for [v1, v2] in [[1, 2], [3, 4]]
1937        result->add(v1)
1938        result->add(v2)
1939      endfor
1940      assert_equal([1, 2, 3, 4], result)
1941
1942      result = []
1943      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
1944        result->add(v1)
1945        result->add(v2)
1946        result->add(v3)
1947      endfor
1948      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
1949
1950      result = []
1951      for [&ts, &sw] in [[1, 2], [3, 4]]
1952        result->add(&ts)
1953        result->add(&sw)
1954      endfor
1955      assert_equal([1, 2, 3, 4], result)
1956
1957      var slist: list<string>
1958      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
1959        slist->add($LOOPVAR)
1960        slist->add(@r)
1961        slist->add(v:errmsg)
1962      endfor
1963      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
1964
1965      slist = []
1966      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
1967        slist->add(g:globalvar)
1968        slist->add(b:bufvar)
1969        slist->add(w:winvar)
1970        slist->add(t:tabvar)
1971      endfor
1972      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
1973      unlet! g:globalvar b:bufvar w:winvar t:tabvar
1974  END
1975  CheckDefAndScriptSuccess(lines)
1976
1977  lines =<< trim END
1978      for [v1, v2] in [[1, 2, 3], [3, 4]]
1979        echo v1 v2
1980      endfor
1981  END
1982  CheckDefExecFailure(lines, 'E710:', 1)
1983
1984  lines =<< trim END
1985      for [v1, v2] in [[1], [3, 4]]
1986        echo v1 v2
1987      endfor
1988  END
1989  CheckDefExecFailure(lines, 'E711:', 1)
1990
1991  lines =<< trim END
1992      for [v1, v1] in [[1, 2], [3, 4]]
1993        echo v1
1994      endfor
1995  END
1996  CheckDefExecFailure(lines, 'E1017:', 1)
1997enddef
1998
1999def Test_while_loop()
2000  var result = ''
2001  var cnt = 0
2002  while cnt < 555
2003    if cnt == 3
2004      break
2005    endif
2006    cnt += 1
2007    if cnt == 2
2008      continue
2009    endif
2010    result ..= cnt .. '_'
2011  endwhile
2012  assert_equal('1_3_', result)
2013enddef
2014
2015def Test_while_loop_fails()
2016  CheckDefFailure(['while xxx'], 'E1001:')
2017  CheckDefFailure(['endwhile'], 'E588:')
2018  CheckDefFailure(['continue'], 'E586:')
2019  CheckDefFailure(['if true', 'continue'], 'E586:')
2020  CheckDefFailure(['break'], 'E587:')
2021  CheckDefFailure(['if true', 'break'], 'E587:')
2022  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
2023enddef
2024
2025def Test_interrupt_loop()
2026  var caught = false
2027  var x = 0
2028  try
2029    while 1
2030      x += 1
2031      if x == 100
2032        feedkeys("\<C-C>", 'Lt')
2033      endif
2034    endwhile
2035  catch
2036    caught = true
2037    assert_equal(100, x)
2038  endtry
2039  assert_true(caught, 'should have caught an exception')
2040  # consume the CTRL-C
2041  getchar(0)
2042enddef
2043
2044def Test_automatic_line_continuation()
2045  var mylist = [
2046      'one',
2047      'two',
2048      'three',
2049      ] # comment
2050  assert_equal(['one', 'two', 'three'], mylist)
2051
2052  var mydict = {
2053      ['one']: 1,
2054      ['two']: 2,
2055      ['three']:
2056          3,
2057      } # comment
2058  assert_equal({one: 1, two: 2, three: 3}, mydict)
2059  mydict = {
2060      one: 1,  # comment
2061      two:     # comment
2062           2,  # comment
2063      three: 3 # comment
2064      }
2065  assert_equal({one: 1, two: 2, three: 3}, mydict)
2066  mydict = {
2067      one: 1,
2068      two:
2069           2,
2070      three: 3
2071      }
2072  assert_equal({one: 1, two: 2, three: 3}, mydict)
2073
2074  assert_equal(
2075        ['one', 'two', 'three'],
2076        split('one two three')
2077        )
2078enddef
2079
2080def Test_vim9_comment()
2081  CheckScriptSuccess([
2082      'vim9script',
2083      '# something',
2084      '#something',
2085      '#{something',
2086      ])
2087
2088  split Xfile
2089  CheckScriptSuccess([
2090      'vim9script',
2091      'edit #something',
2092      ])
2093  CheckScriptSuccess([
2094      'vim9script',
2095      'edit #{something',
2096      ])
2097  close
2098
2099  CheckScriptFailure([
2100      'vim9script',
2101      ':# something',
2102      ], 'E488:')
2103  CheckScriptFailure([
2104      '# something',
2105      ], 'E488:')
2106  CheckScriptFailure([
2107      ':# something',
2108      ], 'E488:')
2109
2110  { # block start
2111  } # block end
2112  CheckDefFailure([
2113      '{# comment',
2114      ], 'E488:')
2115  CheckDefFailure([
2116      '{',
2117      '}# comment',
2118      ], 'E488:')
2119
2120  echo "yes" # comment
2121  CheckDefFailure([
2122      'echo "yes"# comment',
2123      ], 'E488:')
2124  CheckScriptSuccess([
2125      'vim9script',
2126      'echo "yes" # something',
2127      ])
2128  CheckScriptFailure([
2129      'vim9script',
2130      'echo "yes"# something',
2131      ], 'E121:')
2132  CheckScriptFailure([
2133      'vim9script',
2134      'echo# something',
2135      ], 'E121:')
2136  CheckScriptFailure([
2137      'echo "yes" # something',
2138      ], 'E121:')
2139
2140  exe "echo" # comment
2141  CheckDefFailure([
2142      'exe "echo"# comment',
2143      ], 'E488:')
2144  CheckScriptSuccess([
2145      'vim9script',
2146      'exe "echo" # something',
2147      ])
2148  CheckScriptFailure([
2149      'vim9script',
2150      'exe "echo"# something',
2151      ], 'E121:')
2152  CheckScriptFailure([
2153      'vim9script',
2154      'exe# something',
2155      ], 'E121:')
2156  CheckScriptFailure([
2157      'exe "echo" # something',
2158      ], 'E121:')
2159
2160  CheckDefFailure([
2161      'try# comment',
2162      '  echo "yes"',
2163      'catch',
2164      'endtry',
2165      ], 'E488:')
2166  CheckScriptFailure([
2167      'vim9script',
2168      'try# comment',
2169      'echo "yes"',
2170      ], 'E488:')
2171  CheckDefFailure([
2172      'try',
2173      '  throw#comment',
2174      'catch',
2175      'endtry',
2176      ], 'E1143:')
2177  CheckDefFailure([
2178      'try',
2179      '  throw "yes"#comment',
2180      'catch',
2181      'endtry',
2182      ], 'E488:')
2183  CheckDefFailure([
2184      'try',
2185      '  echo "yes"',
2186      'catch# comment',
2187      'endtry',
2188      ], 'E488:')
2189  CheckScriptFailure([
2190      'vim9script',
2191      'try',
2192      '  echo "yes"',
2193      'catch# comment',
2194      'endtry',
2195      ], 'E654:')
2196  CheckDefFailure([
2197      'try',
2198      '  echo "yes"',
2199      'catch /pat/# comment',
2200      'endtry',
2201      ], 'E488:')
2202  CheckDefFailure([
2203      'try',
2204      'echo "yes"',
2205      'catch',
2206      'endtry# comment',
2207      ], 'E488:')
2208  CheckScriptFailure([
2209      'vim9script',
2210      'try',
2211      '  echo "yes"',
2212      'catch',
2213      'endtry# comment',
2214      ], 'E488:')
2215
2216  CheckScriptSuccess([
2217      'vim9script',
2218      'hi # comment',
2219      ])
2220  CheckScriptFailure([
2221      'vim9script',
2222      'hi# comment',
2223      ], 'E416:')
2224  CheckScriptSuccess([
2225      'vim9script',
2226      'hi Search # comment',
2227      ])
2228  CheckScriptFailure([
2229      'vim9script',
2230      'hi Search# comment',
2231      ], 'E416:')
2232  CheckScriptSuccess([
2233      'vim9script',
2234      'hi link This Search # comment',
2235      ])
2236  CheckScriptFailure([
2237      'vim9script',
2238      'hi link This That# comment',
2239      ], 'E413:')
2240  CheckScriptSuccess([
2241      'vim9script',
2242      'hi clear This # comment',
2243      'hi clear # comment',
2244      ])
2245  # not tested, because it doesn't give an error but a warning:
2246  # hi clear This# comment',
2247  CheckScriptFailure([
2248      'vim9script',
2249      'hi clear# comment',
2250      ], 'E416:')
2251
2252  CheckScriptSuccess([
2253      'vim9script',
2254      'hi Group term=bold',
2255      'match Group /todo/ # comment',
2256      ])
2257  CheckScriptFailure([
2258      'vim9script',
2259      'hi Group term=bold',
2260      'match Group /todo/# comment',
2261      ], 'E488:')
2262  CheckScriptSuccess([
2263      'vim9script',
2264      'match # comment',
2265      ])
2266  CheckScriptFailure([
2267      'vim9script',
2268      'match# comment',
2269      ], 'E475:')
2270  CheckScriptSuccess([
2271      'vim9script',
2272      'match none # comment',
2273      ])
2274  CheckScriptFailure([
2275      'vim9script',
2276      'match none# comment',
2277      ], 'E475:')
2278
2279  CheckScriptSuccess([
2280      'vim9script',
2281      'menutrans clear # comment',
2282      ])
2283  CheckScriptFailure([
2284      'vim9script',
2285      'menutrans clear# comment text',
2286      ], 'E474:')
2287
2288  CheckScriptSuccess([
2289      'vim9script',
2290      'syntax clear # comment',
2291      ])
2292  CheckScriptFailure([
2293      'vim9script',
2294      'syntax clear# comment text',
2295      ], 'E28:')
2296  CheckScriptSuccess([
2297      'vim9script',
2298      'syntax keyword Word some',
2299      'syntax clear Word # comment',
2300      ])
2301  CheckScriptFailure([
2302      'vim9script',
2303      'syntax keyword Word some',
2304      'syntax clear Word# comment text',
2305      ], 'E28:')
2306
2307  CheckScriptSuccess([
2308      'vim9script',
2309      'syntax list # comment',
2310      ])
2311  CheckScriptFailure([
2312      'vim9script',
2313      'syntax list# comment text',
2314      ], 'E28:')
2315
2316  CheckScriptSuccess([
2317      'vim9script',
2318      'syntax match Word /pat/ oneline # comment',
2319      ])
2320  CheckScriptFailure([
2321      'vim9script',
2322      'syntax match Word /pat/ oneline# comment',
2323      ], 'E475:')
2324
2325  CheckScriptSuccess([
2326      'vim9script',
2327      'syntax keyword Word word # comm[ent',
2328      ])
2329  CheckScriptFailure([
2330      'vim9script',
2331      'syntax keyword Word word# comm[ent',
2332      ], 'E789:')
2333
2334  CheckScriptSuccess([
2335      'vim9script',
2336      'syntax match Word /pat/ # comment',
2337      ])
2338  CheckScriptFailure([
2339      'vim9script',
2340      'syntax match Word /pat/# comment',
2341      ], 'E402:')
2342
2343  CheckScriptSuccess([
2344      'vim9script',
2345      'syntax match Word /pat/ contains=Something # comment',
2346      ])
2347  CheckScriptFailure([
2348      'vim9script',
2349      'syntax match Word /pat/ contains=Something# comment',
2350      ], 'E475:')
2351  CheckScriptFailure([
2352      'vim9script',
2353      'syntax match Word /pat/ contains= # comment',
2354      ], 'E406:')
2355  CheckScriptFailure([
2356      'vim9script',
2357      'syntax match Word /pat/ contains=# comment',
2358      ], 'E475:')
2359
2360  CheckScriptSuccess([
2361      'vim9script',
2362      'syntax region Word start=/pat/ end=/pat/ # comment',
2363      ])
2364  CheckScriptFailure([
2365      'vim9script',
2366      'syntax region Word start=/pat/ end=/pat/# comment',
2367      ], 'E402:')
2368
2369  CheckScriptSuccess([
2370      'vim9script',
2371      'syntax sync # comment',
2372      ])
2373  CheckScriptFailure([
2374      'vim9script',
2375      'syntax sync# comment',
2376      ], 'E404:')
2377  CheckScriptSuccess([
2378      'vim9script',
2379      'syntax sync ccomment # comment',
2380      ])
2381  CheckScriptFailure([
2382      'vim9script',
2383      'syntax sync ccomment# comment',
2384      ], 'E404:')
2385
2386  CheckScriptSuccess([
2387      'vim9script',
2388      'syntax cluster Some contains=Word # comment',
2389      ])
2390  CheckScriptFailure([
2391      'vim9script',
2392      'syntax cluster Some contains=Word# comment',
2393      ], 'E475:')
2394
2395  CheckScriptSuccess([
2396      'vim9script',
2397      'command Echo echo # comment',
2398      'command Echo # comment',
2399      'delcommand Echo',
2400      ])
2401  CheckScriptFailure([
2402      'vim9script',
2403      'command Echo echo# comment',
2404      'Echo',
2405      ], 'E121:')
2406  delcommand Echo
2407
2408  var curdir = getcwd()
2409  CheckScriptSuccess([
2410      'command Echo cd " comment',
2411      'Echo',
2412      'delcommand Echo',
2413      ])
2414  CheckScriptSuccess([
2415      'vim9script'
2416      'command Echo cd # comment',
2417      'Echo',
2418      'delcommand Echo',
2419      ])
2420  CheckScriptFailure([
2421      'vim9script',
2422      'command Echo cd " comment',
2423      'Echo',
2424      ], 'E344:')
2425  delcommand Echo
2426  chdir(curdir)
2427
2428  CheckScriptFailure([
2429      'vim9script',
2430      'command Echo# comment',
2431      ], 'E182:')
2432  CheckScriptFailure([
2433      'vim9script',
2434      'command Echo echo',
2435      'command Echo# comment',
2436      ], 'E182:')
2437  delcommand Echo
2438
2439  CheckScriptSuccess([
2440      'vim9script',
2441      'function # comment',
2442      ])
2443  CheckScriptFailure([
2444      'vim9script',
2445      'function " comment',
2446      ], 'E129:')
2447  CheckScriptFailure([
2448      'vim9script',
2449      'function# comment',
2450      ], 'E129:')
2451  CheckScriptSuccess([
2452      'vim9script',
2453      'function CheckScriptSuccess # comment',
2454      ])
2455  CheckScriptFailure([
2456      'vim9script',
2457      'function CheckScriptSuccess# comment',
2458      ], 'E488:')
2459
2460  CheckScriptSuccess([
2461      'vim9script',
2462      'func g:DeleteMeA()',
2463      'endfunc',
2464      'delfunction g:DeleteMeA # comment',
2465      ])
2466  CheckScriptFailure([
2467      'vim9script',
2468      'func g:DeleteMeB()',
2469      'endfunc',
2470      'delfunction g:DeleteMeB# comment',
2471      ], 'E488:')
2472
2473  CheckScriptSuccess([
2474      'vim9script',
2475      'call execute("ls") # comment',
2476      ])
2477  CheckScriptFailure([
2478      'vim9script',
2479      'call execute("ls")# comment',
2480      ], 'E488:')
2481
2482  CheckScriptFailure([
2483      'def Test() " comment',
2484      'enddef',
2485      ], 'E488:')
2486  CheckScriptFailure([
2487      'vim9script',
2488      'def Test() " comment',
2489      'enddef',
2490      ], 'E488:')
2491
2492  CheckScriptSuccess([
2493      'func Test() " comment',
2494      'endfunc',
2495      'delfunc Test',
2496      ])
2497  CheckScriptSuccess([
2498      'vim9script',
2499      'func Test() " comment',
2500      'endfunc',
2501      ])
2502
2503  CheckScriptSuccess([
2504      'def Test() # comment',
2505      'enddef',
2506      ])
2507  CheckScriptFailure([
2508      'func Test() # comment',
2509      'endfunc',
2510      ], 'E488:')
2511enddef
2512
2513def Test_vim9_comment_gui()
2514  CheckCanRunGui
2515
2516  CheckScriptFailure([
2517      'vim9script',
2518      'gui#comment'
2519      ], 'E499:')
2520  CheckScriptFailure([
2521      'vim9script',
2522      'gui -f#comment'
2523      ], 'E499:')
2524enddef
2525
2526def Test_vim9_comment_not_compiled()
2527  au TabEnter *.vim g:entered = 1
2528  au TabEnter *.x g:entered = 2
2529
2530  edit test.vim
2531  doautocmd TabEnter #comment
2532  assert_equal(1, g:entered)
2533
2534  doautocmd TabEnter f.x
2535  assert_equal(2, g:entered)
2536
2537  g:entered = 0
2538  doautocmd TabEnter f.x #comment
2539  assert_equal(2, g:entered)
2540
2541  assert_fails('doautocmd Syntax#comment', 'E216:')
2542
2543  au! TabEnter
2544  unlet g:entered
2545
2546  CheckScriptSuccess([
2547      'vim9script',
2548      'g:var = 123',
2549      'b:var = 456',
2550      'w:var = 777',
2551      't:var = 888',
2552      'unlet g:var w:var # something',
2553      ])
2554
2555  CheckScriptFailure([
2556      'vim9script',
2557      'let var = 123',
2558      ], 'E1126: Cannot use :let in Vim9 script')
2559
2560  CheckScriptFailure([
2561      'vim9script',
2562      'var g:var = 123',
2563      ], 'E1016: Cannot declare a global variable:')
2564
2565  CheckScriptFailure([
2566      'vim9script',
2567      'var b:var = 123',
2568      ], 'E1016: Cannot declare a buffer variable:')
2569
2570  CheckScriptFailure([
2571      'vim9script',
2572      'var w:var = 123',
2573      ], 'E1016: Cannot declare a window variable:')
2574
2575  CheckScriptFailure([
2576      'vim9script',
2577      'var t:var = 123',
2578      ], 'E1016: Cannot declare a tab variable:')
2579
2580  CheckScriptFailure([
2581      'vim9script',
2582      'var v:version = 123',
2583      ], 'E1016: Cannot declare a v: variable:')
2584
2585  CheckScriptFailure([
2586      'vim9script',
2587      'var $VARIABLE = "text"',
2588      ], 'E1016: Cannot declare an environment variable:')
2589
2590  CheckScriptFailure([
2591      'vim9script',
2592      'g:var = 123',
2593      'unlet g:var# comment1',
2594      ], 'E108:')
2595
2596  CheckScriptFailure([
2597      'let g:var = 123',
2598      'unlet g:var # something',
2599      ], 'E488:')
2600
2601  CheckScriptSuccess([
2602      'vim9script',
2603      'if 1 # comment2',
2604      '  echo "yes"',
2605      'elseif 2 #comment',
2606      '  echo "no"',
2607      'endif',
2608      ])
2609
2610  CheckScriptFailure([
2611      'vim9script',
2612      'if 1# comment3',
2613      '  echo "yes"',
2614      'endif',
2615      ], 'E15:')
2616
2617  CheckScriptFailure([
2618      'vim9script',
2619      'if 0 # comment4',
2620      '  echo "yes"',
2621      'elseif 2#comment',
2622      '  echo "no"',
2623      'endif',
2624      ], 'E15:')
2625
2626  CheckScriptSuccess([
2627      'vim9script',
2628      'var v = 1 # comment5',
2629      ])
2630
2631  CheckScriptFailure([
2632      'vim9script',
2633      'var v = 1# comment6',
2634      ], 'E15:')
2635
2636  CheckScriptSuccess([
2637      'vim9script',
2638      'new'
2639      'setline(1, ["# define pat", "last"])',
2640      ':$',
2641      'dsearch /pat/ #comment',
2642      'bwipe!',
2643      ])
2644
2645  CheckScriptFailure([
2646      'vim9script',
2647      'new'
2648      'setline(1, ["# define pat", "last"])',
2649      ':$',
2650      'dsearch /pat/#comment',
2651      'bwipe!',
2652      ], 'E488:')
2653
2654  CheckScriptFailure([
2655      'vim9script',
2656      'func! SomeFunc()',
2657      ], 'E477:')
2658enddef
2659
2660def Test_finish()
2661  var lines =<< trim END
2662    vim9script
2663    g:res = 'one'
2664    if v:false | finish | endif
2665    g:res = 'two'
2666    finish
2667    g:res = 'three'
2668  END
2669  writefile(lines, 'Xfinished')
2670  source Xfinished
2671  assert_equal('two', g:res)
2672
2673  unlet g:res
2674  delete('Xfinished')
2675enddef
2676
2677def Test_forward_declaration()
2678  var lines =<< trim END
2679    vim9script
2680    def GetValue(): string
2681      return theVal
2682    enddef
2683    var theVal = 'something'
2684    g:initVal = GetValue()
2685    theVal = 'else'
2686    g:laterVal = GetValue()
2687  END
2688  writefile(lines, 'Xforward')
2689  source Xforward
2690  assert_equal('something', g:initVal)
2691  assert_equal('else', g:laterVal)
2692
2693  unlet g:initVal
2694  unlet g:laterVal
2695  delete('Xforward')
2696enddef
2697
2698def Test_source_vim9_from_legacy()
2699  var legacy_lines =<< trim END
2700    source Xvim9_script.vim
2701
2702    call assert_false(exists('local'))
2703    call assert_false(exists('exported'))
2704    call assert_false(exists('s:exported'))
2705    call assert_equal('global', global)
2706    call assert_equal('global', g:global)
2707
2708    " imported variable becomes script-local
2709    import exported from './Xvim9_script.vim'
2710    call assert_equal('exported', s:exported)
2711    call assert_false(exists('exported'))
2712
2713    " imported function becomes script-local
2714    import GetText from './Xvim9_script.vim'
2715    call assert_equal('text', s:GetText())
2716    call assert_false(exists('*GetText'))
2717  END
2718  writefile(legacy_lines, 'Xlegacy_script.vim')
2719
2720  var vim9_lines =<< trim END
2721    vim9script
2722    var local = 'local'
2723    g:global = 'global'
2724    export var exported = 'exported'
2725    export def GetText(): string
2726       return 'text'
2727    enddef
2728  END
2729  writefile(vim9_lines, 'Xvim9_script.vim')
2730
2731  source Xlegacy_script.vim
2732
2733  assert_equal('global', g:global)
2734  unlet g:global
2735
2736  delete('Xlegacy_script.vim')
2737  delete('Xvim9_script.vim')
2738enddef
2739
2740func Test_vim9script_not_global()
2741  " check that items defined in Vim9 script are script-local, not global
2742  let vim9lines =<< trim END
2743    vim9script
2744    var name = 'local'
2745    func TheFunc()
2746      echo 'local'
2747    endfunc
2748    def DefFunc()
2749      echo 'local'
2750    enddef
2751  END
2752  call writefile(vim9lines, 'Xvim9script.vim')
2753  source Xvim9script.vim
2754  try
2755    echo g:var
2756    assert_report('did not fail')
2757  catch /E121:/
2758    " caught
2759  endtry
2760  try
2761    call TheFunc()
2762    assert_report('did not fail')
2763  catch /E117:/
2764    " caught
2765  endtry
2766  try
2767    call DefFunc()
2768    assert_report('did not fail')
2769  catch /E117:/
2770    " caught
2771  endtry
2772
2773  call delete('Xvim9script.vim')
2774endfunc
2775
2776def Test_vim9_copen()
2777  # this was giving an error for setting w:quickfix_title
2778  copen
2779  quit
2780enddef
2781
2782" test using a vim9script that is auto-loaded from an autocmd
2783def Test_vim9_autoload()
2784  var lines =<< trim END
2785     vim9script
2786     def foo#test()
2787         echomsg getreg('"')
2788     enddef
2789  END
2790
2791  mkdir('Xdir/autoload', 'p')
2792  writefile(lines, 'Xdir/autoload/foo.vim')
2793  var save_rtp = &rtp
2794  exe 'set rtp^=' .. getcwd() .. '/Xdir'
2795  augroup test
2796    autocmd TextYankPost * call foo#test()
2797  augroup END
2798
2799  normal Y
2800
2801  augroup test
2802    autocmd!
2803  augroup END
2804  delete('Xdir', 'rf')
2805  &rtp = save_rtp
2806enddef
2807
2808" This was causing a crash because suppress_errthrow wasn't reset.
2809def Test_vim9_autoload_error()
2810  var lines =<< trim END
2811      vim9script
2812      def crash#func()
2813          try
2814              for x in List()
2815              endfor
2816          catch
2817          endtry
2818          g:ok = true
2819      enddef
2820      fu List()
2821          invalid
2822      endfu
2823      try
2824          invalid
2825      catch /wontmatch/
2826      endtry
2827  END
2828  call mkdir('Xruntime/autoload', 'p')
2829  call writefile(lines, 'Xruntime/autoload/crash.vim')
2830
2831  # run in a separate Vim to avoid the side effects of assert_fails()
2832  lines =<< trim END
2833    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
2834    call crash#func()
2835    call writefile(['ok'], 'Xdidit')
2836    qall!
2837  END
2838  writefile(lines, 'Xscript')
2839  RunVim([], [], '-S Xscript')
2840  assert_equal(['ok'], readfile('Xdidit'))
2841
2842  delete('Xdidit')
2843  delete('Xscript')
2844  delete('Xruntime', 'rf')
2845enddef
2846
2847def Test_script_var_in_autocmd()
2848  # using a script variable from an autocommand, defined in a :def function in a
2849  # legacy Vim script, cannot check the variable type.
2850  var lines =<< trim END
2851    let s:counter = 1
2852    def s:Func()
2853      au! CursorHold
2854      au CursorHold * s:counter += 1
2855    enddef
2856    call s:Func()
2857    doau CursorHold
2858    call assert_equal(2, s:counter)
2859    au! CursorHold
2860  END
2861  CheckScriptSuccess(lines)
2862enddef
2863
2864def Test_cmdline_win()
2865  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
2866  # the command line window.
2867  mkdir('rtp/syntax', 'p')
2868  var export_lines =<< trim END
2869    vim9script
2870    export var That = 'yes'
2871  END
2872  writefile(export_lines, 'rtp/syntax/Xexport.vim')
2873  var import_lines =<< trim END
2874    vim9script
2875    import That from './Xexport.vim'
2876  END
2877  writefile(import_lines, 'rtp/syntax/vim.vim')
2878  var save_rtp = &rtp
2879  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
2880  syntax on
2881  augroup CmdWin
2882    autocmd CmdwinEnter * g:got_there = 'yes'
2883  augroup END
2884  # this will open and also close the cmdline window
2885  feedkeys('q:', 'xt')
2886  assert_equal('yes', g:got_there)
2887
2888  augroup CmdWin
2889    au!
2890  augroup END
2891  &rtp = save_rtp
2892  delete('rtp', 'rf')
2893enddef
2894
2895def Test_invalid_sid()
2896  assert_fails('func <SNR>1234_func', 'E123:')
2897
2898  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
2899    assert_equal([], readfile('Xdidit'))
2900  endif
2901  delete('Xdidit')
2902enddef
2903
2904def Test_restoring_cpo()
2905  writefile(['vim9script', 'set nocp'], 'Xsourced')
2906  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
2907  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
2908    assert_equal(['done'], readfile('Xdone'))
2909  endif
2910  delete('Xsourced')
2911  delete('Xclose')
2912enddef
2913
2914
2915def Test_unset_any_variable()
2916  var lines =<< trim END
2917    var name: any
2918    assert_equal(0, name)
2919  END
2920  CheckDefAndScriptSuccess(lines)
2921enddef
2922
2923func Test_define_func_at_command_line()
2924  CheckRunVimInTerminal
2925
2926  " call indirectly to avoid compilation error for missing functions
2927  call Run_Test_define_func_at_command_line()
2928endfunc
2929
2930def Run_Test_define_func_at_command_line()
2931  # run in a separate Vim instance to avoid the script context
2932  var lines =<< trim END
2933    func CheckAndQuit()
2934      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
2935      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
2936    endfunc
2937  END
2938  writefile([''], 'Xdidcmd')
2939  writefile(lines, 'XcallFunc')
2940  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
2941  # define Afunc() on the command line
2942  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
2943  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
2944  WaitForAssert({-> assert_equal(['errors: []'], readfile('Xdidcmd'))})
2945
2946  call StopVimInTerminal(buf)
2947  delete('XcallFunc')
2948  delete('Xdidcmd')
2949enddef
2950
2951def Test_script_var_scope()
2952  var lines =<< trim END
2953      vim9script
2954      if true
2955        if true
2956          var one = 'one'
2957          echo one
2958        endif
2959        echo one
2960      endif
2961  END
2962  CheckScriptFailure(lines, 'E121:', 7)
2963
2964  lines =<< trim END
2965      vim9script
2966      if true
2967        if false
2968          var one = 'one'
2969          echo one
2970        else
2971          var one = 'one'
2972          echo one
2973        endif
2974        echo one
2975      endif
2976  END
2977  CheckScriptFailure(lines, 'E121:', 10)
2978
2979  lines =<< trim END
2980      vim9script
2981      while true
2982        var one = 'one'
2983        echo one
2984        break
2985      endwhile
2986      echo one
2987  END
2988  CheckScriptFailure(lines, 'E121:', 7)
2989
2990  lines =<< trim END
2991      vim9script
2992      for i in range(1)
2993        var one = 'one'
2994        echo one
2995      endfor
2996      echo one
2997  END
2998  CheckScriptFailure(lines, 'E121:', 6)
2999
3000  lines =<< trim END
3001      vim9script
3002      {
3003        var one = 'one'
3004        assert_equal('one', one)
3005      }
3006      assert_false(exists('one'))
3007      assert_false(exists('s:one'))
3008  END
3009  CheckScriptSuccess(lines)
3010
3011  lines =<< trim END
3012      vim9script
3013      {
3014        var one = 'one'
3015        echo one
3016      }
3017      echo one
3018  END
3019  CheckScriptFailure(lines, 'E121:', 6)
3020enddef
3021
3022def Test_catch_exception_in_callback()
3023  var lines =<< trim END
3024    vim9script
3025    def Callback(...l: any)
3026      try
3027        var x: string
3028        var y: string
3029        # this error should be caught with CHECKLEN
3030        [x, y] = ['']
3031      catch
3032        g:caught = 'yes'
3033      endtry
3034    enddef
3035    popup_menu('popup', {callback: Callback})
3036    feedkeys("\r", 'xt')
3037  END
3038  CheckScriptSuccess(lines)
3039
3040  unlet g:caught
3041enddef
3042
3043def Test_no_unknown_error_after_error()
3044  if !has('unix') || !has('job')
3045    throw 'Skipped: not unix of missing +job feature'
3046  endif
3047  var lines =<< trim END
3048      vim9script
3049      var source: list<number>
3050      def Out_cb(...l: any)
3051          eval [][0]
3052      enddef
3053      def Exit_cb(...l: any)
3054          sleep 1m
3055          source += l
3056      enddef
3057      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
3058      sleep 100m
3059  END
3060  writefile(lines, 'Xdef')
3061  assert_fails('so Xdef', ['E684:', 'E1012:'])
3062  delete('Xdef')
3063enddef
3064
3065def InvokeNormal()
3066  exe "norm! :m+1\r"
3067enddef
3068
3069def Test_invoke_normal_in_visual_mode()
3070  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
3071  new
3072  setline(1, ['aaa', 'bbb'])
3073  feedkeys("V\<F3>", 'xt')
3074  assert_equal(['bbb', 'aaa'], getline(1, 2))
3075  xunmap <F3>
3076enddef
3077
3078def Test_white_space_after_command()
3079  var lines =<< trim END
3080    exit_cb: Func})
3081  END
3082  CheckDefAndScriptFailure(lines, 'E1144:', 1)
3083enddef
3084
3085" Keep this last, it messes up highlighting.
3086def Test_substitute_cmd()
3087  new
3088  setline(1, 'something')
3089  :substitute(some(other(
3090  assert_equal('otherthing', getline(1))
3091  bwipe!
3092
3093  # also when the context is Vim9 script
3094  var lines =<< trim END
3095    vim9script
3096    new
3097    setline(1, 'something')
3098    :substitute(some(other(
3099    assert_equal('otherthing', getline(1))
3100    bwipe!
3101  END
3102  writefile(lines, 'Xvim9lines')
3103  source Xvim9lines
3104
3105  delete('Xvim9lines')
3106enddef
3107
3108" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3109