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