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
8source screendump.vim
9
10def Test_range_only()
11  new
12  setline(1, ['blah', 'Blah'])
13  :/Blah/
14  assert_equal(2, getcurpos()[1])
15  bwipe!
16
17  # without range commands use current line
18  new
19  setline(1, ['one', 'two', 'three'])
20  :2
21  print
22  assert_equal('two', Screenline(&lines))
23  :3
24  list
25  assert_equal('three$', Screenline(&lines))
26
27  # missing command does not print the line
28  var lines =<< trim END
29    vim9script
30    :1|
31    assert_equal('three$', Screenline(&lines))
32    :|
33    assert_equal('three$', Screenline(&lines))
34  END
35  CheckScriptSuccess(lines)
36
37  bwipe!
38
39  # won't generate anything
40  if false
41    :123
42  endif
43enddef
44
45let g:alist = [7]
46let g:astring = 'text'
47let g:anumber = 123
48
49def Test_delfunction()
50  # Check function is defined in script namespace
51  CheckScriptSuccess([
52      'vim9script',
53      'func CheckMe()',
54      '  return 123',
55      'endfunc',
56      'assert_equal(123, s:CheckMe())',
57      ])
58
59  # Check function in script namespace cannot be deleted
60  CheckScriptFailure([
61      'vim9script',
62      'func DeleteMe1()',
63      'endfunc',
64      'delfunction DeleteMe1',
65      ], 'E1084:')
66  CheckScriptFailure([
67      'vim9script',
68      'func DeleteMe2()',
69      'endfunc',
70      'def DoThat()',
71      '  delfunction DeleteMe2',
72      'enddef',
73      'DoThat()',
74      ], 'E1084:')
75  CheckScriptFailure([
76      'vim9script',
77      'def DeleteMe3()',
78      'enddef',
79      'delfunction DeleteMe3',
80      ], 'E1084:')
81  CheckScriptFailure([
82      'vim9script',
83      'def DeleteMe4()',
84      'enddef',
85      'def DoThat()',
86      '  delfunction DeleteMe4',
87      'enddef',
88      'DoThat()',
89      ], 'E1084:')
90
91  # Check that global :def function can be replaced and deleted
92  var lines =<< trim END
93      vim9script
94      def g:Global(): string
95        return "yes"
96      enddef
97      assert_equal("yes", g:Global())
98      def! g:Global(): string
99        return "no"
100      enddef
101      assert_equal("no", g:Global())
102      delfunc g:Global
103      assert_false(exists('*g:Global'))
104  END
105  CheckScriptSuccess(lines)
106
107  # Check that global function can be replaced by a :def function and deleted
108  lines =<< trim END
109      vim9script
110      func g:Global()
111        return "yes"
112      endfunc
113      assert_equal("yes", g:Global())
114      def! g:Global(): string
115        return "no"
116      enddef
117      assert_equal("no", g:Global())
118      delfunc g:Global
119      assert_false(exists('*g:Global'))
120  END
121  CheckScriptSuccess(lines)
122
123  # Check that global :def function can be replaced by a function and deleted
124  lines =<< trim END
125      vim9script
126      def g:Global(): string
127        return "yes"
128      enddef
129      assert_equal("yes", g:Global())
130      func! g:Global()
131        return "no"
132      endfunc
133      assert_equal("no", g:Global())
134      delfunc g:Global
135      assert_false(exists('*g:Global'))
136  END
137  CheckScriptSuccess(lines)
138enddef
139
140def Test_wrong_type()
141  CheckDefFailure(['var name: list<nothing>'], 'E1010:')
142  CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
143  CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
144  CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
145
146  CheckDefFailure(['var name: dict<number'], 'E1009:')
147  CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
148
149  CheckDefFailure(['var name: ally'], 'E1010:')
150  CheckDefFailure(['var name: bram'], 'E1010:')
151  CheckDefFailure(['var name: cathy'], 'E1010:')
152  CheckDefFailure(['var name: dom'], 'E1010:')
153  CheckDefFailure(['var name: freddy'], 'E1010:')
154  CheckDefFailure(['var name: john'], 'E1010:')
155  CheckDefFailure(['var name: larry'], 'E1010:')
156  CheckDefFailure(['var name: ned'], 'E1010:')
157  CheckDefFailure(['var name: pam'], 'E1010:')
158  CheckDefFailure(['var name: sam'], 'E1010:')
159  CheckDefFailure(['var name: vim'], 'E1010:')
160
161  CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
162  CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
163enddef
164
165def Test_script_wrong_type()
166  var lines =<< trim END
167      vim9script
168      var s:dict: dict<string>
169      s:dict['a'] = ['x']
170  END
171  CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
172enddef
173
174def Test_const()
175  CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
176  CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
177  CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
178  CheckDefFailure(['final two'], 'E1125:')
179  CheckDefFailure(['final &option'], 'E996:')
180
181  var lines =<< trim END
182    final list = [1, 2, 3]
183    list[0] = 4
184    list->assert_equal([4, 2, 3])
185    const other = [5, 6, 7]
186    other->assert_equal([5, 6, 7])
187
188    var varlist = [7, 8]
189    const constlist = [1, varlist, 3]
190    varlist[0] = 77
191    constlist[1][1] = 88
192    var cl = constlist[1]
193    cl[1] = 88
194    constlist->assert_equal([1, [77, 88], 3])
195
196    var vardict = {five: 5, six: 6}
197    const constdict = {one: 1, two: vardict, three: 3}
198    vardict['five'] = 55
199    constdict['two']['six'] = 66
200    var cd = constdict['two']
201    cd['six'] = 66
202    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
203  END
204  CheckDefAndScriptSuccess(lines)
205enddef
206
207def Test_const_bang()
208  var lines =<< trim END
209      const var = 234
210      var = 99
211  END
212  CheckDefExecFailure(lines, 'E1018:', 2)
213  CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
214
215  lines =<< trim END
216      const ll = [2, 3, 4]
217      ll[0] = 99
218  END
219  CheckDefExecFailure(lines, 'E1119:', 2)
220  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
221
222  lines =<< trim END
223      const ll = [2, 3, 4]
224      ll[3] = 99
225  END
226  CheckDefExecFailure(lines, 'E1118:', 2)
227  CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
228
229  lines =<< trim END
230      const dd = {one: 1, two: 2}
231      dd["one"] = 99
232  END
233  CheckDefExecFailure(lines, 'E1121:', 2)
234  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
235
236  lines =<< trim END
237      const dd = {one: 1, two: 2}
238      dd["three"] = 99
239  END
240  CheckDefExecFailure(lines, 'E1120:')
241  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
242enddef
243
244def Test_range_no_colon()
245  CheckDefFailure(['%s/a/b/'], 'E1050:')
246  CheckDefFailure(['+ s/a/b/'], 'E1050:')
247  CheckDefFailure(['- s/a/b/'], 'E1050:')
248  CheckDefFailure(['. s/a/b/'], 'E1050:')
249enddef
250
251
252def Test_block()
253  var outer = 1
254  {
255    var inner = 2
256    assert_equal(1, outer)
257    assert_equal(2, inner)
258  }
259  assert_equal(1, outer)
260
261  {|echo 'yes'|}
262enddef
263
264def Test_block_failure()
265  CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
266  CheckDefFailure(['}'], 'E1025:')
267  CheckDefFailure(['{', 'echo 1'], 'E1026:')
268enddef
269
270def Test_block_local_vars()
271  var lines =<< trim END
272      vim9script
273      v:testing = 1
274      if true
275        var text = ['hello']
276        def SayHello(): list<string>
277          return text
278        enddef
279        def SetText(v: string)
280          text = [v]
281        enddef
282      endif
283
284      if true
285        var text = ['again']
286        def SayAgain(): list<string>
287          return text
288        enddef
289      endif
290
291      # test that the "text" variables are not cleaned up
292      test_garbagecollect_now()
293
294      defcompile
295
296      assert_equal(['hello'], SayHello())
297      assert_equal(['again'], SayAgain())
298
299      SetText('foobar')
300      assert_equal(['foobar'], SayHello())
301
302      call writefile(['ok'], 'Xdidit')
303      qall!
304  END
305
306  # need to execute this with a separate Vim instance to avoid the current
307  # context gets garbage collected.
308  writefile(lines, 'Xscript')
309  RunVim([], [], '-S Xscript')
310  assert_equal(['ok'], readfile('Xdidit'))
311
312  delete('Xscript')
313  delete('Xdidit')
314enddef
315
316def Test_block_local_vars_with_func()
317  var lines =<< trim END
318      vim9script
319      if true
320        var foo = 'foo'
321        if true
322          var bar = 'bar'
323          def Func(): list<string>
324            return [foo, bar]
325          enddef
326        endif
327      endif
328      # function is compiled here, after blocks have finished, can still access
329      # "foo" and "bar"
330      assert_equal(['foo', 'bar'], Func())
331  END
332  CheckScriptSuccess(lines)
333enddef
334
335" legacy func for command that's defined later
336func InvokeSomeCommand()
337  SomeCommand
338endfunc
339
340def Test_autocommand_block()
341  com SomeCommand {
342      g:someVar = 'some'
343    }
344  InvokeSomeCommand()
345  assert_equal('some', g:someVar)
346
347  delcommand SomeCommand
348  unlet g:someVar
349enddef
350
351def Test_command_block()
352  au BufNew *.xml {
353      g:otherVar = 'other'
354    }
355  split other.xml
356  assert_equal('other', g:otherVar)
357
358  bwipe!
359  au! BufNew *.xml
360  unlet g:otherVar
361enddef
362
363func g:NoSuchFunc()
364  echo 'none'
365endfunc
366
367def Test_try_catch_throw()
368  var l = []
369  try # comment
370    add(l, '1')
371    throw 'wrong'
372    add(l, '2')
373  catch # comment
374    add(l, v:exception)
375  finally # comment
376    add(l, '3')
377  endtry # comment
378  assert_equal(['1', 'wrong', '3'], l)
379
380  l = []
381  try
382    try
383      add(l, '1')
384      throw 'wrong'
385      add(l, '2')
386    catch /right/
387      add(l, v:exception)
388    endtry
389  catch /wrong/
390    add(l, 'caught')
391  fina
392    add(l, 'finally')
393  endtry
394  assert_equal(['1', 'caught', 'finally'], l)
395
396  var n: number
397  try
398    n = l[3]
399  catch /E684:/
400    n = 99
401  endtry
402  assert_equal(99, n)
403
404  var done = 'no'
405  if 0
406    try | catch | endtry
407  else
408    done = 'yes'
409  endif
410  assert_equal('yes', done)
411
412  done = 'no'
413  if 1
414    done = 'yes'
415  else
416    try | catch | endtry
417    done = 'never'
418  endif
419  assert_equal('yes', done)
420
421  if 1
422  else
423    try | catch /pat/ | endtry
424    try | catch /pat/
425    endtry
426    try
427    catch /pat/ | endtry
428    try
429    catch /pat/
430    endtry
431  endif
432
433  try
434    # string slice returns a string, not a number
435    n = g:astring[3]
436  catch /E1012:/
437    n = 77
438  endtry
439  assert_equal(77, n)
440
441  try
442    n = l[g:astring]
443  catch /E1012:/
444    n = 88
445  endtry
446  assert_equal(88, n)
447
448  try
449    n = s:does_not_exist
450  catch /E121:/
451    n = 111
452  endtry
453  assert_equal(111, n)
454
455  try
456    n = g:does_not_exist
457  catch /E121:/
458    n = 121
459  endtry
460  assert_equal(121, n)
461
462  var d = {one: 1}
463  try
464    n = d[g:astring]
465  catch /E716:/
466    n = 222
467  endtry
468  assert_equal(222, n)
469
470  try
471    n = -g:astring
472  catch /E1012:/
473    n = 233
474  endtry
475  assert_equal(233, n)
476
477  try
478    n = +g:astring
479  catch /E1012:/
480    n = 244
481  endtry
482  assert_equal(244, n)
483
484  try
485    n = +g:alist
486  catch /E1012:/
487    n = 255
488  endtry
489  assert_equal(255, n)
490
491  var nd: dict<any>
492  try
493    nd = {[g:alist]: 1}
494  catch /E1105:/
495    n = 266
496  endtry
497  assert_equal(266, n)
498
499  try
500    [n] = [1, 2, 3]
501  catch /E1093:/
502    n = 277
503  endtry
504  assert_equal(277, n)
505
506  try
507    &ts = g:astring
508  catch /E1012:/
509    n = 288
510  endtry
511  assert_equal(288, n)
512
513  try
514    &backspace = 'asdf'
515  catch /E474:/
516    n = 299
517  endtry
518  assert_equal(299, n)
519
520  l = [1]
521  try
522    l[3] = 3
523  catch /E684:/
524    n = 300
525  endtry
526  assert_equal(300, n)
527
528  try
529    unlet g:does_not_exist
530  catch /E108:/
531    n = 322
532  endtry
533  assert_equal(322, n)
534
535  try
536    d = {text: 1, [g:astring]: 2}
537  catch /E721:/
538    n = 333
539  endtry
540  assert_equal(333, n)
541
542  try
543    l = DeletedFunc()
544  catch /E933:/
545    n = 344
546  endtry
547  assert_equal(344, n)
548
549  try
550    echo range(1, 2, 0)
551  catch /E726:/
552    n = 355
553  endtry
554  assert_equal(355, n)
555
556  var P = function('g:NoSuchFunc')
557  delfunc g:NoSuchFunc
558  try
559    echo P()
560  catch /E117:/
561    n = 366
562  endtry
563  assert_equal(366, n)
564
565  try
566    echo g:NoSuchFunc()
567  catch /E117:/
568    n = 377
569  endtry
570  assert_equal(377, n)
571
572  try
573    echo g:alist + 4
574  catch /E745:/
575    n = 388
576  endtry
577  assert_equal(388, n)
578
579  try
580    echo 4 + g:alist
581  catch /E745:/
582    n = 399
583  endtry
584  assert_equal(399, n)
585
586  try
587    echo g:alist.member
588  catch /E715:/
589    n = 400
590  endtry
591  assert_equal(400, n)
592
593  try
594    echo d.member
595  catch /E716:/
596    n = 411
597  endtry
598  assert_equal(411, n)
599
600  var counter = 0
601  for i in range(4)
602    try
603      eval [][0]
604    catch
605    endtry
606    counter += 1
607  endfor
608  assert_equal(4, counter)
609
610  # no requirement for spaces before |
611  try|echo 0|catch|endtry
612
613  # return in finally after empty catch
614  def ReturnInFinally(): number
615    try
616    finally
617      return 4
618    endtry
619    return 2
620  enddef
621  assert_equal(4, ReturnInFinally())
622
623  var lines =<< trim END
624      vim9script
625      try
626        acos('0.5')
627          ->setline(1)
628      catch
629        g:caught = v:exception
630      endtry
631  END
632  CheckScriptSuccess(lines)
633  assert_match('E1219: Float or Number required for argument 1', g:caught)
634  unlet g:caught
635
636  # missing catch and/or finally
637  lines =<< trim END
638      vim9script
639      try
640        echo 'something'
641      endtry
642  END
643  CheckScriptFailure(lines, 'E1032:')
644
645  # skipping try-finally-endtry when try-finally-endtry is used in another block
646  lines =<< trim END
647      if v:true
648        try
649        finally
650        endtry
651      else
652        try
653        finally
654        endtry
655      endif
656  END
657  CheckDefAndScriptSuccess(lines)
658enddef
659
660def Test_try_in_catch()
661  var lines =<< trim END
662      vim9script
663      var seq = []
664      def DoIt()
665        try
666          seq->add('throw 1')
667          eval [][0]
668          seq->add('notreached')
669        catch
670          seq->add('catch')
671          try
672            seq->add('throw 2')
673            eval [][0]
674            seq->add('notreached')
675          catch /nothing/
676            seq->add('notreached')
677          endtry
678          seq->add('done')
679        endtry
680      enddef
681      DoIt()
682      assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq)
683  END
684enddef
685
686def Test_error_in_catch()
687  var lines =<< trim END
688      try
689        eval [][0]
690      catch /E684:/
691        eval [][0]
692      endtry
693  END
694  CheckDefExecFailure(lines, 'E684:', 4)
695enddef
696
697" :while at the very start of a function that :continue jumps to
698def TryContinueFunc()
699 while g:Count < 2
700   g:sequence ..= 't'
701    try
702      echoerr 'Test'
703    catch
704      g:Count += 1
705      g:sequence ..= 'c'
706      continue
707    endtry
708    g:sequence ..= 'e'
709    g:Count += 1
710  endwhile
711enddef
712
713def Test_continue_in_try_in_while()
714  g:Count = 0
715  g:sequence = ''
716  TryContinueFunc()
717  assert_equal('tctc', g:sequence)
718  unlet g:Count
719  unlet g:sequence
720enddef
721
722def Test_nocatch_return_in_try()
723  # return in try block returns normally
724  def ReturnInTry(): string
725    try
726      return '"some message"'
727    catch
728    endtry
729    return 'not reached'
730  enddef
731  exe 'echoerr ' .. ReturnInTry()
732enddef
733
734def Test_cnext_works_in_catch()
735  var lines =<< trim END
736      vim9script
737      au BufEnter * eval 1 + 2
738      writefile(['text'], 'Xfile1')
739      writefile(['text'], 'Xfile2')
740      var items = [
741          {lnum: 1, filename: 'Xfile1', valid: true},
742          {lnum: 1, filename: 'Xfile2', valid: true}
743        ]
744      setqflist([], ' ', {items: items})
745      cwindow
746
747      def CnextOrCfirst()
748        # if cnext fails, cfirst is used
749        try
750          cnext
751        catch
752          cfirst
753        endtry
754      enddef
755
756      CnextOrCfirst()
757      CnextOrCfirst()
758      writefile([getqflist({idx: 0}).idx], 'Xresult')
759      qall
760  END
761  writefile(lines, 'XCatchCnext')
762  RunVim([], [], '--clean -S XCatchCnext')
763  assert_equal(['1'], readfile('Xresult'))
764
765  delete('Xfile1')
766  delete('Xfile2')
767  delete('XCatchCnext')
768  delete('Xresult')
769enddef
770
771def Test_throw_skipped()
772  if 0
773    throw dontgethere
774  endif
775enddef
776
777def Test_nocatch_throw_silenced()
778  var lines =<< trim END
779    vim9script
780    def Func()
781      throw 'error'
782    enddef
783    silent! Func()
784  END
785  writefile(lines, 'XthrowSilenced')
786  source XthrowSilenced
787  delete('XthrowSilenced')
788enddef
789
790def DeletedFunc(): list<any>
791  return ['delete me']
792enddef
793defcompile
794delfunc DeletedFunc
795
796def ThrowFromDef()
797  throw "getout" # comment
798enddef
799
800func CatchInFunc()
801  try
802    call ThrowFromDef()
803  catch
804    let g:thrown_func = v:exception
805  endtry
806endfunc
807
808def CatchInDef()
809  try
810    ThrowFromDef()
811  catch
812    g:thrown_def = v:exception
813  endtry
814enddef
815
816def ReturnFinally(): string
817  try
818    return 'intry'
819  finall
820    g:in_finally = 'finally'
821  endtry
822  return 'end'
823enddef
824
825def Test_try_catch_nested()
826  CatchInFunc()
827  assert_equal('getout', g:thrown_func)
828
829  CatchInDef()
830  assert_equal('getout', g:thrown_def)
831
832  assert_equal('intry', ReturnFinally())
833  assert_equal('finally', g:in_finally)
834
835  var l = []
836  try
837    l->add('1')
838    throw 'bad'
839    l->add('x')
840  catch /bad/
841    l->add('2')
842    try
843      l->add('3')
844      throw 'one'
845      l->add('x')
846    catch /one/
847      l->add('4')
848      try
849        l->add('5')
850        throw 'more'
851        l->add('x')
852      catch /more/
853        l->add('6')
854      endtry
855    endtry
856  endtry
857  assert_equal(['1', '2', '3', '4', '5', '6'], l)
858
859  l = []
860  try
861    try
862      l->add('1')
863      throw 'foo'
864      l->add('x')
865    catch
866      l->add('2')
867      throw 'bar'
868      l->add('x')
869    finally
870      l->add('3')
871    endtry
872    l->add('x')
873  catch /bar/
874    l->add('4')
875  endtry
876  assert_equal(['1', '2', '3', '4'], l)
877enddef
878
879def TryOne(): number
880  try
881    return 0
882  catch
883  endtry
884  return 0
885enddef
886
887def TryTwo(n: number): string
888  try
889    var x = {}
890  catch
891  endtry
892  return 'text'
893enddef
894
895def Test_try_catch_twice()
896  assert_equal('text', TryOne()->TryTwo())
897enddef
898
899def Test_try_catch_match()
900  var seq = 'a'
901  try
902    throw 'something'
903  catch /nothing/
904    seq ..= 'x'
905  catch /some/
906    seq ..= 'b'
907  catch /asdf/
908    seq ..= 'x'
909  catch ?a\?sdf?
910    seq ..= 'y'
911  finally
912    seq ..= 'c'
913  endtry
914  assert_equal('abc', seq)
915enddef
916
917def Test_try_catch_fails()
918  CheckDefFailure(['catch'], 'E603:')
919  CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
920  CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
921  CheckDefFailure(['finally'], 'E606:')
922  CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
923  CheckDefFailure(['endtry'], 'E602:')
924  CheckDefFailure(['while 1', 'endtry'], 'E170:')
925  CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
926  CheckDefFailure(['if 1', 'endtry'], 'E171:')
927  CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
928
929  CheckDefFailure(['throw'], 'E1143:')
930  CheckDefFailure(['throw xxx'], 'E1001:')
931enddef
932
933def Try_catch_skipped()
934  var l = []
935  try
936  finally
937  endtry
938
939  if 1
940  else
941    try
942    endtry
943  endif
944enddef
945
946" The skipped try/endtry was updating the wrong instruction.
947def Test_try_catch_skipped()
948  var instr = execute('disassemble Try_catch_skipped')
949  assert_match("NEWLIST size 0\n", instr)
950enddef
951
952
953
954def Test_throw_vimscript()
955  # only checks line continuation
956  var lines =<< trim END
957      vim9script
958      try
959        throw 'one'
960              .. 'two'
961      catch
962        assert_equal('onetwo', v:exception)
963      endtry
964  END
965  CheckScriptSuccess(lines)
966
967  lines =<< trim END
968    vim9script
969    @r = ''
970    def Func()
971      throw @r
972    enddef
973    var result = ''
974    try
975      Func()
976    catch /E1129:/
977      result = 'caught'
978    endtry
979    assert_equal('caught', result)
980  END
981  CheckScriptSuccess(lines)
982enddef
983
984def Test_error_in_nested_function()
985  # an error in a nested :function aborts executing in the calling :def function
986  var lines =<< trim END
987      vim9script
988      def Func()
989        Error()
990        g:test_var = 1
991      enddef
992      func Error() abort
993        eval [][0]
994      endfunc
995      Func()
996  END
997  g:test_var = 0
998  CheckScriptFailure(lines, 'E684:')
999  assert_equal(0, g:test_var)
1000enddef
1001
1002def Test_abort_after_error()
1003  var lines =<< trim END
1004      vim9script
1005      while true
1006        echo notfound
1007      endwhile
1008      g:gotthere = true
1009  END
1010  g:gotthere = false
1011  CheckScriptFailure(lines, 'E121:')
1012  assert_false(g:gotthere)
1013  unlet g:gotthere
1014enddef
1015
1016def Test_cexpr_vimscript()
1017  # only checks line continuation
1018  set errorformat=File\ %f\ line\ %l
1019  var lines =<< trim END
1020      vim9script
1021      cexpr 'File'
1022                .. ' someFile' ..
1023                   ' line 19'
1024      assert_equal(19, getqflist()[0].lnum)
1025  END
1026  CheckScriptSuccess(lines)
1027  set errorformat&
1028enddef
1029
1030def Test_statusline_syntax()
1031  # legacy syntax is used for 'statusline'
1032  var lines =<< trim END
1033      vim9script
1034      func g:Status()
1035        return '%{"x" is# "x"}'
1036      endfunc
1037      set laststatus=2 statusline=%!Status()
1038      redrawstatus
1039      set laststatus statusline=
1040  END
1041  CheckScriptSuccess(lines)
1042enddef
1043
1044def Test_list_vimscript()
1045  # checks line continuation and comments
1046  var lines =<< trim END
1047      vim9script
1048      var mylist = [
1049            'one',
1050            # comment
1051            'two', # empty line follows
1052
1053            'three',
1054            ]
1055      assert_equal(['one', 'two', 'three'], mylist)
1056  END
1057  CheckScriptSuccess(lines)
1058
1059  # check all lines from heredoc are kept
1060  lines =<< trim END
1061      # comment 1
1062      two
1063      # comment 3
1064
1065      five
1066      # comment 6
1067  END
1068  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
1069
1070  lines =<< trim END
1071    [{
1072      a: 0}]->string()->assert_equal("[{'a': 0}]")
1073  END
1074  CheckDefAndScriptSuccess(lines)
1075enddef
1076
1077if has('channel')
1078  let someJob = test_null_job()
1079
1080  def FuncWithError()
1081    echomsg g:someJob
1082  enddef
1083
1084  func Test_convert_emsg_to_exception()
1085    try
1086      call FuncWithError()
1087    catch
1088      call assert_match('Vim:E908:', v:exception)
1089    endtry
1090  endfunc
1091endif
1092
1093let s:export_script_lines =<< trim END
1094  vim9script
1095  var name: string = 'bob'
1096  def Concat(arg: string): string
1097    return name .. arg
1098  enddef
1099  g:result = Concat('bie')
1100  g:localname = name
1101
1102  export const CONST = 1234
1103  export var exported = 9876
1104  export var exp_name = 'John'
1105  export def Exported(): string
1106    return 'Exported'
1107  enddef
1108  export def ExportedValue(): number
1109    return exported
1110  enddef
1111  export def ExportedInc()
1112    exported += 5
1113  enddef
1114  export final theList = [1]
1115END
1116
1117def Undo_export_script_lines()
1118  unlet g:result
1119  unlet g:localname
1120enddef
1121
1122def Test_vim9_import_export()
1123  var import_script_lines =<< trim END
1124    vim9script
1125    import {exported, Exported, ExportedValue} from './Xexport.vim'
1126    g:exported1 = exported
1127    exported += 3
1128    g:exported2 = exported
1129    g:exported3 = ExportedValue()
1130
1131    import ExportedInc from './Xexport.vim'
1132    ExportedInc()
1133    g:exported_i1 = exported
1134    g:exported_i2 = ExportedValue()
1135
1136    exported = 11
1137    g:exported_s1 = exported
1138    g:exported_s2 = ExportedValue()
1139
1140    g:imported_func = Exported()
1141
1142    def GetExported(): string
1143      var local_dict = {ref: Exported}
1144      return local_dict.ref()
1145    enddef
1146    g:funcref_result = GetExported()
1147
1148    var dir = './'
1149    var ext = ".vim"
1150    import {exp_name} from dir .. 'Xexport' .. ext
1151    g:imported_name = exp_name
1152    exp_name ..= ' Doe'
1153    g:imported_name_appended = exp_name
1154    g:exported_later = exported
1155
1156    import theList from './Xexport.vim'
1157    theList->add(2)
1158    assert_equal([1, 2], theList)
1159  END
1160
1161  writefile(import_script_lines, 'Ximport.vim')
1162  writefile(s:export_script_lines, 'Xexport.vim')
1163
1164  source Ximport.vim
1165
1166  assert_equal('bobbie', g:result)
1167  assert_equal('bob', g:localname)
1168  assert_equal(9876, g:exported1)
1169  assert_equal(9879, g:exported2)
1170  assert_equal(9879, g:exported3)
1171
1172  assert_equal(9884, g:exported_i1)
1173  assert_equal(9884, g:exported_i2)
1174
1175  assert_equal(11, g:exported_s1)
1176  assert_equal(11, g:exported_s2)
1177  assert_equal(11, g:exported_later)
1178
1179  assert_equal('Exported', g:imported_func)
1180  assert_equal('Exported', g:funcref_result)
1181  assert_equal('John', g:imported_name)
1182  assert_equal('John Doe', g:imported_name_appended)
1183  assert_false(exists('g:name'))
1184
1185  Undo_export_script_lines()
1186  unlet g:exported1
1187  unlet g:exported2
1188  unlet g:exported3
1189  unlet g:exported_i1
1190  unlet g:exported_i2
1191  unlet g:exported_later
1192  unlet g:imported_func
1193  unlet g:imported_name g:imported_name_appended
1194  delete('Ximport.vim')
1195
1196  # similar, with line breaks
1197  var import_line_break_script_lines =<< trim END
1198    vim9script
1199    import {
1200        exported,
1201        Exported,
1202        }
1203        from
1204        './Xexport.vim'
1205    g:exported = exported
1206    exported += 7
1207    g:exported_added = exported
1208    g:imported_func = Exported()
1209  END
1210  writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
1211  source Ximport_lbr.vim
1212
1213  assert_equal(11, g:exported)
1214  assert_equal(18, g:exported_added)
1215  assert_equal('Exported', g:imported_func)
1216
1217  # exported script not sourced again
1218  assert_false(exists('g:result'))
1219  unlet g:exported
1220  unlet g:exported_added
1221  unlet g:imported_func
1222  delete('Ximport_lbr.vim')
1223
1224  var import_star_as_lines =<< trim END
1225    vim9script
1226    import * as Export from './Xexport.vim'
1227    def UseExport()
1228      g:exported_def = Export.exported
1229    enddef
1230    g:exported_script = Export.exported
1231    assert_equal(1, exists('Export.exported'))
1232    assert_equal(0, exists('Export.notexported'))
1233    UseExport()
1234  END
1235  writefile(import_star_as_lines, 'Ximport.vim')
1236  source Ximport.vim
1237
1238  assert_equal(18, g:exported_def)
1239  assert_equal(18, g:exported_script)
1240  unlet g:exported_def
1241  unlet g:exported_script
1242
1243  var import_star_as_lines_no_dot =<< trim END
1244    vim9script
1245    import * as Export from './Xexport.vim'
1246    def Func()
1247      var dummy = 1
1248      var imported = Export + dummy
1249    enddef
1250    defcompile
1251  END
1252  writefile(import_star_as_lines_no_dot, 'Ximport.vim')
1253  assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func')
1254
1255  var import_star_as_lines_dot_space =<< trim END
1256    vim9script
1257    import * as Export from './Xexport.vim'
1258    def Func()
1259      var imported = Export . exported
1260    enddef
1261    defcompile
1262  END
1263  writefile(import_star_as_lines_dot_space, 'Ximport.vim')
1264  assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
1265
1266  var import_func_duplicated =<< trim END
1267    vim9script
1268    import ExportedInc from './Xexport.vim'
1269    import ExportedInc from './Xexport.vim'
1270
1271    ExportedInc()
1272  END
1273  writefile(import_func_duplicated, 'Ximport.vim')
1274  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
1275
1276  var import_star_as_duplicated =<< trim END
1277    vim9script
1278    import * as Export from './Xexport.vim'
1279    var some = 'other'
1280    import * as Export from './Xexport.vim'
1281    defcompile
1282  END
1283  writefile(import_star_as_duplicated, 'Ximport.vim')
1284  assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
1285
1286  var import_star_as_lines_script_no_dot =<< trim END
1287    vim9script
1288    import * as Export from './Xexport.vim'
1289    g:imported_script = Export exported
1290  END
1291  writefile(import_star_as_lines_script_no_dot, 'Ximport.vim')
1292  assert_fails('source Ximport.vim', 'E1029:')
1293
1294  var import_star_as_lines_script_space_after_dot =<< trim END
1295    vim9script
1296    import * as Export from './Xexport.vim'
1297    g:imported_script = Export. exported
1298  END
1299  writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim')
1300  assert_fails('source Ximport.vim', 'E1074:')
1301
1302  var import_star_as_lines_missing_name =<< trim END
1303    vim9script
1304    import * as Export from './Xexport.vim'
1305    def Func()
1306      var imported = Export.
1307    enddef
1308    defcompile
1309  END
1310  writefile(import_star_as_lines_missing_name, 'Ximport.vim')
1311  assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func')
1312
1313  var import_star_as_lbr_lines =<< trim END
1314    vim9script
1315    import *
1316        as Export
1317        from
1318        './Xexport.vim'
1319    def UseExport()
1320      g:exported = Export.exported
1321    enddef
1322    UseExport()
1323  END
1324  writefile(import_star_as_lbr_lines, 'Ximport.vim')
1325  source Ximport.vim
1326  assert_equal(18, g:exported)
1327  unlet g:exported
1328
1329  var import_star_lines =<< trim END
1330    vim9script
1331    import * from './Xexport.vim'
1332  END
1333  writefile(import_star_lines, 'Ximport.vim')
1334  assert_fails('source Ximport.vim', 'E1045:', '', 2, 'Ximport.vim')
1335
1336  # try to import something that exists but is not exported
1337  var import_not_exported_lines =<< trim END
1338    vim9script
1339    import name from './Xexport.vim'
1340  END
1341  writefile(import_not_exported_lines, 'Ximport.vim')
1342  assert_fails('source Ximport.vim', 'E1049:', '', 2, 'Ximport.vim')
1343
1344  # try to import something that is already defined
1345  var import_already_defined =<< trim END
1346    vim9script
1347    var exported = 'something'
1348    import exported from './Xexport.vim'
1349  END
1350  writefile(import_already_defined, 'Ximport.vim')
1351  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1352
1353  # try to import something that is already defined
1354  import_already_defined =<< trim END
1355    vim9script
1356    var exported = 'something'
1357    import * as exported from './Xexport.vim'
1358  END
1359  writefile(import_already_defined, 'Ximport.vim')
1360  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1361
1362  # try to import something that is already defined
1363  import_already_defined =<< trim END
1364    vim9script
1365    var exported = 'something'
1366    import {exported} from './Xexport.vim'
1367  END
1368  writefile(import_already_defined, 'Ximport.vim')
1369  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1370
1371  # try changing an imported const
1372  var import_assign_to_const =<< trim END
1373    vim9script
1374    import CONST from './Xexport.vim'
1375    def Assign()
1376      CONST = 987
1377    enddef
1378    defcompile
1379  END
1380  writefile(import_assign_to_const, 'Ximport.vim')
1381  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
1382
1383  # try changing an imported final
1384  var import_assign_to_final =<< trim END
1385    vim9script
1386    import theList from './Xexport.vim'
1387    def Assign()
1388      theList = [2]
1389    enddef
1390    defcompile
1391  END
1392  writefile(import_assign_to_final, 'Ximport.vim')
1393  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
1394
1395  # import a very long name, requires making a copy
1396  var import_long_name_lines =<< trim END
1397    vim9script
1398    import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim'
1399  END
1400  writefile(import_long_name_lines, 'Ximport.vim')
1401  assert_fails('source Ximport.vim', 'E1048:', '', 2, 'Ximport.vim')
1402
1403  var import_no_from_lines =<< trim END
1404    vim9script
1405    import name './Xexport.vim'
1406  END
1407  writefile(import_no_from_lines, 'Ximport.vim')
1408  assert_fails('source Ximport.vim', 'E1070:', '', 2, 'Ximport.vim')
1409
1410  var import_invalid_string_lines =<< trim END
1411    vim9script
1412    import name from Xexport.vim
1413  END
1414  writefile(import_invalid_string_lines, 'Ximport.vim')
1415  assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim')
1416
1417  var import_wrong_name_lines =<< trim END
1418    vim9script
1419    import name from './XnoExport.vim'
1420  END
1421  writefile(import_wrong_name_lines, 'Ximport.vim')
1422  assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
1423
1424  var import_missing_comma_lines =<< trim END
1425    vim9script
1426    import {exported name} from './Xexport.vim'
1427  END
1428  writefile(import_missing_comma_lines, 'Ximport3.vim')
1429  assert_fails('source Ximport3.vim', 'E1046:', '', 2, 'Ximport3.vim')
1430
1431  var import_redefining_lines =<< trim END
1432    vim9script
1433    import exported from './Xexport.vim'
1434    var exported = 5
1435  END
1436  writefile(import_redefining_lines, 'Ximport.vim')
1437  assert_fails('source Ximport.vim', 'E1213: Redefining imported item "exported"', '', 3)
1438
1439  var import_assign_wrong_type_lines =<< trim END
1440    vim9script
1441    import exported from './Xexport.vim'
1442    exported = 'xxx'
1443  END
1444  writefile(import_assign_wrong_type_lines, 'Ximport.vim')
1445  assert_fails('source Ximport.vim', 'E1012: Type mismatch; expected number but got string', '', 3)
1446
1447  var import_assign_const_lines =<< trim END
1448    vim9script
1449    import CONST from './Xexport.vim'
1450    CONST = 4321
1451  END
1452  writefile(import_assign_const_lines, 'Ximport.vim')
1453  assert_fails('source Ximport.vim', 'E741: Value is locked: CONST', '', 3)
1454
1455  delete('Ximport.vim')
1456  delete('Ximport3.vim')
1457  delete('Xexport.vim')
1458
1459  # Check that in a Vim9 script 'cpo' is set to the Vim default.
1460  # Flags added or removed are also applied to the restored value.
1461  set cpo=abcd
1462  var lines =<< trim END
1463    vim9script
1464    g:cpo_in_vim9script = &cpo
1465    set cpo+=f
1466    set cpo-=c
1467    g:cpo_after_vim9script = &cpo
1468  END
1469  writefile(lines, 'Xvim9_script')
1470  source Xvim9_script
1471  assert_equal('fabd', &cpo)
1472  set cpo&vim
1473  assert_equal(&cpo, g:cpo_in_vim9script)
1474  var newcpo = substitute(&cpo, 'c', '', '') .. 'f'
1475  assert_equal(newcpo, g:cpo_after_vim9script)
1476
1477  delete('Xvim9_script')
1478enddef
1479
1480def Test_import_star_fails()
1481  writefile([], 'Xfoo.vim')
1482  var lines =<< trim END
1483      import * as foo from './Xfoo.vim'
1484      foo = 'bar'
1485  END
1486  CheckDefAndScriptFailure2(lines, 'E1094:', 'E1236: Cannot use foo itself')
1487  lines =<< trim END
1488      vim9script
1489      import * as foo from './Xfoo.vim'
1490      var that = foo
1491  END
1492  CheckScriptFailure(lines, 'E1029: Expected ''.''')
1493
1494  lines =<< trim END
1495      vim9script
1496      import * as 9foo from './Xfoo.vim'
1497  END
1498  CheckScriptFailure(lines, 'E1047:')
1499  lines =<< trim END
1500      vim9script
1501      import * as the#foo from './Xfoo.vim'
1502  END
1503  CheckScriptFailure(lines, 'E1047:')
1504  lines =<< trim END
1505      vim9script
1506      import * as g:foo from './Xfoo.vim'
1507  END
1508  CheckScriptFailure(lines, 'E1047:')
1509
1510  delete('Xfoo.vim')
1511enddef
1512
1513def Test_import_as()
1514  var export_lines =<< trim END
1515    vim9script
1516    export var one = 1
1517    export var yes = 'yes'
1518    export var slist: list<string>
1519  END
1520  writefile(export_lines, 'XexportAs')
1521
1522  var import_lines =<< trim END
1523    vim9script
1524    var one = 'notused'
1525    var yes = 777
1526    import one as thatOne from './XexportAs'
1527    assert_equal(1, thatOne)
1528    import yes as yesYes from './XexportAs'
1529    assert_equal('yes', yesYes)
1530  END
1531  CheckScriptSuccess(import_lines)
1532
1533  import_lines =<< trim END
1534    vim9script
1535    import {one as thatOne, yes as yesYes} from './XexportAs'
1536    assert_equal(1, thatOne)
1537    assert_equal('yes', yesYes)
1538    assert_fails('echo one', 'E121:')
1539    assert_fails('echo yes', 'E121:')
1540  END
1541  CheckScriptSuccess(import_lines)
1542
1543  import_lines =<< trim END
1544    vim9script
1545    import {slist as impSlist} from './XexportAs'
1546    impSlist->add(123)
1547  END
1548  CheckScriptFailure(import_lines, 'E1012: Type mismatch; expected string but got number')
1549
1550  delete('XexportAs')
1551enddef
1552
1553func g:Trigger()
1554  source Ximport.vim
1555  return "echo 'yes'\<CR>"
1556endfunc
1557
1558def Test_import_export_expr_map()
1559  # check that :import and :export work when buffer is locked
1560  var export_lines =<< trim END
1561    vim9script
1562    export def That(): string
1563      return 'yes'
1564    enddef
1565  END
1566  writefile(export_lines, 'Xexport_that.vim')
1567
1568  var import_lines =<< trim END
1569    vim9script
1570    import That from './Xexport_that.vim'
1571    assert_equal('yes', That())
1572  END
1573  writefile(import_lines, 'Ximport.vim')
1574
1575  nnoremap <expr> trigger g:Trigger()
1576  feedkeys('trigger', "xt")
1577
1578  delete('Xexport_that.vim')
1579  delete('Ximport.vim')
1580  nunmap trigger
1581enddef
1582
1583def Test_import_in_filetype()
1584  # check that :import works when the buffer is locked
1585  mkdir('ftplugin', 'p')
1586  var export_lines =<< trim END
1587    vim9script
1588    export var That = 'yes'
1589  END
1590  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1591
1592  var import_lines =<< trim END
1593    vim9script
1594    import That from './Xexport_ft.vim'
1595    assert_equal('yes', That)
1596    g:did_load_mytpe = 1
1597  END
1598  writefile(import_lines, 'ftplugin/qf.vim')
1599
1600  var save_rtp = &rtp
1601  &rtp = getcwd() .. ',' .. &rtp
1602
1603  filetype plugin on
1604  copen
1605  assert_equal(1, g:did_load_mytpe)
1606
1607  quit!
1608  delete('Xexport_ft.vim')
1609  delete('ftplugin', 'rf')
1610  &rtp = save_rtp
1611enddef
1612
1613def Test_use_import_in_mapping()
1614  var lines =<< trim END
1615      vim9script
1616      export def Funcx()
1617        g:result = 42
1618      enddef
1619  END
1620  writefile(lines, 'XsomeExport.vim')
1621  lines =<< trim END
1622      vim9script
1623      import Funcx from './XsomeExport.vim'
1624      nnoremap <F3> :call <sid>Funcx()<cr>
1625  END
1626  writefile(lines, 'Xmapscript.vim')
1627
1628  source Xmapscript.vim
1629  feedkeys("\<F3>", "xt")
1630  assert_equal(42, g:result)
1631
1632  unlet g:result
1633  delete('XsomeExport.vim')
1634  delete('Xmapscript.vim')
1635  nunmap <F3>
1636enddef
1637
1638def Test_vim9script_mix()
1639  var lines =<< trim END
1640    if has(g:feature)
1641      " legacy script
1642      let g:legacy = 1
1643      finish
1644    endif
1645    vim9script
1646    g:legacy = 0
1647  END
1648  g:feature = 'eval'
1649  g:legacy = -1
1650  CheckScriptSuccess(lines)
1651  assert_equal(1, g:legacy)
1652
1653  g:feature = 'noteval'
1654  g:legacy = -1
1655  CheckScriptSuccess(lines)
1656  assert_equal(0, g:legacy)
1657enddef
1658
1659def Test_vim9script_fails()
1660  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1661  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1662  CheckScriptFailure(['export var some = 123'], 'E1042:')
1663  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1664  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1665  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1666
1667  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1668  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1669
1670  assert_fails('vim9script', 'E1038:')
1671  assert_fails('export something', 'E1043:')
1672enddef
1673
1674func Test_import_fails_without_script()
1675  CheckRunVimInTerminal
1676
1677  " call indirectly to avoid compilation error for missing functions
1678  call Run_Test_import_fails_on_command_line()
1679endfunc
1680
1681def Run_Test_import_fails_on_command_line()
1682  var export =<< trim END
1683    vim9script
1684    export def Foo(): number
1685        return 0
1686    enddef
1687  END
1688  writefile(export, 'XexportCmd.vim')
1689
1690  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1691                rows: 6, wait_for_ruler: 0})
1692  WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
1693
1694  delete('XexportCmd.vim')
1695  StopVimInTerminal(buf)
1696enddef
1697
1698def Test_vim9script_reload_noclear()
1699  var lines =<< trim END
1700    vim9script
1701    export var exported = 'thexport'
1702
1703    export def TheFunc(x = 0)
1704    enddef
1705  END
1706  writefile(lines, 'XExportReload')
1707  lines =<< trim END
1708    vim9script noclear
1709    g:loadCount += 1
1710    var s:reloaded = 'init'
1711    import exported from './XExportReload'
1712
1713    def Again(): string
1714      return 'again'
1715    enddef
1716
1717    import TheFunc from './XExportReload'
1718    TheFunc()
1719
1720    if exists('s:loaded') | finish | endif
1721    var s:loaded = true
1722
1723    var s:notReloaded = 'yes'
1724    s:reloaded = 'first'
1725    def g:Values(): list<string>
1726      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
1727    enddef
1728
1729    def Once(): string
1730      return 'once'
1731    enddef
1732  END
1733  writefile(lines, 'XReloaded')
1734  g:loadCount = 0
1735  source XReloaded
1736  assert_equal(1, g:loadCount)
1737  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
1738  source XReloaded
1739  assert_equal(2, g:loadCount)
1740  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1741  source XReloaded
1742  assert_equal(3, g:loadCount)
1743  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1744
1745  delete('XReloaded')
1746  delete('XExportReload')
1747  delfunc g:Values
1748  unlet g:loadCount
1749
1750  lines =<< trim END
1751      vim9script
1752      def Inner()
1753      enddef
1754  END
1755  lines->writefile('XreloadScript.vim')
1756  source XreloadScript.vim
1757
1758  lines =<< trim END
1759      vim9script
1760      def Outer()
1761        def Inner()
1762        enddef
1763      enddef
1764      defcompile
1765  END
1766  lines->writefile('XreloadScript.vim')
1767  source XreloadScript.vim
1768
1769  delete('XreloadScript.vim')
1770enddef
1771
1772def Test_vim9script_reload_import()
1773  var lines =<< trim END
1774    vim9script
1775    const var = ''
1776    var valone = 1234
1777    def MyFunc(arg: string)
1778       valone = 5678
1779    enddef
1780  END
1781  var morelines =<< trim END
1782    var valtwo = 222
1783    export def GetValtwo(): number
1784      return valtwo
1785    enddef
1786  END
1787  writefile(lines + morelines, 'Xreload.vim')
1788  source Xreload.vim
1789  source Xreload.vim
1790  source Xreload.vim
1791
1792  # cannot declare a var twice
1793  lines =<< trim END
1794    vim9script
1795    var valone = 1234
1796    var valone = 5678
1797  END
1798  writefile(lines, 'Xreload.vim')
1799  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1800
1801  delete('Xreload.vim')
1802  delete('Ximport.vim')
1803enddef
1804
1805" if a script is reloaded with a script-local variable that changed its type, a
1806" compiled function using that variable must fail.
1807def Test_script_reload_change_type()
1808  var lines =<< trim END
1809    vim9script noclear
1810    var str = 'string'
1811    def g:GetStr(): string
1812      return str .. 'xxx'
1813    enddef
1814  END
1815  writefile(lines, 'Xreload.vim')
1816  source Xreload.vim
1817  echo g:GetStr()
1818
1819  lines =<< trim END
1820    vim9script noclear
1821    var str = 1234
1822  END
1823  writefile(lines, 'Xreload.vim')
1824  source Xreload.vim
1825  assert_fails('echo g:GetStr()', 'E1150:')
1826
1827  delfunc g:GetStr
1828  delete('Xreload.vim')
1829enddef
1830
1831" Define CallFunc so that the test can be compiled
1832command CallFunc echo 'nop'
1833
1834def Test_script_reload_from_function()
1835  var lines =<< trim END
1836      vim9script
1837
1838      if exists('g:loaded')
1839        finish
1840      endif
1841      g:loaded = 1
1842      delcommand CallFunc
1843      command CallFunc Func()
1844      def Func()
1845        so XreloadFunc.vim
1846        g:didTheFunc = 1
1847      enddef
1848  END
1849  writefile(lines, 'XreloadFunc.vim')
1850  source XreloadFunc.vim
1851  CallFunc
1852  assert_equal(1, g:didTheFunc)
1853
1854  delete('XreloadFunc.vim')
1855  delcommand CallFunc
1856  unlet g:loaded
1857  unlet g:didTheFunc
1858enddef
1859
1860def Test_script_var_shadows_function()
1861  var lines =<< trim END
1862      vim9script
1863      def Func(): number
1864        return 123
1865      enddef
1866      var Func = 1
1867  END
1868  CheckScriptFailure(lines, 'E1041:', 5)
1869enddef
1870
1871def Test_script_var_shadows_command()
1872  var lines =<< trim END
1873      var undo = 1
1874      undo = 2
1875      assert_equal(2, undo)
1876  END
1877  CheckDefAndScriptSuccess(lines)
1878
1879  lines =<< trim END
1880      var undo = 1
1881      undo
1882  END
1883  CheckDefAndScriptFailure(lines, 'E1207:', 2)
1884enddef
1885
1886def s:RetSome(): string
1887  return 'some'
1888enddef
1889
1890" Not exported function that is referenced needs to be accessed by the
1891" script-local name.
1892def Test_vim9script_funcref()
1893  var sortlines =<< trim END
1894      vim9script
1895      def Compare(i1: number, i2: number): number
1896        return i2 - i1
1897      enddef
1898
1899      export def FastSort(): list<number>
1900        return range(5)->sort(Compare)
1901      enddef
1902
1903      export def GetString(arg: string): string
1904        return arg
1905      enddef
1906  END
1907  writefile(sortlines, 'Xsort.vim')
1908
1909  var lines =<< trim END
1910    vim9script
1911    import FastSort from './Xsort.vim'
1912    def Test()
1913      g:result = FastSort()
1914    enddef
1915    Test()
1916
1917    # using a function imported with "as"
1918    import * as anAlias from './Xsort.vim'
1919    assert_equal('yes', anAlias.GetString('yes'))
1920
1921    # using the function from a compiled function
1922    def TestMore(): string
1923      var s = s:anAlias.GetString('foo')
1924      return s .. anAlias.GetString('bar')
1925    enddef
1926    assert_equal('foobar', TestMore())
1927
1928    # error when using a function that isn't exported
1929    assert_fails('anAlias.Compare(1, 2)', 'E1049:')
1930  END
1931  writefile(lines, 'Xscript.vim')
1932
1933  source Xscript.vim
1934  assert_equal([4, 3, 2, 1, 0], g:result)
1935
1936  unlet g:result
1937  delete('Xsort.vim')
1938  delete('Xscript.vim')
1939
1940  var Funcref = function('s:RetSome')
1941  assert_equal('some', Funcref())
1942enddef
1943
1944" Check that when searching for "FilterFunc" it finds the import in the
1945" script where FastFilter() is called from, both as a string and as a direct
1946" function reference.
1947def Test_vim9script_funcref_other_script()
1948  var filterLines =<< trim END
1949    vim9script
1950    export def FilterFunc(idx: number, val: number): bool
1951      return idx % 2 == 1
1952    enddef
1953    export def FastFilter(): list<number>
1954      return range(10)->filter('FilterFunc')
1955    enddef
1956    export def FastFilterDirect(): list<number>
1957      return range(10)->filter(FilterFunc)
1958    enddef
1959  END
1960  writefile(filterLines, 'Xfilter.vim')
1961
1962  var lines =<< trim END
1963    vim9script
1964    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1965    def Test()
1966      var x: list<number> = FastFilter()
1967    enddef
1968    Test()
1969    def TestDirect()
1970      var x: list<number> = FastFilterDirect()
1971    enddef
1972    TestDirect()
1973  END
1974  CheckScriptSuccess(lines)
1975  delete('Xfilter.vim')
1976enddef
1977
1978def Test_vim9script_reload_delfunc()
1979  var first_lines =<< trim END
1980    vim9script
1981    def FuncYes(): string
1982      return 'yes'
1983    enddef
1984  END
1985  var withno_lines =<< trim END
1986    def FuncNo(): string
1987      return 'no'
1988    enddef
1989    def g:DoCheck(no_exists: bool)
1990      assert_equal('yes', FuncYes())
1991      assert_equal('no', FuncNo())
1992    enddef
1993  END
1994  var nono_lines =<< trim END
1995    def g:DoCheck(no_exists: bool)
1996      assert_equal('yes', FuncYes())
1997      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
1998    enddef
1999  END
2000
2001  # FuncNo() is defined
2002  writefile(first_lines + withno_lines, 'Xreloaded.vim')
2003  source Xreloaded.vim
2004  g:DoCheck(true)
2005
2006  # FuncNo() is not redefined
2007  writefile(first_lines + nono_lines, 'Xreloaded.vim')
2008  source Xreloaded.vim
2009  g:DoCheck(false)
2010
2011  # FuncNo() is back
2012  writefile(first_lines + withno_lines, 'Xreloaded.vim')
2013  source Xreloaded.vim
2014  g:DoCheck(false)
2015
2016  delete('Xreloaded.vim')
2017enddef
2018
2019def Test_vim9script_reload_delvar()
2020  # write the script with a script-local variable
2021  var lines =<< trim END
2022    vim9script
2023    var name = 'string'
2024  END
2025  writefile(lines, 'XreloadVar.vim')
2026  source XreloadVar.vim
2027
2028  # now write the script using the same variable locally - works
2029  lines =<< trim END
2030    vim9script
2031    def Func()
2032      var name = 'string'
2033    enddef
2034  END
2035  writefile(lines, 'XreloadVar.vim')
2036  source XreloadVar.vim
2037
2038  delete('XreloadVar.vim')
2039enddef
2040
2041def Test_import_absolute()
2042  var import_lines = [
2043        'vim9script',
2044        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
2045        'def UseExported()',
2046        '  g:imported_abs = exported',
2047        '  exported = 8888',
2048        '  g:imported_after = exported',
2049        'enddef',
2050        'UseExported()',
2051        'g:import_disassembled = execute("disass UseExported")',
2052        ]
2053  writefile(import_lines, 'Ximport_abs.vim')
2054  writefile(s:export_script_lines, 'Xexport_abs.vim')
2055
2056  source Ximport_abs.vim
2057
2058  assert_equal(9876, g:imported_abs)
2059  assert_equal(8888, g:imported_after)
2060  assert_match('<SNR>\d\+_UseExported\_s*' ..
2061          'g:imported_abs = exported\_s*' ..
2062          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2063          '1 STOREG g:imported_abs\_s*' ..
2064          'exported = 8888\_s*' ..
2065          '2 PUSHNR 8888\_s*' ..
2066          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
2067          'g:imported_after = exported\_s*' ..
2068          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2069          '5 STOREG g:imported_after',
2070        g:import_disassembled)
2071
2072  Undo_export_script_lines()
2073  unlet g:imported_abs
2074  unlet g:import_disassembled
2075
2076  delete('Ximport_abs.vim')
2077  delete('Xexport_abs.vim')
2078enddef
2079
2080def Test_import_rtp()
2081  var import_lines = [
2082        'vim9script',
2083        'import exported from "Xexport_rtp.vim"',
2084        'g:imported_rtp = exported',
2085        ]
2086  writefile(import_lines, 'Ximport_rtp.vim')
2087  mkdir('import', 'p')
2088  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
2089
2090  var save_rtp = &rtp
2091  &rtp = getcwd()
2092  source Ximport_rtp.vim
2093  &rtp = save_rtp
2094
2095  assert_equal(9876, g:imported_rtp)
2096
2097  Undo_export_script_lines()
2098  unlet g:imported_rtp
2099  delete('Ximport_rtp.vim')
2100  delete('import', 'rf')
2101enddef
2102
2103def Test_import_compile_error()
2104  var export_lines = [
2105        'vim9script',
2106        'export def ExpFunc(): string',
2107        '  return notDefined',
2108        'enddef',
2109        ]
2110  writefile(export_lines, 'Xexported.vim')
2111
2112  var import_lines = [
2113        'vim9script',
2114        'import ExpFunc from "./Xexported.vim"',
2115        'def ImpFunc()',
2116        '  echo ExpFunc()',
2117        'enddef',
2118        'defcompile',
2119        ]
2120  writefile(import_lines, 'Ximport.vim')
2121
2122  try
2123    source Ximport.vim
2124  catch /E1001/
2125    # Error should be fore the Xexported.vim file.
2126    assert_match('E1001: Variable not found: notDefined', v:exception)
2127    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
2128  endtry
2129
2130  delete('Xexported.vim')
2131  delete('Ximport.vim')
2132enddef
2133
2134def Test_func_redefine_error()
2135  var lines = [
2136        'vim9script',
2137        'def Func()',
2138        '  eval [][0]',
2139        'enddef',
2140        'Func()',
2141        ]
2142  writefile(lines, 'Xtestscript.vim')
2143
2144  for count in range(3)
2145    try
2146      source Xtestscript.vim
2147    catch /E684/
2148      # function name should contain <SNR> every time
2149      assert_match('E684: list index out of range', v:exception)
2150      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
2151    endtry
2152  endfor
2153
2154  delete('Xtestscript.vim')
2155enddef
2156
2157def Test_func_overrules_import_fails()
2158  var export_lines =<< trim END
2159      vim9script
2160      export def Func()
2161        echo 'imported'
2162      enddef
2163  END
2164  writefile(export_lines, 'XexportedFunc.vim')
2165
2166  var lines =<< trim END
2167    vim9script
2168    import Func from './XexportedFunc.vim'
2169    def Func()
2170      echo 'local to function'
2171    enddef
2172  END
2173  CheckScriptFailure(lines, 'E1073:')
2174
2175  lines =<< trim END
2176    vim9script
2177    import Func from './XexportedFunc.vim'
2178    def Outer()
2179      def Func()
2180        echo 'local to function'
2181      enddef
2182    enddef
2183    defcompile
2184  END
2185  CheckScriptFailure(lines, 'E1073:')
2186
2187  delete('XexportedFunc.vim')
2188enddef
2189
2190def Test_func_redefine_fails()
2191  var lines =<< trim END
2192    vim9script
2193    def Func()
2194      echo 'one'
2195    enddef
2196    def Func()
2197      echo 'two'
2198    enddef
2199  END
2200  CheckScriptFailure(lines, 'E1073:')
2201
2202  lines =<< trim END
2203    vim9script
2204    def Foo(): string
2205      return 'foo'
2206      enddef
2207    def Func()
2208      var  Foo = {-> 'lambda'}
2209    enddef
2210    defcompile
2211  END
2212  CheckScriptFailure(lines, 'E1073:')
2213enddef
2214
2215def Test_fixed_size_list()
2216  # will be allocated as one piece of memory, check that changes work
2217  var l = [1, 2, 3, 4]
2218  l->remove(0)
2219  l->add(5)
2220  l->insert(99, 1)
2221  assert_equal([2, 99, 3, 4, 5], l)
2222enddef
2223
2224def Test_no_insert_xit()
2225  CheckDefExecFailure(['a = 1'], 'E1100:')
2226  CheckDefExecFailure(['c = 1'], 'E1100:')
2227  CheckDefExecFailure(['i = 1'], 'E1100:')
2228  CheckDefExecFailure(['t = 1'], 'E1100:')
2229  CheckDefExecFailure(['x = 1'], 'E1100:')
2230
2231  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
2232  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
2233  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
2234  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
2235  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
2236  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
2237  CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
2238  CheckScriptFailure(['vim9script', 'o'], 'E1100:')
2239  CheckScriptFailure(['vim9script', 't'], 'E1100:')
2240  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
2241  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
2242enddef
2243
2244def IfElse(what: number): string
2245  var res = ''
2246  if what == 1
2247    res = "one"
2248  elseif what == 2
2249    res = "two"
2250  else
2251    res = "three"
2252  endif
2253  return res
2254enddef
2255
2256def Test_if_elseif_else()
2257  assert_equal('one', IfElse(1))
2258  assert_equal('two', IfElse(2))
2259  assert_equal('three', IfElse(3))
2260enddef
2261
2262def Test_if_elseif_else_fails()
2263  CheckDefFailure(['elseif true'], 'E582:')
2264  CheckDefFailure(['else'], 'E581:')
2265  CheckDefFailure(['endif'], 'E580:')
2266  CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
2267  CheckDefFailure(['if true', 'echo 1'], 'E171:')
2268
2269  var lines =<< trim END
2270      var s = ''
2271      if s = ''
2272      endif
2273  END
2274  CheckDefFailure(lines, 'E488:')
2275
2276  lines =<< trim END
2277      var s = ''
2278      if s == ''
2279      elseif s = ''
2280      endif
2281  END
2282  CheckDefFailure(lines, 'E488:')
2283enddef
2284
2285let g:bool_true = v:true
2286let g:bool_false = v:false
2287
2288def Test_if_const_expr()
2289  var res = false
2290  if true ? true : false
2291    res = true
2292  endif
2293  assert_equal(true, res)
2294
2295  g:glob = 2
2296  if false
2297    execute('g:glob = 3')
2298  endif
2299  assert_equal(2, g:glob)
2300  if true
2301    execute('g:glob = 3')
2302  endif
2303  assert_equal(3, g:glob)
2304
2305  res = false
2306  if g:bool_true ? true : false
2307    res = true
2308  endif
2309  assert_equal(true, res)
2310
2311  res = false
2312  if true ? g:bool_true : false
2313    res = true
2314  endif
2315  assert_equal(true, res)
2316
2317  res = false
2318  if true ? true : g:bool_false
2319    res = true
2320  endif
2321  assert_equal(true, res)
2322
2323  res = false
2324  if true ? false : true
2325    res = true
2326  endif
2327  assert_equal(false, res)
2328
2329  res = false
2330  if false ? false : true
2331    res = true
2332  endif
2333  assert_equal(true, res)
2334
2335  res = false
2336  if false ? true : false
2337    res = true
2338  endif
2339  assert_equal(false, res)
2340
2341  res = false
2342  if has('xyz') ? true : false
2343    res = true
2344  endif
2345  assert_equal(false, res)
2346
2347  res = false
2348  if true && true
2349    res = true
2350  endif
2351  assert_equal(true, res)
2352
2353  res = false
2354  if true && false
2355    res = true
2356  endif
2357  assert_equal(false, res)
2358
2359  res = false
2360  if g:bool_true && false
2361    res = true
2362  endif
2363  assert_equal(false, res)
2364
2365  res = false
2366  if true && g:bool_false
2367    res = true
2368  endif
2369  assert_equal(false, res)
2370
2371  res = false
2372  if false && false
2373    res = true
2374  endif
2375  assert_equal(false, res)
2376
2377  res = false
2378  if true || false
2379    res = true
2380  endif
2381  assert_equal(true, res)
2382
2383  res = false
2384  if g:bool_true || false
2385    res = true
2386  endif
2387  assert_equal(true, res)
2388
2389  res = false
2390  if true || g:bool_false
2391    res = true
2392  endif
2393  assert_equal(true, res)
2394
2395  res = false
2396  if false || false
2397    res = true
2398  endif
2399  assert_equal(false, res)
2400
2401  # with constant "false" expression may be invalid so long as the syntax is OK
2402  if false | eval 1 + 2 | endif
2403  if false | eval burp + 234 | endif
2404  if false | echo burp 234 'asd' | endif
2405  if false
2406    burp
2407  endif
2408
2409  # expression with line breaks skipped
2410  if false
2411      ('aaa'
2412      .. 'bbb'
2413      .. 'ccc'
2414      )->setline(1)
2415  endif
2416enddef
2417
2418def Test_if_const_expr_fails()
2419  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
2420  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
2421  CheckDefFailure(["if has('aaa'"], 'E110:')
2422  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
2423enddef
2424
2425def RunNested(i: number): number
2426  var x: number = 0
2427  if i % 2
2428    if 1
2429      # comment
2430    else
2431      # comment
2432    endif
2433    x += 1
2434  else
2435    x += 1000
2436  endif
2437  return x
2438enddef
2439
2440def Test_nested_if()
2441  assert_equal(1, RunNested(1))
2442  assert_equal(1000, RunNested(2))
2443enddef
2444
2445def Test_execute_cmd()
2446  # missing argument is ignored
2447  execute
2448  execute # comment
2449
2450  new
2451  setline(1, 'default')
2452  execute 'setline(1, "execute-string")'
2453  assert_equal('execute-string', getline(1))
2454
2455  execute "setline(1, 'execute-string')"
2456  assert_equal('execute-string', getline(1))
2457
2458  var cmd1 = 'setline(1,'
2459  var cmd2 = '"execute-var")'
2460  execute cmd1 cmd2 # comment
2461  assert_equal('execute-var', getline(1))
2462
2463  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
2464  assert_equal('execute-var-string', getline(1))
2465
2466  var cmd_first = 'call '
2467  var cmd_last = 'setline(1, "execute-var-var")'
2468  execute cmd_first .. cmd_last
2469  assert_equal('execute-var-var', getline(1))
2470  bwipe!
2471
2472  var n = true
2473  execute 'echomsg' (n ? '"true"' : '"no"')
2474  assert_match('^true$', Screenline(&lines))
2475
2476  echomsg [1, 2, 3] {a: 1, b: 2}
2477  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
2478
2479  CheckDefFailure(['execute xxx'], 'E1001:', 1)
2480  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
2481  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
2482enddef
2483
2484def Test_execute_cmd_vimscript()
2485  # only checks line continuation
2486  var lines =<< trim END
2487      vim9script
2488      execute 'g:someVar'
2489                .. ' = ' ..
2490                   '28'
2491      assert_equal(28, g:someVar)
2492      unlet g:someVar
2493  END
2494  CheckScriptSuccess(lines)
2495enddef
2496
2497def Test_echo_cmd()
2498  echo 'some' # comment
2499  echon 'thing'
2500  assert_match('^something$', Screenline(&lines))
2501
2502  echo "some" # comment
2503  echon "thing"
2504  assert_match('^something$', Screenline(&lines))
2505
2506  var str1 = 'some'
2507  var str2 = 'more'
2508  echo str1 str2
2509  assert_match('^some more$', Screenline(&lines))
2510
2511  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
2512enddef
2513
2514def Test_echomsg_cmd()
2515  echomsg 'some' 'more' # comment
2516  assert_match('^some more$', Screenline(&lines))
2517  echo 'clear'
2518  :1messages
2519  assert_match('^some more$', Screenline(&lines))
2520
2521  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
2522enddef
2523
2524def Test_echomsg_cmd_vimscript()
2525  # only checks line continuation
2526  var lines =<< trim END
2527      vim9script
2528      echomsg 'here'
2529                .. ' is ' ..
2530                   'a message'
2531      assert_match('^here is a message$', Screenline(&lines))
2532  END
2533  CheckScriptSuccess(lines)
2534enddef
2535
2536def Test_echoerr_cmd()
2537  var local = 'local'
2538  try
2539    echoerr 'something' local 'wrong' # comment
2540  catch
2541    assert_match('something local wrong', v:exception)
2542  endtry
2543enddef
2544
2545def Test_echoerr_cmd_vimscript()
2546  # only checks line continuation
2547  var lines =<< trim END
2548      vim9script
2549      try
2550        echoerr 'this'
2551                .. ' is ' ..
2552                   'wrong'
2553      catch
2554        assert_match('this is wrong', v:exception)
2555      endtry
2556  END
2557  CheckScriptSuccess(lines)
2558enddef
2559
2560def Test_echoconsole_cmd()
2561  var local = 'local'
2562  echoconsole 'something' local # comment
2563  # output goes anywhere
2564enddef
2565
2566def Test_for_outside_of_function()
2567  var lines =<< trim END
2568    vim9script
2569    new
2570    for var in range(0, 3)
2571      append(line('$'), var)
2572    endfor
2573    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
2574    bwipe!
2575
2576    var result = ''
2577    for i in [1, 2, 3]
2578      var loop = ' loop ' .. i
2579      result ..= loop
2580    endfor
2581    assert_equal(' loop 1 loop 2 loop 3', result)
2582  END
2583  writefile(lines, 'Xvim9for.vim')
2584  source Xvim9for.vim
2585  delete('Xvim9for.vim')
2586enddef
2587
2588def Test_for_skipped_block()
2589  # test skipped blocks at outside of function
2590  var lines =<< trim END
2591    var result = []
2592    if true
2593      for n in [1, 2]
2594        result += [n]
2595      endfor
2596    else
2597      for n in [3, 4]
2598        result += [n]
2599      endfor
2600    endif
2601    assert_equal([1, 2], result)
2602
2603    result = []
2604    if false
2605      for n in [1, 2]
2606        result += [n]
2607      endfor
2608    else
2609      for n in [3, 4]
2610        result += [n]
2611      endfor
2612    endif
2613    assert_equal([3, 4], result)
2614  END
2615  CheckDefAndScriptSuccess(lines)
2616
2617  # test skipped blocks at inside of function
2618  lines =<< trim END
2619    def DefTrue()
2620      var result = []
2621      if true
2622        for n in [1, 2]
2623          result += [n]
2624        endfor
2625      else
2626        for n in [3, 4]
2627          result += [n]
2628        endfor
2629      endif
2630      assert_equal([1, 2], result)
2631    enddef
2632    DefTrue()
2633
2634    def DefFalse()
2635      var result = []
2636      if false
2637        for n in [1, 2]
2638          result += [n]
2639        endfor
2640      else
2641        for n in [3, 4]
2642          result += [n]
2643        endfor
2644      endif
2645      assert_equal([3, 4], result)
2646    enddef
2647    DefFalse()
2648  END
2649  CheckDefAndScriptSuccess(lines)
2650enddef
2651
2652def Test_for_loop()
2653  var lines =<< trim END
2654      var result = ''
2655      for cnt in range(7)
2656        if cnt == 4
2657          break
2658        endif
2659        if cnt == 2
2660          continue
2661        endif
2662        result ..= cnt .. '_'
2663      endfor
2664      assert_equal('0_1_3_', result)
2665
2666      var concat = ''
2667      for str in eval('["one", "two"]')
2668        concat ..= str
2669      endfor
2670      assert_equal('onetwo', concat)
2671
2672      var total = 0
2673      for nr in
2674          [1, 2, 3]
2675        total += nr
2676      endfor
2677      assert_equal(6, total)
2678
2679      total = 0
2680      for nr
2681        in [1, 2, 3]
2682        total += nr
2683      endfor
2684      assert_equal(6, total)
2685
2686      total = 0
2687      for nr
2688        in
2689        [1, 2, 3]
2690        total += nr
2691      endfor
2692      assert_equal(6, total)
2693
2694      # with type
2695      total = 0
2696      for n: number in [1, 2, 3]
2697        total += n
2698      endfor
2699      assert_equal(6, total)
2700
2701      var chars = ''
2702      for s: string in 'foobar'
2703        chars ..= s
2704      endfor
2705      assert_equal('foobar', chars)
2706
2707      chars = ''
2708      for x: string in {a: 'a', b: 'b'}->values()
2709        chars ..= x
2710      endfor
2711      assert_equal('ab', chars)
2712
2713      # unpack with type
2714      var res = ''
2715      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
2716        res ..= n .. s
2717      endfor
2718      assert_equal('1a2b', res)
2719
2720      # unpack with one var
2721      var reslist = []
2722      for [x] in [['aaa'], ['bbb']]
2723        reslist->add(x)
2724      endfor
2725      assert_equal(['aaa', 'bbb'], reslist)
2726
2727      # loop over string
2728      res = ''
2729      for c in 'aéc̀d'
2730        res ..= c .. '-'
2731      endfor
2732      assert_equal('a-é-c̀-d-', res)
2733
2734      res = ''
2735      for c in ''
2736        res ..= c .. '-'
2737      endfor
2738      assert_equal('', res)
2739
2740      res = ''
2741      for c in test_null_string()
2742        res ..= c .. '-'
2743      endfor
2744      assert_equal('', res)
2745
2746      var foo: list<dict<any>> = [
2747              {a: 'Cat'}
2748            ]
2749      for dd in foo
2750        dd.counter = 12
2751      endfor
2752      assert_equal([{a: 'Cat', counter: 12}], foo)
2753
2754      reslist = []
2755      for _ in range(3)
2756        reslist->add('x')
2757      endfor
2758      assert_equal(['x', 'x', 'x'], reslist)
2759  END
2760  CheckDefAndScriptSuccess(lines)
2761enddef
2762
2763def Test_for_loop_with_closure()
2764  var lines =<< trim END
2765      var flist: list<func>
2766      for i in range(5)
2767        var inloop = i
2768        flist[i] = () => inloop
2769      endfor
2770      for i in range(5)
2771        assert_equal(4, flist[i]())
2772      endfor
2773  END
2774  CheckDefAndScriptSuccess(lines)
2775
2776  lines =<< trim END
2777      var flist: list<func>
2778      for i in range(5)
2779        var inloop = i
2780        flist[i] = () => {
2781              return inloop
2782            }
2783      endfor
2784      for i in range(5)
2785        assert_equal(4, flist[i]())
2786      endfor
2787  END
2788  CheckDefAndScriptSuccess(lines)
2789enddef
2790
2791def Test_for_loop_fails()
2792  CheckDefAndScriptFailure2(['for '], 'E1097:', 'E690:')
2793  CheckDefAndScriptFailure2(['for x'], 'E1097:', 'E690:')
2794  CheckDefAndScriptFailure2(['for x in'], 'E1097:', 'E15:')
2795  CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
2796  CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
2797  CheckDefAndScriptFailure2(['var x = 5', 'for x in range(5)', 'endfor'], 'E1017:', 'E1041:')
2798  CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
2799  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2800  delfunc! g:Func
2801  CheckDefFailure(['for i in xxx'], 'E1001:')
2802  CheckDefFailure(['endfor'], 'E588:')
2803  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2804
2805  # wrong type detected at compile time
2806  CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2807
2808  # wrong type detected at runtime
2809  g:adict = {a: 1}
2810  CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2811  unlet g:adict
2812
2813  var lines =<< trim END
2814      var d: list<dict<any>> = [{a: 0}]
2815      for e in d
2816        e = {a: 0, b: ''}
2817      endfor
2818  END
2819  CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
2820
2821  lines =<< trim END
2822      for nr: number in ['foo']
2823      endfor
2824  END
2825  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
2826
2827  lines =<< trim END
2828      for n : number in [1, 2]
2829        echo n
2830      endfor
2831  END
2832  CheckDefAndScriptFailure(lines, 'E1059:', 1)
2833
2834  lines =<< trim END
2835      var d: dict<number> = {a: 1, b: 2}
2836      for [k: job, v: job] in d->items()
2837        echo k v
2838      endfor
2839  END
2840  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
2841enddef
2842
2843def Test_for_loop_script_var()
2844  # cannot use s:var in a :def function
2845  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2846
2847  # can use s:var in Vim9 script, with or without s:
2848  var lines =<< trim END
2849    vim9script
2850    var total = 0
2851    for s:var in [1, 2, 3]
2852      total += s:var
2853    endfor
2854    assert_equal(6, total)
2855
2856    total = 0
2857    for var in [1, 2, 3]
2858      total += var
2859    endfor
2860    assert_equal(6, total)
2861  END
2862enddef
2863
2864def Test_for_loop_unpack()
2865  var lines =<< trim END
2866      var result = []
2867      for [v1, v2] in [[1, 2], [3, 4]]
2868        result->add(v1)
2869        result->add(v2)
2870      endfor
2871      assert_equal([1, 2, 3, 4], result)
2872
2873      result = []
2874      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2875        result->add(v1)
2876        result->add(v2)
2877        result->add(v3)
2878      endfor
2879      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2880
2881      result = []
2882      for [&ts, &sw] in [[1, 2], [3, 4]]
2883        result->add(&ts)
2884        result->add(&sw)
2885      endfor
2886      assert_equal([1, 2, 3, 4], result)
2887
2888      var slist: list<string>
2889      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2890        slist->add($LOOPVAR)
2891        slist->add(@r)
2892        slist->add(v:errmsg)
2893      endfor
2894      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2895
2896      slist = []
2897      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2898        slist->add(g:globalvar)
2899        slist->add(b:bufvar)
2900        slist->add(w:winvar)
2901        slist->add(t:tabvar)
2902      endfor
2903      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2904      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2905
2906      var res = []
2907      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
2908        res->add(n)
2909      endfor
2910      assert_equal([2, 5], res)
2911  END
2912  CheckDefAndScriptSuccess(lines)
2913
2914  lines =<< trim END
2915      for [v1, v2] in [[1, 2, 3], [3, 4]]
2916        echo v1 v2
2917      endfor
2918  END
2919  CheckDefExecFailure(lines, 'E710:', 1)
2920
2921  lines =<< trim END
2922      for [v1, v2] in [[1], [3, 4]]
2923        echo v1 v2
2924      endfor
2925  END
2926  CheckDefExecFailure(lines, 'E711:', 1)
2927
2928  lines =<< trim END
2929      for [v1, v1] in [[1, 2], [3, 4]]
2930        echo v1
2931      endfor
2932  END
2933  CheckDefExecFailure(lines, 'E1017:', 1)
2934enddef
2935
2936def Test_for_loop_with_try_continue()
2937  var lines =<< trim END
2938      var looped = 0
2939      var cleanup = 0
2940      for i in range(3)
2941        looped += 1
2942        try
2943          eval [][0]
2944        catch
2945          continue
2946        finally
2947          cleanup += 1
2948        endtry
2949      endfor
2950      assert_equal(3, looped)
2951      assert_equal(3, cleanup)
2952  END
2953  CheckDefAndScriptSuccess(lines)
2954enddef
2955
2956def Test_while_skipped_block()
2957  # test skipped blocks at outside of function
2958  var lines =<< trim END
2959    var result = []
2960    var n = 0
2961    if true
2962      n = 1
2963      while n < 3
2964        result += [n]
2965        n += 1
2966      endwhile
2967    else
2968      n = 3
2969      while n < 5
2970        result += [n]
2971        n += 1
2972      endwhile
2973    endif
2974    assert_equal([1, 2], result)
2975
2976    result = []
2977    if false
2978      n = 1
2979      while n < 3
2980        result += [n]
2981        n += 1
2982      endwhile
2983    else
2984      n = 3
2985      while n < 5
2986        result += [n]
2987        n += 1
2988      endwhile
2989    endif
2990    assert_equal([3, 4], result)
2991  END
2992  CheckDefAndScriptSuccess(lines)
2993
2994  # test skipped blocks at inside of function
2995  lines =<< trim END
2996    def DefTrue()
2997      var result = []
2998      var n = 0
2999      if true
3000        n = 1
3001        while n < 3
3002          result += [n]
3003          n += 1
3004        endwhile
3005      else
3006        n = 3
3007        while n < 5
3008          result += [n]
3009          n += 1
3010        endwhile
3011      endif
3012      assert_equal([1, 2], result)
3013    enddef
3014    DefTrue()
3015
3016    def DefFalse()
3017      var result = []
3018      var n = 0
3019      if false
3020        n = 1
3021        while n < 3
3022          result += [n]
3023          n += 1
3024        endwhile
3025      else
3026        n = 3
3027        while n < 5
3028          result += [n]
3029          n += 1
3030        endwhile
3031      endif
3032      assert_equal([3, 4], result)
3033    enddef
3034    DefFalse()
3035  END
3036  CheckDefAndScriptSuccess(lines)
3037enddef
3038
3039def Test_while_loop()
3040  var result = ''
3041  var cnt = 0
3042  while cnt < 555
3043    if cnt == 3
3044      break
3045    endif
3046    cnt += 1
3047    if cnt == 2
3048      continue
3049    endif
3050    result ..= cnt .. '_'
3051  endwhile
3052  assert_equal('1_3_', result)
3053
3054  var s = ''
3055  while s == 'x' # {comment}
3056  endwhile
3057enddef
3058
3059def Test_while_loop_fails()
3060  CheckDefFailure(['while xxx'], 'E1001:')
3061  CheckDefFailure(['endwhile'], 'E588:')
3062  CheckDefFailure(['continue'], 'E586:')
3063  CheckDefFailure(['if true', 'continue'], 'E586:')
3064  CheckDefFailure(['break'], 'E587:')
3065  CheckDefFailure(['if true', 'break'], 'E587:')
3066  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
3067
3068  var lines =<< trim END
3069      var s = ''
3070      while s = ''
3071      endwhile
3072  END
3073  CheckDefFailure(lines, 'E488:')
3074enddef
3075
3076def Test_interrupt_loop()
3077  var caught = false
3078  var x = 0
3079  try
3080    while 1
3081      x += 1
3082      if x == 100
3083        feedkeys("\<C-C>", 'Lt')
3084      endif
3085    endwhile
3086  catch
3087    caught = true
3088    assert_equal(100, x)
3089  endtry
3090  assert_true(caught, 'should have caught an exception')
3091  # consume the CTRL-C
3092  getchar(0)
3093enddef
3094
3095def Test_automatic_line_continuation()
3096  var mylist = [
3097      'one',
3098      'two',
3099      'three',
3100      ] # comment
3101  assert_equal(['one', 'two', 'three'], mylist)
3102
3103  var mydict = {
3104      ['one']: 1,
3105      ['two']: 2,
3106      ['three']:
3107          3,
3108      } # comment
3109  assert_equal({one: 1, two: 2, three: 3}, mydict)
3110  mydict = {
3111      one: 1,  # comment
3112      two:     # comment
3113           2,  # comment
3114      three: 3 # comment
3115      }
3116  assert_equal({one: 1, two: 2, three: 3}, mydict)
3117  mydict = {
3118      one: 1,
3119      two:
3120           2,
3121      three: 3
3122      }
3123  assert_equal({one: 1, two: 2, three: 3}, mydict)
3124
3125  assert_equal(
3126        ['one', 'two', 'three'],
3127        split('one two three')
3128        )
3129enddef
3130
3131def Test_vim9_comment()
3132  CheckScriptSuccess([
3133      'vim9script',
3134      '# something',
3135      '#something',
3136      '#{something',
3137      ])
3138
3139  split Xfile
3140  CheckScriptSuccess([
3141      'vim9script',
3142      'edit #something',
3143      ])
3144  CheckScriptSuccess([
3145      'vim9script',
3146      'edit #{something',
3147      ])
3148  close
3149
3150  CheckScriptFailure([
3151      'vim9script',
3152      ':# something',
3153      ], 'E488:')
3154  CheckScriptFailure([
3155      '# something',
3156      ], 'E488:')
3157  CheckScriptFailure([
3158      ':# something',
3159      ], 'E488:')
3160
3161  { # block start
3162  } # block end
3163  CheckDefFailure([
3164      '{# comment',
3165      ], 'E488:')
3166  CheckDefFailure([
3167      '{',
3168      '}# comment',
3169      ], 'E488:')
3170
3171  echo "yes" # comment
3172  CheckDefFailure([
3173      'echo "yes"# comment',
3174      ], 'E488:')
3175  CheckScriptSuccess([
3176      'vim9script',
3177      'echo "yes" # something',
3178      ])
3179  CheckScriptFailure([
3180      'vim9script',
3181      'echo "yes"# something',
3182      ], 'E121:')
3183  CheckScriptFailure([
3184      'vim9script',
3185      'echo# something',
3186      ], 'E1144:')
3187  CheckScriptFailure([
3188      'echo "yes" # something',
3189      ], 'E121:')
3190
3191  exe "echo" # comment
3192  CheckDefFailure([
3193      'exe "echo"# comment',
3194      ], 'E488:')
3195  CheckScriptSuccess([
3196      'vim9script',
3197      'exe "echo" # something',
3198      ])
3199  CheckScriptFailure([
3200      'vim9script',
3201      'exe "echo"# something',
3202      ], 'E121:')
3203  CheckScriptFailure([
3204      'vim9script',
3205      'exe# something',
3206      ], 'E1144:')
3207  CheckScriptFailure([
3208      'exe "echo" # something',
3209      ], 'E121:')
3210
3211  CheckDefFailure([
3212      'try# comment',
3213      '  echo "yes"',
3214      'catch',
3215      'endtry',
3216      ], 'E1144:')
3217  CheckScriptFailure([
3218      'vim9script',
3219      'try# comment',
3220      'echo "yes"',
3221      ], 'E1144:')
3222  CheckDefFailure([
3223      'try',
3224      '  throw#comment',
3225      'catch',
3226      'endtry',
3227      ], 'E1144:')
3228  CheckDefFailure([
3229      'try',
3230      '  throw "yes"#comment',
3231      'catch',
3232      'endtry',
3233      ], 'E488:')
3234  CheckDefFailure([
3235      'try',
3236      '  echo "yes"',
3237      'catch# comment',
3238      'endtry',
3239      ], 'E1144:')
3240  CheckScriptFailure([
3241      'vim9script',
3242      'try',
3243      '  echo "yes"',
3244      'catch# comment',
3245      'endtry',
3246      ], 'E1144:')
3247  CheckDefFailure([
3248      'try',
3249      '  echo "yes"',
3250      'catch /pat/# comment',
3251      'endtry',
3252      ], 'E488:')
3253  CheckDefFailure([
3254      'try',
3255      'echo "yes"',
3256      'catch',
3257      'endtry# comment',
3258      ], 'E1144:')
3259  CheckScriptFailure([
3260      'vim9script',
3261      'try',
3262      '  echo "yes"',
3263      'catch',
3264      'endtry# comment',
3265      ], 'E1144:')
3266
3267  CheckScriptSuccess([
3268      'vim9script',
3269      'hi # comment',
3270      ])
3271  CheckScriptFailure([
3272      'vim9script',
3273      'hi# comment',
3274      ], 'E1144:')
3275  CheckScriptSuccess([
3276      'vim9script',
3277      'hi Search # comment',
3278      ])
3279  CheckScriptFailure([
3280      'vim9script',
3281      'hi Search# comment',
3282      ], 'E416:')
3283  CheckScriptSuccess([
3284      'vim9script',
3285      'hi link This Search # comment',
3286      ])
3287  CheckScriptFailure([
3288      'vim9script',
3289      'hi link This That# comment',
3290      ], 'E413:')
3291  CheckScriptSuccess([
3292      'vim9script',
3293      'hi clear This # comment',
3294      'hi clear # comment',
3295      ])
3296  # not tested, because it doesn't give an error but a warning:
3297  # hi clear This# comment',
3298  CheckScriptFailure([
3299      'vim9script',
3300      'hi clear# comment',
3301      ], 'E416:')
3302
3303  CheckScriptSuccess([
3304      'vim9script',
3305      'hi Group term=bold',
3306      'match Group /todo/ # comment',
3307      ])
3308  CheckScriptFailure([
3309      'vim9script',
3310      'hi Group term=bold',
3311      'match Group /todo/# comment',
3312      ], 'E488:')
3313  CheckScriptSuccess([
3314      'vim9script',
3315      'match # comment',
3316      ])
3317  CheckScriptFailure([
3318      'vim9script',
3319      'match# comment',
3320      ], 'E1144:')
3321  CheckScriptSuccess([
3322      'vim9script',
3323      'match none # comment',
3324      ])
3325  CheckScriptFailure([
3326      'vim9script',
3327      'match none# comment',
3328      ], 'E475:')
3329
3330  CheckScriptSuccess([
3331      'vim9script',
3332      'menutrans clear # comment',
3333      ])
3334  CheckScriptFailure([
3335      'vim9script',
3336      'menutrans clear# comment text',
3337      ], 'E474:')
3338
3339  CheckScriptSuccess([
3340      'vim9script',
3341      'syntax clear # comment',
3342      ])
3343  CheckScriptFailure([
3344      'vim9script',
3345      'syntax clear# comment text',
3346      ], 'E28:')
3347  CheckScriptSuccess([
3348      'vim9script',
3349      'syntax keyword Word some',
3350      'syntax clear Word # comment',
3351      ])
3352  CheckScriptFailure([
3353      'vim9script',
3354      'syntax keyword Word some',
3355      'syntax clear Word# comment text',
3356      ], 'E28:')
3357
3358  CheckScriptSuccess([
3359      'vim9script',
3360      'syntax list # comment',
3361      ])
3362  CheckScriptFailure([
3363      'vim9script',
3364      'syntax list# comment text',
3365      ], 'E28:')
3366
3367  CheckScriptSuccess([
3368      'vim9script',
3369      'syntax match Word /pat/ oneline # comment',
3370      ])
3371  CheckScriptFailure([
3372      'vim9script',
3373      'syntax match Word /pat/ oneline# comment',
3374      ], 'E475:')
3375
3376  CheckScriptSuccess([
3377      'vim9script',
3378      'syntax keyword Word word # comm[ent',
3379      ])
3380  CheckScriptFailure([
3381      'vim9script',
3382      'syntax keyword Word word# comm[ent',
3383      ], 'E789:')
3384
3385  CheckScriptSuccess([
3386      'vim9script',
3387      'syntax match Word /pat/ # comment',
3388      ])
3389  CheckScriptFailure([
3390      'vim9script',
3391      'syntax match Word /pat/# comment',
3392      ], 'E402:')
3393
3394  CheckScriptSuccess([
3395      'vim9script',
3396      'syntax match Word /pat/ contains=Something # comment',
3397      ])
3398  CheckScriptFailure([
3399      'vim9script',
3400      'syntax match Word /pat/ contains=Something# comment',
3401      ], 'E475:')
3402  CheckScriptFailure([
3403      'vim9script',
3404      'syntax match Word /pat/ contains= # comment',
3405      ], 'E406:')
3406  CheckScriptFailure([
3407      'vim9script',
3408      'syntax match Word /pat/ contains=# comment',
3409      ], 'E475:')
3410
3411  CheckScriptSuccess([
3412      'vim9script',
3413      'syntax region Word start=/pat/ end=/pat/ # comment',
3414      ])
3415  CheckScriptFailure([
3416      'vim9script',
3417      'syntax region Word start=/pat/ end=/pat/# comment',
3418      ], 'E402:')
3419
3420  CheckScriptSuccess([
3421      'vim9script',
3422      'syntax sync # comment',
3423      ])
3424  CheckScriptFailure([
3425      'vim9script',
3426      'syntax sync# comment',
3427      ], 'E404:')
3428  CheckScriptSuccess([
3429      'vim9script',
3430      'syntax sync ccomment # comment',
3431      ])
3432  CheckScriptFailure([
3433      'vim9script',
3434      'syntax sync ccomment# comment',
3435      ], 'E404:')
3436
3437  CheckScriptSuccess([
3438      'vim9script',
3439      'syntax cluster Some contains=Word # comment',
3440      ])
3441  CheckScriptFailure([
3442      'vim9script',
3443      'syntax cluster Some contains=Word# comment',
3444      ], 'E475:')
3445
3446  CheckScriptSuccess([
3447      'vim9script',
3448      'command Echo echo # comment',
3449      'command Echo # comment',
3450      'delcommand Echo',
3451      ])
3452  CheckScriptFailure([
3453      'vim9script',
3454      'command Echo echo# comment',
3455      'Echo',
3456      ], 'E1144:')
3457  delcommand Echo
3458
3459  var curdir = getcwd()
3460  CheckScriptSuccess([
3461      'command Echo cd " comment',
3462      'Echo',
3463      'delcommand Echo',
3464      ])
3465  CheckScriptSuccess([
3466      'vim9script',
3467      'command Echo cd # comment',
3468      'Echo',
3469      'delcommand Echo',
3470      ])
3471  CheckScriptFailure([
3472      'vim9script',
3473      'command Echo cd " comment',
3474      'Echo',
3475      ], 'E344:')
3476  delcommand Echo
3477  chdir(curdir)
3478
3479  CheckScriptFailure([
3480      'vim9script',
3481      'command Echo# comment',
3482      ], 'E182:')
3483  CheckScriptFailure([
3484      'vim9script',
3485      'command Echo echo',
3486      'command Echo# comment',
3487      ], 'E182:')
3488  delcommand Echo
3489
3490  CheckScriptSuccess([
3491      'vim9script',
3492      'function # comment',
3493      ])
3494  CheckScriptFailure([
3495      'vim9script',
3496      'function " comment',
3497      ], 'E129:')
3498  CheckScriptFailure([
3499      'vim9script',
3500      'function# comment',
3501      ], 'E1144:')
3502  CheckScriptSuccess([
3503      'vim9script',
3504      'function CheckScriptSuccess # comment',
3505      ])
3506  CheckScriptFailure([
3507      'vim9script',
3508      'function CheckScriptSuccess# comment',
3509      ], 'E488:')
3510
3511  CheckScriptSuccess([
3512      'vim9script',
3513      'func g:DeleteMeA()',
3514      'endfunc',
3515      'delfunction g:DeleteMeA # comment',
3516      ])
3517  CheckScriptFailure([
3518      'vim9script',
3519      'func g:DeleteMeB()',
3520      'endfunc',
3521      'delfunction g:DeleteMeB# comment',
3522      ], 'E488:')
3523
3524  CheckScriptSuccess([
3525      'vim9script',
3526      'call execute("ls") # comment',
3527      ])
3528  CheckScriptFailure([
3529      'vim9script',
3530      'call execute("ls")# comment',
3531      ], 'E488:')
3532
3533  CheckScriptFailure([
3534      'def Test() " comment',
3535      'enddef',
3536      ], 'E488:')
3537  CheckScriptFailure([
3538      'vim9script',
3539      'def Test() " comment',
3540      'enddef',
3541      ], 'E488:')
3542
3543  CheckScriptSuccess([
3544      'func Test() " comment',
3545      'endfunc',
3546      'delfunc Test',
3547      ])
3548  CheckScriptSuccess([
3549      'vim9script',
3550      'func Test() " comment',
3551      'endfunc',
3552      ])
3553
3554  CheckScriptSuccess([
3555      'def Test() # comment',
3556      'enddef',
3557      ])
3558  CheckScriptFailure([
3559      'func Test() # comment',
3560      'endfunc',
3561      ], 'E488:')
3562
3563  var lines =<< trim END
3564      vim9script
3565      syn region Text
3566      \ start='foo'
3567      #\ comment
3568      \ end='bar'
3569      syn region Text start='foo'
3570      #\ comment
3571      \ end='bar'
3572  END
3573  CheckScriptSuccess(lines)
3574
3575  lines =<< trim END
3576      vim9script
3577      syn region Text
3578      \ start='foo'
3579      "\ comment
3580      \ end='bar'
3581  END
3582  CheckScriptFailure(lines, 'E399:')
3583enddef
3584
3585def Test_vim9_comment_gui()
3586  CheckCanRunGui
3587
3588  CheckScriptFailure([
3589      'vim9script',
3590      'gui#comment'
3591      ], 'E1144:')
3592  CheckScriptFailure([
3593      'vim9script',
3594      'gui -f#comment'
3595      ], 'E194:')
3596enddef
3597
3598def Test_vim9_comment_not_compiled()
3599  au TabEnter *.vim g:entered = 1
3600  au TabEnter *.x g:entered = 2
3601
3602  edit test.vim
3603  doautocmd TabEnter #comment
3604  assert_equal(1, g:entered)
3605
3606  doautocmd TabEnter f.x
3607  assert_equal(2, g:entered)
3608
3609  g:entered = 0
3610  doautocmd TabEnter f.x #comment
3611  assert_equal(2, g:entered)
3612
3613  assert_fails('doautocmd Syntax#comment', 'E216:')
3614
3615  au! TabEnter
3616  unlet g:entered
3617
3618  CheckScriptSuccess([
3619      'vim9script',
3620      'g:var = 123',
3621      'b:var = 456',
3622      'w:var = 777',
3623      't:var = 888',
3624      'unlet g:var w:var # something',
3625      ])
3626
3627  CheckScriptFailure([
3628      'vim9script',
3629      'let var = 123',
3630      ], 'E1126: Cannot use :let in Vim9 script')
3631
3632  CheckScriptFailure([
3633      'vim9script',
3634      'var g:var = 123',
3635      ], 'E1016: Cannot declare a global variable:')
3636
3637  CheckScriptFailure([
3638      'vim9script',
3639      'var b:var = 123',
3640      ], 'E1016: Cannot declare a buffer variable:')
3641
3642  CheckScriptFailure([
3643      'vim9script',
3644      'var w:var = 123',
3645      ], 'E1016: Cannot declare a window variable:')
3646
3647  CheckScriptFailure([
3648      'vim9script',
3649      'var t:var = 123',
3650      ], 'E1016: Cannot declare a tab variable:')
3651
3652  CheckScriptFailure([
3653      'vim9script',
3654      'var v:version = 123',
3655      ], 'E1016: Cannot declare a v: variable:')
3656
3657  CheckScriptFailure([
3658      'vim9script',
3659      'var $VARIABLE = "text"',
3660      ], 'E1016: Cannot declare an environment variable:')
3661
3662  CheckScriptFailure([
3663      'vim9script',
3664      'g:var = 123',
3665      'unlet g:var# comment1',
3666      ], 'E108:')
3667
3668  CheckScriptFailure([
3669      'let g:var = 123',
3670      'unlet g:var # something',
3671      ], 'E488:')
3672
3673  CheckScriptSuccess([
3674      'vim9script',
3675      'if 1 # comment2',
3676      '  echo "yes"',
3677      'elseif 2 #comment',
3678      '  echo "no"',
3679      'endif',
3680      ])
3681
3682  CheckScriptFailure([
3683      'vim9script',
3684      'if 1# comment3',
3685      '  echo "yes"',
3686      'endif',
3687      ], 'E488:')
3688
3689  CheckScriptFailure([
3690      'vim9script',
3691      'if 0 # comment4',
3692      '  echo "yes"',
3693      'elseif 2#comment',
3694      '  echo "no"',
3695      'endif',
3696      ], 'E488:')
3697
3698  CheckScriptSuccess([
3699      'vim9script',
3700      'var v = 1 # comment5',
3701      ])
3702
3703  CheckScriptFailure([
3704      'vim9script',
3705      'var v = 1# comment6',
3706      ], 'E488:')
3707
3708  CheckScriptSuccess([
3709      'vim9script',
3710      'new'
3711      'setline(1, ["# define pat", "last"])',
3712      ':$',
3713      'dsearch /pat/ #comment',
3714      'bwipe!',
3715      ])
3716
3717  CheckScriptFailure([
3718      'vim9script',
3719      'new'
3720      'setline(1, ["# define pat", "last"])',
3721      ':$',
3722      'dsearch /pat/#comment',
3723      'bwipe!',
3724      ], 'E488:')
3725
3726  CheckScriptFailure([
3727      'vim9script',
3728      'func! SomeFunc()',
3729      ], 'E477:')
3730enddef
3731
3732def Test_finish()
3733  var lines =<< trim END
3734    vim9script
3735    g:res = 'one'
3736    if v:false | finish | endif
3737    g:res = 'two'
3738    finish
3739    g:res = 'three'
3740  END
3741  writefile(lines, 'Xfinished')
3742  source Xfinished
3743  assert_equal('two', g:res)
3744
3745  unlet g:res
3746  delete('Xfinished')
3747enddef
3748
3749def Test_forward_declaration()
3750  var lines =<< trim END
3751    vim9script
3752    def GetValue(): string
3753      return theVal
3754    enddef
3755    var theVal = 'something'
3756    g:initVal = GetValue()
3757    theVal = 'else'
3758    g:laterVal = GetValue()
3759  END
3760  writefile(lines, 'Xforward')
3761  source Xforward
3762  assert_equal('something', g:initVal)
3763  assert_equal('else', g:laterVal)
3764
3765  unlet g:initVal
3766  unlet g:laterVal
3767  delete('Xforward')
3768enddef
3769
3770def Test_source_vim9_from_legacy()
3771  var vim9_lines =<< trim END
3772    vim9script
3773    var local = 'local'
3774    g:global = 'global'
3775    export var exported = 'exported'
3776    export def GetText(): string
3777       return 'text'
3778    enddef
3779  END
3780  writefile(vim9_lines, 'Xvim9_script.vim')
3781
3782  var legacy_lines =<< trim END
3783    source Xvim9_script.vim
3784
3785    call assert_false(exists('local'))
3786    call assert_false(exists('exported'))
3787    call assert_false(exists('s:exported'))
3788    call assert_equal('global', global)
3789    call assert_equal('global', g:global)
3790
3791    " imported variable becomes script-local
3792    import exported from './Xvim9_script.vim'
3793    call assert_equal('exported', s:exported)
3794    call assert_false(exists('exported'))
3795
3796    " imported function becomes script-local
3797    import GetText from './Xvim9_script.vim'
3798    call assert_equal('text', s:GetText())
3799    call assert_false(exists('*GetText'))
3800  END
3801  writefile(legacy_lines, 'Xlegacy_script.vim')
3802
3803  source Xlegacy_script.vim
3804  assert_equal('global', g:global)
3805  unlet g:global
3806
3807  delete('Xlegacy_script.vim')
3808  delete('Xvim9_script.vim')
3809enddef
3810
3811def Test_declare_script_in_func()
3812  var lines =<< trim END
3813      vim9script
3814      func Declare()
3815        let s:local = 123
3816      endfunc
3817      Declare()
3818      assert_equal(123, local)
3819
3820      var error: string
3821      try
3822        local = 'asdf'
3823      catch
3824        error = v:exception
3825      endtry
3826      assert_match('E1012: Type mismatch; expected number but got string', error)
3827
3828      lockvar local
3829      try
3830        local = 999
3831      catch
3832        error = v:exception
3833      endtry
3834      assert_match('E741: Value is locked: local', error)
3835  END
3836  CheckScriptSuccess(lines)
3837enddef
3838
3839
3840func Test_vim9script_not_global()
3841  " check that items defined in Vim9 script are script-local, not global
3842  let vim9lines =<< trim END
3843    vim9script
3844    var name = 'local'
3845    func TheFunc()
3846      echo 'local'
3847    endfunc
3848    def DefFunc()
3849      echo 'local'
3850    enddef
3851  END
3852  call writefile(vim9lines, 'Xvim9script.vim')
3853  source Xvim9script.vim
3854  try
3855    echo g:var
3856    assert_report('did not fail')
3857  catch /E121:/
3858    " caught
3859  endtry
3860  try
3861    call TheFunc()
3862    assert_report('did not fail')
3863  catch /E117:/
3864    " caught
3865  endtry
3866  try
3867    call DefFunc()
3868    assert_report('did not fail')
3869  catch /E117:/
3870    " caught
3871  endtry
3872
3873  call delete('Xvim9script.vim')
3874endfunc
3875
3876def Test_vim9_copen()
3877  # this was giving an error for setting w:quickfix_title
3878  copen
3879  quit
3880enddef
3881
3882" test using an auto-loaded function and variable
3883def Test_vim9_autoload()
3884  var lines =<< trim END
3885     vim9script
3886     def some#gettest(): string
3887       return 'test'
3888     enddef
3889     g:some#name = 'name'
3890     g:some#dict = {key: 'value'}
3891
3892     def some#varargs(a1: string, ...l: list<string>): string
3893       return a1 .. l[0] .. l[1]
3894     enddef
3895  END
3896
3897  mkdir('Xdir/autoload', 'p')
3898  writefile(lines, 'Xdir/autoload/some.vim')
3899  var save_rtp = &rtp
3900  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3901
3902  assert_equal('test', g:some#gettest())
3903  assert_equal('name', g:some#name)
3904  assert_equal('value', g:some#dict.key)
3905  g:some#other = 'other'
3906  assert_equal('other', g:some#other)
3907
3908  assert_equal('abc', some#varargs('a', 'b', 'c'))
3909
3910  # upper case script name works
3911  lines =<< trim END
3912     vim9script
3913     def Other#getOther(): string
3914       return 'other'
3915     enddef
3916  END
3917  writefile(lines, 'Xdir/autoload/Other.vim')
3918  assert_equal('other', g:Other#getOther())
3919
3920  delete('Xdir', 'rf')
3921  &rtp = save_rtp
3922enddef
3923
3924" test using a vim9script that is auto-loaded from an autocmd
3925def Test_vim9_aucmd_autoload()
3926  var lines =<< trim END
3927     vim9script
3928     def foo#test()
3929         echomsg getreg('"')
3930     enddef
3931  END
3932
3933  mkdir('Xdir/autoload', 'p')
3934  writefile(lines, 'Xdir/autoload/foo.vim')
3935  var save_rtp = &rtp
3936  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3937  augroup test
3938    autocmd TextYankPost * call foo#test()
3939  augroup END
3940
3941  normal Y
3942
3943  augroup test
3944    autocmd!
3945  augroup END
3946  delete('Xdir', 'rf')
3947  &rtp = save_rtp
3948enddef
3949
3950" This was causing a crash because suppress_errthrow wasn't reset.
3951def Test_vim9_autoload_error()
3952  var lines =<< trim END
3953      vim9script
3954      def crash#func()
3955          try
3956              for x in List()
3957              endfor
3958          catch
3959          endtry
3960          g:ok = true
3961      enddef
3962      fu List()
3963          invalid
3964      endfu
3965      try
3966          alsoinvalid
3967      catch /wontmatch/
3968      endtry
3969  END
3970  call mkdir('Xruntime/autoload', 'p')
3971  call writefile(lines, 'Xruntime/autoload/crash.vim')
3972
3973  # run in a separate Vim to avoid the side effects of assert_fails()
3974  lines =<< trim END
3975    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
3976    call crash#func()
3977    call writefile(['ok'], 'Xdidit')
3978    qall!
3979  END
3980  writefile(lines, 'Xscript')
3981  RunVim([], [], '-S Xscript')
3982  assert_equal(['ok'], readfile('Xdidit'))
3983
3984  delete('Xdidit')
3985  delete('Xscript')
3986  delete('Xruntime', 'rf')
3987
3988  lines =<< trim END
3989    vim9script
3990    var foo#bar = 'asdf'
3991  END
3992  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
3993enddef
3994
3995def Test_script_var_in_autocmd()
3996  # using a script variable from an autocommand, defined in a :def function in a
3997  # legacy Vim script, cannot check the variable type.
3998  var lines =<< trim END
3999    let s:counter = 1
4000    def s:Func()
4001      au! CursorHold
4002      au CursorHold * s:counter += 1
4003    enddef
4004    call s:Func()
4005    doau CursorHold
4006    call assert_equal(2, s:counter)
4007    au! CursorHold
4008  END
4009  CheckScriptSuccess(lines)
4010enddef
4011
4012def Test_error_in_autoload_script()
4013  var save_rtp = &rtp
4014  var dir = getcwd() .. '/Xruntime'
4015  &rtp = dir
4016  mkdir(dir .. '/autoload', 'p')
4017
4018  var lines =<< trim END
4019      vim9script noclear
4020      def script#autoloaded()
4021      enddef
4022      def Broken()
4023        var x: any = ''
4024        eval x != 0
4025      enddef
4026      Broken()
4027  END
4028  writefile(lines, dir .. '/autoload/script.vim')
4029
4030  lines =<< trim END
4031      vim9script
4032      def CallAutoloaded()
4033        script#autoloaded()
4034      enddef
4035
4036      function Legacy()
4037        try
4038          call s:CallAutoloaded()
4039        catch
4040          call assert_match('E1030: Using a String as a Number', v:exception)
4041        endtry
4042      endfunction
4043
4044      Legacy()
4045  END
4046  CheckScriptSuccess(lines)
4047
4048  &rtp = save_rtp
4049  delete(dir, 'rf')
4050enddef
4051
4052def Test_cmdline_win()
4053  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
4054  # the command line window.
4055  mkdir('rtp/syntax', 'p')
4056  var export_lines =<< trim END
4057    vim9script
4058    export var That = 'yes'
4059  END
4060  writefile(export_lines, 'rtp/syntax/Xexport.vim')
4061  var import_lines =<< trim END
4062    vim9script
4063    import That from './Xexport.vim'
4064  END
4065  writefile(import_lines, 'rtp/syntax/vim.vim')
4066  var save_rtp = &rtp
4067  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
4068  syntax on
4069  augroup CmdWin
4070    autocmd CmdwinEnter * g:got_there = 'yes'
4071  augroup END
4072  # this will open and also close the cmdline window
4073  feedkeys('q:', 'xt')
4074  assert_equal('yes', g:got_there)
4075
4076  augroup CmdWin
4077    au!
4078  augroup END
4079  &rtp = save_rtp
4080  delete('rtp', 'rf')
4081enddef
4082
4083def Test_invalid_sid()
4084  assert_fails('func <SNR>1234_func', 'E123:')
4085
4086  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
4087    assert_equal([], readfile('Xdidit'))
4088  endif
4089  delete('Xdidit')
4090enddef
4091
4092def Test_restoring_cpo()
4093  writefile(['vim9script', 'set nocp'], 'Xsourced')
4094  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
4095  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
4096    assert_equal(['done'], readfile('Xdone'))
4097  endif
4098  delete('Xsourced')
4099  delete('Xclose')
4100  delete('Xdone')
4101
4102  writefile(['vim9script'], 'XanotherScript')
4103  set cpo=aABceFsMny>
4104  edit XanotherScript
4105  so %
4106  assert_equal('aABceFsMny>', &cpo)
4107  :1del
4108  w
4109  so %
4110  assert_equal('aABceFsMny>', &cpo)
4111
4112  delete('XanotherScript')
4113  set cpo&vim
4114enddef
4115
4116" Use :function so we can use Check commands
4117func Test_no_redraw_when_restoring_cpo()
4118  CheckScreendump
4119  CheckFeature timers
4120
4121  let lines =<< trim END
4122    vim9script
4123    def script#func()
4124    enddef
4125  END
4126  call mkdir('Xdir/autoload', 'p')
4127  call writefile(lines, 'Xdir/autoload/script.vim')
4128
4129  let lines =<< trim END
4130      vim9script
4131      set cpo+=M
4132      exe 'set rtp^=' .. getcwd() .. '/Xdir'
4133      au CmdlineEnter : ++once timer_start(0, (_) => script#func())
4134      setline(1, 'some text')
4135  END
4136  call writefile(lines, 'XTest_redraw_cpo')
4137  let buf = RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
4138  call term_sendkeys(buf, "V:")
4139  call VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
4140
4141  " clean up
4142  call term_sendkeys(buf, "\<Esc>u")
4143  call StopVimInTerminal(buf)
4144  call delete('XTest_redraw_cpo')
4145  call delete('Xdir', 'rf')
4146endfunc
4147
4148
4149def Test_unset_any_variable()
4150  var lines =<< trim END
4151    var name: any
4152    assert_equal(0, name)
4153  END
4154  CheckDefAndScriptSuccess(lines)
4155enddef
4156
4157func Test_define_func_at_command_line()
4158  CheckRunVimInTerminal
4159
4160  " call indirectly to avoid compilation error for missing functions
4161  call Run_Test_define_func_at_command_line()
4162endfunc
4163
4164def Run_Test_define_func_at_command_line()
4165  # run in a separate Vim instance to avoid the script context
4166  var lines =<< trim END
4167    func CheckAndQuit()
4168      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
4169      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
4170    endfunc
4171  END
4172  writefile([''], 'Xdidcmd')
4173  writefile(lines, 'XcallFunc')
4174  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
4175  # define Afunc() on the command line
4176  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
4177  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
4178  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
4179
4180  call StopVimInTerminal(buf)
4181  delete('XcallFunc')
4182  delete('Xdidcmd')
4183enddef
4184
4185def Test_script_var_scope()
4186  var lines =<< trim END
4187      vim9script
4188      if true
4189        if true
4190          var one = 'one'
4191          echo one
4192        endif
4193        echo one
4194      endif
4195  END
4196  CheckScriptFailure(lines, 'E121:', 7)
4197
4198  lines =<< trim END
4199      vim9script
4200      if true
4201        if false
4202          var one = 'one'
4203          echo one
4204        else
4205          var one = 'one'
4206          echo one
4207        endif
4208        echo one
4209      endif
4210  END
4211  CheckScriptFailure(lines, 'E121:', 10)
4212
4213  lines =<< trim END
4214      vim9script
4215      while true
4216        var one = 'one'
4217        echo one
4218        break
4219      endwhile
4220      echo one
4221  END
4222  CheckScriptFailure(lines, 'E121:', 7)
4223
4224  lines =<< trim END
4225      vim9script
4226      for i in range(1)
4227        var one = 'one'
4228        echo one
4229      endfor
4230      echo one
4231  END
4232  CheckScriptFailure(lines, 'E121:', 6)
4233
4234  lines =<< trim END
4235      vim9script
4236      {
4237        var one = 'one'
4238        assert_equal('one', one)
4239      }
4240      assert_false(exists('one'))
4241      assert_false(exists('s:one'))
4242  END
4243  CheckScriptSuccess(lines)
4244
4245  lines =<< trim END
4246      vim9script
4247      {
4248        var one = 'one'
4249        echo one
4250      }
4251      echo one
4252  END
4253  CheckScriptFailure(lines, 'E121:', 6)
4254enddef
4255
4256def Test_catch_exception_in_callback()
4257  var lines =<< trim END
4258    vim9script
4259    def Callback(...l: list<any>)
4260      try
4261        var x: string
4262        var y: string
4263        # this error should be caught with CHECKLEN
4264        [x, y] = ['']
4265      catch
4266        g:caught = 'yes'
4267      endtry
4268    enddef
4269    popup_menu('popup', {callback: Callback})
4270    feedkeys("\r", 'xt')
4271  END
4272  CheckScriptSuccess(lines)
4273
4274  unlet g:caught
4275enddef
4276
4277def Test_no_unknown_error_after_error()
4278  if !has('unix') || !has('job')
4279    throw 'Skipped: not unix of missing +job feature'
4280  endif
4281  # FIXME: this check should not be needed
4282  if has('win32')
4283    throw 'Skipped: does not work on MS-Windows'
4284  endif
4285  var lines =<< trim END
4286      vim9script
4287      var source: list<number>
4288      def Out_cb(...l: list<any>)
4289          eval [][0]
4290      enddef
4291      def Exit_cb(...l: list<any>)
4292          sleep 1m
4293          source += l
4294      enddef
4295      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
4296      while job_status(myjob) == 'run'
4297        sleep 10m
4298      endwhile
4299      # wait for Exit_cb() to be called
4300      sleep 200m
4301  END
4302  writefile(lines, 'Xdef')
4303  assert_fails('so Xdef', ['E684:', 'E1012:'])
4304  delete('Xdef')
4305enddef
4306
4307def InvokeNormal()
4308  exe "norm! :m+1\r"
4309enddef
4310
4311def Test_invoke_normal_in_visual_mode()
4312  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
4313  new
4314  setline(1, ['aaa', 'bbb'])
4315  feedkeys("V\<F3>", 'xt')
4316  assert_equal(['bbb', 'aaa'], getline(1, 2))
4317  xunmap <F3>
4318enddef
4319
4320def Test_white_space_after_command()
4321  var lines =<< trim END
4322    exit_cb: Func})
4323  END
4324  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4325
4326  lines =<< trim END
4327    e#
4328  END
4329  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4330enddef
4331
4332def Test_script_var_gone_when_sourced_twice()
4333  var lines =<< trim END
4334      vim9script
4335      if exists('g:guard')
4336        finish
4337      endif
4338      g:guard = 1
4339      var name = 'thename'
4340      def g:GetName(): string
4341        return name
4342      enddef
4343      def g:SetName(arg: string)
4344        name = arg
4345      enddef
4346  END
4347  writefile(lines, 'XscriptTwice.vim')
4348  so XscriptTwice.vim
4349  assert_equal('thename', g:GetName())
4350  g:SetName('newname')
4351  assert_equal('newname', g:GetName())
4352  so XscriptTwice.vim
4353  assert_fails('call g:GetName()', 'E1149:')
4354  assert_fails('call g:SetName("x")', 'E1149:')
4355
4356  delfunc g:GetName
4357  delfunc g:SetName
4358  delete('XscriptTwice.vim')
4359  unlet g:guard
4360enddef
4361
4362def Test_import_gone_when_sourced_twice()
4363  var exportlines =<< trim END
4364      vim9script
4365      if exists('g:guard')
4366        finish
4367      endif
4368      g:guard = 1
4369      export var name = 'someName'
4370  END
4371  writefile(exportlines, 'XexportScript.vim')
4372
4373  var lines =<< trim END
4374      vim9script
4375      import name from './XexportScript.vim'
4376      def g:GetName(): string
4377        return name
4378      enddef
4379  END
4380  writefile(lines, 'XscriptImport.vim')
4381  so XscriptImport.vim
4382  assert_equal('someName', g:GetName())
4383
4384  so XexportScript.vim
4385  assert_fails('call g:GetName()', 'E1149:')
4386
4387  delfunc g:GetName
4388  delete('XexportScript.vim')
4389  delete('XscriptImport.vim')
4390  unlet g:guard
4391enddef
4392
4393def Test_unsupported_commands()
4394  var lines =<< trim END
4395      ka
4396  END
4397  CheckDefFailure(lines, 'E476:')
4398  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4399
4400  lines =<< trim END
4401      :1ka
4402  END
4403  CheckDefFailure(lines, 'E476:')
4404  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4405
4406  lines =<< trim END
4407    t
4408  END
4409  CheckDefFailure(lines, 'E1100:')
4410  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4411
4412  lines =<< trim END
4413    x
4414  END
4415  CheckDefFailure(lines, 'E1100:')
4416  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4417
4418  lines =<< trim END
4419    xit
4420  END
4421  CheckDefFailure(lines, 'E1100:')
4422  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4423enddef
4424
4425def Test_mapping_line_number()
4426  var lines =<< trim END
4427      vim9script
4428      def g:FuncA()
4429          # Some comment
4430          FuncB(0)
4431      enddef
4432          # Some comment
4433      def FuncB(
4434          # Some comment
4435          n: number
4436      )
4437          exe 'nno '
4438              # Some comment
4439              .. '<F3> a'
4440              .. 'b'
4441              .. 'c'
4442      enddef
4443  END
4444  CheckScriptSuccess(lines)
4445  var res = execute('verbose nmap <F3>')
4446  assert_match('No mapping found', res)
4447
4448  g:FuncA()
4449  res = execute('verbose nmap <F3>')
4450  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
4451
4452  nunmap <F3>
4453  delfunc g:FuncA
4454enddef
4455
4456def Test_option_set()
4457  # legacy script allows for white space
4458  var lines =<< trim END
4459      set foldlevel  =11
4460      call assert_equal(11, &foldlevel)
4461  END
4462  CheckScriptSuccess(lines)
4463
4464  set foldlevel
4465  set foldlevel=12
4466  assert_equal(12, &foldlevel)
4467  set foldlevel+=2
4468  assert_equal(14, &foldlevel)
4469  set foldlevel-=3
4470  assert_equal(11, &foldlevel)
4471
4472  lines =<< trim END
4473      set foldlevel =1
4474  END
4475  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
4476
4477  lines =<< trim END
4478      set foldlevel +=1
4479  END
4480  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
4481
4482  lines =<< trim END
4483      set foldlevel ^=1
4484  END
4485  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
4486
4487  lines =<< trim END
4488      set foldlevel -=1
4489  END
4490  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
4491
4492  set foldlevel&
4493enddef
4494
4495def Test_option_modifier()
4496  # legacy script allows for white space
4497  var lines =<< trim END
4498      set hlsearch &  hlsearch  !
4499      call assert_equal(1, &hlsearch)
4500  END
4501  CheckScriptSuccess(lines)
4502
4503  set hlsearch
4504  set hlsearch!
4505  assert_equal(false, &hlsearch)
4506
4507  set hlsearch
4508  set hlsearch&
4509  assert_equal(false, &hlsearch)
4510
4511  lines =<< trim END
4512      set hlsearch &
4513  END
4514  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
4515
4516  lines =<< trim END
4517      set hlsearch   !
4518  END
4519  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
4520
4521  set hlsearch&
4522enddef
4523
4524" This must be called last, it may cause following :def functions to fail
4525def Test_xxx_echoerr_line_number()
4526  var lines =<< trim END
4527      echoerr 'some'
4528         .. ' error'
4529         .. ' continued'
4530  END
4531  CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
4532enddef
4533
4534def ProfiledWithLambda()
4535  var n = 3
4536  echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
4537enddef
4538
4539def ProfiledNested()
4540  var x = 0
4541  def Nested(): any
4542      return x
4543  enddef
4544  Nested()
4545enddef
4546
4547def ProfiledNestedProfiled()
4548  var x = 0
4549  def Nested(): any
4550      return x
4551  enddef
4552  Nested()
4553enddef
4554
4555" Execute this near the end, profiling doesn't stop until Vim exists.
4556" This only tests that it works, not the profiling output.
4557def Test_xx_profile_with_lambda()
4558  CheckFeature profile
4559
4560  profile start Xprofile.log
4561  profile func ProfiledWithLambda
4562  ProfiledWithLambda()
4563
4564  profile func ProfiledNested
4565  ProfiledNested()
4566
4567  # Also profile the nested function.  Use a different function, although the
4568  # contents is the same, to make sure it was not already compiled.
4569  profile func *
4570  ProfiledNestedProfiled()
4571
4572  profdel func *
4573  profile pause
4574enddef
4575
4576" Keep this last, it messes up highlighting.
4577def Test_substitute_cmd()
4578  new
4579  setline(1, 'something')
4580  :substitute(some(other(
4581  assert_equal('otherthing', getline(1))
4582  bwipe!
4583
4584  # also when the context is Vim9 script
4585  var lines =<< trim END
4586    vim9script
4587    new
4588    setline(1, 'something')
4589    :substitute(some(other(
4590    assert_equal('otherthing', getline(1))
4591    bwipe!
4592  END
4593  writefile(lines, 'Xvim9lines')
4594  source Xvim9lines
4595
4596  delete('Xvim9lines')
4597enddef
4598
4599" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
4600