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 '/tmp/foo.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 '/tmp/foo.vim'
1490      var that = foo
1491  END
1492  CheckScriptFailure(lines, 'E1029: Expected ''.''')
1493enddef
1494
1495def Test_import_as()
1496  var export_lines =<< trim END
1497    vim9script
1498    export var one = 1
1499    export var yes = 'yes'
1500    export var slist: list<string>
1501  END
1502  writefile(export_lines, 'XexportAs')
1503
1504  var import_lines =<< trim END
1505    vim9script
1506    var one = 'notused'
1507    var yes = 777
1508    import one as thatOne from './XexportAs'
1509    assert_equal(1, thatOne)
1510    import yes as yesYes from './XexportAs'
1511    assert_equal('yes', yesYes)
1512  END
1513  CheckScriptSuccess(import_lines)
1514
1515  import_lines =<< trim END
1516    vim9script
1517    import {one as thatOne, yes as yesYes} from './XexportAs'
1518    assert_equal(1, thatOne)
1519    assert_equal('yes', yesYes)
1520    assert_fails('echo one', 'E121:')
1521    assert_fails('echo yes', 'E121:')
1522  END
1523  CheckScriptSuccess(import_lines)
1524
1525  import_lines =<< trim END
1526    vim9script
1527    import {slist as impSlist} from './XexportAs'
1528    impSlist->add(123)
1529  END
1530  CheckScriptFailure(import_lines, 'E1012: Type mismatch; expected string but got number')
1531
1532  delete('XexportAs')
1533enddef
1534
1535func g:Trigger()
1536  source Ximport.vim
1537  return "echo 'yes'\<CR>"
1538endfunc
1539
1540def Test_import_export_expr_map()
1541  # check that :import and :export work when buffer is locked
1542  var export_lines =<< trim END
1543    vim9script
1544    export def That(): string
1545      return 'yes'
1546    enddef
1547  END
1548  writefile(export_lines, 'Xexport_that.vim')
1549
1550  var import_lines =<< trim END
1551    vim9script
1552    import That from './Xexport_that.vim'
1553    assert_equal('yes', That())
1554  END
1555  writefile(import_lines, 'Ximport.vim')
1556
1557  nnoremap <expr> trigger g:Trigger()
1558  feedkeys('trigger', "xt")
1559
1560  delete('Xexport_that.vim')
1561  delete('Ximport.vim')
1562  nunmap trigger
1563enddef
1564
1565def Test_import_in_filetype()
1566  # check that :import works when the buffer is locked
1567  mkdir('ftplugin', 'p')
1568  var export_lines =<< trim END
1569    vim9script
1570    export var That = 'yes'
1571  END
1572  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1573
1574  var import_lines =<< trim END
1575    vim9script
1576    import That from './Xexport_ft.vim'
1577    assert_equal('yes', That)
1578    g:did_load_mytpe = 1
1579  END
1580  writefile(import_lines, 'ftplugin/qf.vim')
1581
1582  var save_rtp = &rtp
1583  &rtp = getcwd() .. ',' .. &rtp
1584
1585  filetype plugin on
1586  copen
1587  assert_equal(1, g:did_load_mytpe)
1588
1589  quit!
1590  delete('Xexport_ft.vim')
1591  delete('ftplugin', 'rf')
1592  &rtp = save_rtp
1593enddef
1594
1595def Test_use_import_in_mapping()
1596  var lines =<< trim END
1597      vim9script
1598      export def Funcx()
1599        g:result = 42
1600      enddef
1601  END
1602  writefile(lines, 'XsomeExport.vim')
1603  lines =<< trim END
1604      vim9script
1605      import Funcx from './XsomeExport.vim'
1606      nnoremap <F3> :call <sid>Funcx()<cr>
1607  END
1608  writefile(lines, 'Xmapscript.vim')
1609
1610  source Xmapscript.vim
1611  feedkeys("\<F3>", "xt")
1612  assert_equal(42, g:result)
1613
1614  unlet g:result
1615  delete('XsomeExport.vim')
1616  delete('Xmapscript.vim')
1617  nunmap <F3>
1618enddef
1619
1620def Test_vim9script_mix()
1621  var lines =<< trim END
1622    if has(g:feature)
1623      " legacy script
1624      let g:legacy = 1
1625      finish
1626    endif
1627    vim9script
1628    g:legacy = 0
1629  END
1630  g:feature = 'eval'
1631  g:legacy = -1
1632  CheckScriptSuccess(lines)
1633  assert_equal(1, g:legacy)
1634
1635  g:feature = 'noteval'
1636  g:legacy = -1
1637  CheckScriptSuccess(lines)
1638  assert_equal(0, g:legacy)
1639enddef
1640
1641def Test_vim9script_fails()
1642  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1643  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1644  CheckScriptFailure(['export var some = 123'], 'E1042:')
1645  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1646  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1647  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1648
1649  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1650  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1651
1652  assert_fails('vim9script', 'E1038:')
1653  assert_fails('export something', 'E1043:')
1654enddef
1655
1656func Test_import_fails_without_script()
1657  CheckRunVimInTerminal
1658
1659  " call indirectly to avoid compilation error for missing functions
1660  call Run_Test_import_fails_on_command_line()
1661endfunc
1662
1663def Run_Test_import_fails_on_command_line()
1664  var export =<< trim END
1665    vim9script
1666    export def Foo(): number
1667        return 0
1668    enddef
1669  END
1670  writefile(export, 'XexportCmd.vim')
1671
1672  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1673                rows: 6, wait_for_ruler: 0})
1674  WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
1675
1676  delete('XexportCmd.vim')
1677  StopVimInTerminal(buf)
1678enddef
1679
1680def Test_vim9script_reload_noclear()
1681  var lines =<< trim END
1682    vim9script
1683    export var exported = 'thexport'
1684
1685    export def TheFunc(x = 0)
1686    enddef
1687  END
1688  writefile(lines, 'XExportReload')
1689  lines =<< trim END
1690    vim9script noclear
1691    g:loadCount += 1
1692    var s:reloaded = 'init'
1693    import exported from './XExportReload'
1694
1695    def Again(): string
1696      return 'again'
1697    enddef
1698
1699    import TheFunc from './XExportReload'
1700    TheFunc()
1701
1702    if exists('s:loaded') | finish | endif
1703    var s:loaded = true
1704
1705    var s:notReloaded = 'yes'
1706    s:reloaded = 'first'
1707    def g:Values(): list<string>
1708      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
1709    enddef
1710
1711    def Once(): string
1712      return 'once'
1713    enddef
1714  END
1715  writefile(lines, 'XReloaded')
1716  g:loadCount = 0
1717  source XReloaded
1718  assert_equal(1, g:loadCount)
1719  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
1720  source XReloaded
1721  assert_equal(2, g:loadCount)
1722  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1723  source XReloaded
1724  assert_equal(3, g:loadCount)
1725  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1726
1727  delete('XReloaded')
1728  delete('XExportReload')
1729  delfunc g:Values
1730  unlet g:loadCount
1731
1732  lines =<< trim END
1733      vim9script
1734      def Inner()
1735      enddef
1736  END
1737  lines->writefile('XreloadScript.vim')
1738  source XreloadScript.vim
1739
1740  lines =<< trim END
1741      vim9script
1742      def Outer()
1743        def Inner()
1744        enddef
1745      enddef
1746      defcompile
1747  END
1748  lines->writefile('XreloadScript.vim')
1749  source XreloadScript.vim
1750
1751  delete('XreloadScript.vim')
1752enddef
1753
1754def Test_vim9script_reload_import()
1755  var lines =<< trim END
1756    vim9script
1757    const var = ''
1758    var valone = 1234
1759    def MyFunc(arg: string)
1760       valone = 5678
1761    enddef
1762  END
1763  var morelines =<< trim END
1764    var valtwo = 222
1765    export def GetValtwo(): number
1766      return valtwo
1767    enddef
1768  END
1769  writefile(lines + morelines, 'Xreload.vim')
1770  source Xreload.vim
1771  source Xreload.vim
1772  source Xreload.vim
1773
1774  # cannot declare a var twice
1775  lines =<< trim END
1776    vim9script
1777    var valone = 1234
1778    var valone = 5678
1779  END
1780  writefile(lines, 'Xreload.vim')
1781  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1782
1783  delete('Xreload.vim')
1784  delete('Ximport.vim')
1785enddef
1786
1787" if a script is reloaded with a script-local variable that changed its type, a
1788" compiled function using that variable must fail.
1789def Test_script_reload_change_type()
1790  var lines =<< trim END
1791    vim9script noclear
1792    var str = 'string'
1793    def g:GetStr(): string
1794      return str .. 'xxx'
1795    enddef
1796  END
1797  writefile(lines, 'Xreload.vim')
1798  source Xreload.vim
1799  echo g:GetStr()
1800
1801  lines =<< trim END
1802    vim9script noclear
1803    var str = 1234
1804  END
1805  writefile(lines, 'Xreload.vim')
1806  source Xreload.vim
1807  assert_fails('echo g:GetStr()', 'E1150:')
1808
1809  delfunc g:GetStr
1810  delete('Xreload.vim')
1811enddef
1812
1813" Define CallFunc so that the test can be compiled
1814command CallFunc echo 'nop'
1815
1816def Test_script_reload_from_function()
1817  var lines =<< trim END
1818      vim9script
1819
1820      if exists('g:loaded')
1821        finish
1822      endif
1823      g:loaded = 1
1824      delcommand CallFunc
1825      command CallFunc Func()
1826      def Func()
1827        so XreloadFunc.vim
1828        g:didTheFunc = 1
1829      enddef
1830  END
1831  writefile(lines, 'XreloadFunc.vim')
1832  source XreloadFunc.vim
1833  CallFunc
1834  assert_equal(1, g:didTheFunc)
1835
1836  delete('XreloadFunc.vim')
1837  delcommand CallFunc
1838  unlet g:loaded
1839  unlet g:didTheFunc
1840enddef
1841
1842def Test_script_var_shadows_function()
1843  var lines =<< trim END
1844      vim9script
1845      def Func(): number
1846        return 123
1847      enddef
1848      var Func = 1
1849  END
1850  CheckScriptFailure(lines, 'E1041:', 5)
1851enddef
1852
1853def Test_script_var_shadows_command()
1854  var lines =<< trim END
1855      var undo = 1
1856      undo = 2
1857      assert_equal(2, undo)
1858  END
1859  CheckDefAndScriptSuccess(lines)
1860
1861  lines =<< trim END
1862      var undo = 1
1863      undo
1864  END
1865  CheckDefAndScriptFailure(lines, 'E1207:', 2)
1866enddef
1867
1868def s:RetSome(): string
1869  return 'some'
1870enddef
1871
1872" Not exported function that is referenced needs to be accessed by the
1873" script-local name.
1874def Test_vim9script_funcref()
1875  var sortlines =<< trim END
1876      vim9script
1877      def Compare(i1: number, i2: number): number
1878        return i2 - i1
1879      enddef
1880
1881      export def FastSort(): list<number>
1882        return range(5)->sort(Compare)
1883      enddef
1884
1885      export def GetString(arg: string): string
1886        return arg
1887      enddef
1888  END
1889  writefile(sortlines, 'Xsort.vim')
1890
1891  var lines =<< trim END
1892    vim9script
1893    import FastSort from './Xsort.vim'
1894    def Test()
1895      g:result = FastSort()
1896    enddef
1897    Test()
1898
1899    # using a function imported with "as"
1900    import * as anAlias from './Xsort.vim'
1901    assert_equal('yes', anAlias.GetString('yes'))
1902
1903    # using the function from a compiled function
1904    def TestMore(): string
1905      var s = s:anAlias.GetString('foo')
1906      return s .. anAlias.GetString('bar')
1907    enddef
1908    assert_equal('foobar', TestMore())
1909
1910    # error when using a function that isn't exported
1911    assert_fails('anAlias.Compare(1, 2)', 'E1049:')
1912  END
1913  writefile(lines, 'Xscript.vim')
1914
1915  source Xscript.vim
1916  assert_equal([4, 3, 2, 1, 0], g:result)
1917
1918  unlet g:result
1919  delete('Xsort.vim')
1920  delete('Xscript.vim')
1921
1922  var Funcref = function('s:RetSome')
1923  assert_equal('some', Funcref())
1924enddef
1925
1926" Check that when searching for "FilterFunc" it finds the import in the
1927" script where FastFilter() is called from, both as a string and as a direct
1928" function reference.
1929def Test_vim9script_funcref_other_script()
1930  var filterLines =<< trim END
1931    vim9script
1932    export def FilterFunc(idx: number, val: number): bool
1933      return idx % 2 == 1
1934    enddef
1935    export def FastFilter(): list<number>
1936      return range(10)->filter('FilterFunc')
1937    enddef
1938    export def FastFilterDirect(): list<number>
1939      return range(10)->filter(FilterFunc)
1940    enddef
1941  END
1942  writefile(filterLines, 'Xfilter.vim')
1943
1944  var lines =<< trim END
1945    vim9script
1946    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1947    def Test()
1948      var x: list<number> = FastFilter()
1949    enddef
1950    Test()
1951    def TestDirect()
1952      var x: list<number> = FastFilterDirect()
1953    enddef
1954    TestDirect()
1955  END
1956  CheckScriptSuccess(lines)
1957  delete('Xfilter.vim')
1958enddef
1959
1960def Test_vim9script_reload_delfunc()
1961  var first_lines =<< trim END
1962    vim9script
1963    def FuncYes(): string
1964      return 'yes'
1965    enddef
1966  END
1967  var withno_lines =<< trim END
1968    def FuncNo(): string
1969      return 'no'
1970    enddef
1971    def g:DoCheck(no_exists: bool)
1972      assert_equal('yes', FuncYes())
1973      assert_equal('no', FuncNo())
1974    enddef
1975  END
1976  var nono_lines =<< trim END
1977    def g:DoCheck(no_exists: bool)
1978      assert_equal('yes', FuncYes())
1979      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
1980    enddef
1981  END
1982
1983  # FuncNo() is defined
1984  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1985  source Xreloaded.vim
1986  g:DoCheck(true)
1987
1988  # FuncNo() is not redefined
1989  writefile(first_lines + nono_lines, 'Xreloaded.vim')
1990  source Xreloaded.vim
1991  g:DoCheck(false)
1992
1993  # FuncNo() is back
1994  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1995  source Xreloaded.vim
1996  g:DoCheck(false)
1997
1998  delete('Xreloaded.vim')
1999enddef
2000
2001def Test_vim9script_reload_delvar()
2002  # write the script with a script-local variable
2003  var lines =<< trim END
2004    vim9script
2005    var name = 'string'
2006  END
2007  writefile(lines, 'XreloadVar.vim')
2008  source XreloadVar.vim
2009
2010  # now write the script using the same variable locally - works
2011  lines =<< trim END
2012    vim9script
2013    def Func()
2014      var name = 'string'
2015    enddef
2016  END
2017  writefile(lines, 'XreloadVar.vim')
2018  source XreloadVar.vim
2019
2020  delete('XreloadVar.vim')
2021enddef
2022
2023def Test_import_absolute()
2024  var import_lines = [
2025        'vim9script',
2026        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
2027        'def UseExported()',
2028        '  g:imported_abs = exported',
2029        '  exported = 8888',
2030        '  g:imported_after = exported',
2031        'enddef',
2032        'UseExported()',
2033        'g:import_disassembled = execute("disass UseExported")',
2034        ]
2035  writefile(import_lines, 'Ximport_abs.vim')
2036  writefile(s:export_script_lines, 'Xexport_abs.vim')
2037
2038  source Ximport_abs.vim
2039
2040  assert_equal(9876, g:imported_abs)
2041  assert_equal(8888, g:imported_after)
2042  assert_match('<SNR>\d\+_UseExported\_s*' ..
2043          'g:imported_abs = exported\_s*' ..
2044          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2045          '1 STOREG g:imported_abs\_s*' ..
2046          'exported = 8888\_s*' ..
2047          '2 PUSHNR 8888\_s*' ..
2048          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
2049          'g:imported_after = exported\_s*' ..
2050          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2051          '5 STOREG g:imported_after',
2052        g:import_disassembled)
2053
2054  Undo_export_script_lines()
2055  unlet g:imported_abs
2056  unlet g:import_disassembled
2057
2058  delete('Ximport_abs.vim')
2059  delete('Xexport_abs.vim')
2060enddef
2061
2062def Test_import_rtp()
2063  var import_lines = [
2064        'vim9script',
2065        'import exported from "Xexport_rtp.vim"',
2066        'g:imported_rtp = exported',
2067        ]
2068  writefile(import_lines, 'Ximport_rtp.vim')
2069  mkdir('import', 'p')
2070  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
2071
2072  var save_rtp = &rtp
2073  &rtp = getcwd()
2074  source Ximport_rtp.vim
2075  &rtp = save_rtp
2076
2077  assert_equal(9876, g:imported_rtp)
2078
2079  Undo_export_script_lines()
2080  unlet g:imported_rtp
2081  delete('Ximport_rtp.vim')
2082  delete('import', 'rf')
2083enddef
2084
2085def Test_import_compile_error()
2086  var export_lines = [
2087        'vim9script',
2088        'export def ExpFunc(): string',
2089        '  return notDefined',
2090        'enddef',
2091        ]
2092  writefile(export_lines, 'Xexported.vim')
2093
2094  var import_lines = [
2095        'vim9script',
2096        'import ExpFunc from "./Xexported.vim"',
2097        'def ImpFunc()',
2098        '  echo ExpFunc()',
2099        'enddef',
2100        'defcompile',
2101        ]
2102  writefile(import_lines, 'Ximport.vim')
2103
2104  try
2105    source Ximport.vim
2106  catch /E1001/
2107    # Error should be fore the Xexported.vim file.
2108    assert_match('E1001: Variable not found: notDefined', v:exception)
2109    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
2110  endtry
2111
2112  delete('Xexported.vim')
2113  delete('Ximport.vim')
2114enddef
2115
2116def Test_func_redefine_error()
2117  var lines = [
2118        'vim9script',
2119        'def Func()',
2120        '  eval [][0]',
2121        'enddef',
2122        'Func()',
2123        ]
2124  writefile(lines, 'Xtestscript.vim')
2125
2126  for count in range(3)
2127    try
2128      source Xtestscript.vim
2129    catch /E684/
2130      # function name should contain <SNR> every time
2131      assert_match('E684: list index out of range', v:exception)
2132      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
2133    endtry
2134  endfor
2135
2136  delete('Xtestscript.vim')
2137enddef
2138
2139def Test_func_overrules_import_fails()
2140  var export_lines =<< trim END
2141      vim9script
2142      export def Func()
2143        echo 'imported'
2144      enddef
2145  END
2146  writefile(export_lines, 'XexportedFunc.vim')
2147
2148  var lines =<< trim END
2149    vim9script
2150    import Func from './XexportedFunc.vim'
2151    def Func()
2152      echo 'local to function'
2153    enddef
2154  END
2155  CheckScriptFailure(lines, 'E1073:')
2156
2157  lines =<< trim END
2158    vim9script
2159    import Func from './XexportedFunc.vim'
2160    def Outer()
2161      def Func()
2162        echo 'local to function'
2163      enddef
2164    enddef
2165    defcompile
2166  END
2167  CheckScriptFailure(lines, 'E1073:')
2168
2169  delete('XexportedFunc.vim')
2170enddef
2171
2172def Test_func_redefine_fails()
2173  var lines =<< trim END
2174    vim9script
2175    def Func()
2176      echo 'one'
2177    enddef
2178    def Func()
2179      echo 'two'
2180    enddef
2181  END
2182  CheckScriptFailure(lines, 'E1073:')
2183
2184  lines =<< trim END
2185    vim9script
2186    def Foo(): string
2187      return 'foo'
2188      enddef
2189    def Func()
2190      var  Foo = {-> 'lambda'}
2191    enddef
2192    defcompile
2193  END
2194  CheckScriptFailure(lines, 'E1073:')
2195enddef
2196
2197def Test_fixed_size_list()
2198  # will be allocated as one piece of memory, check that changes work
2199  var l = [1, 2, 3, 4]
2200  l->remove(0)
2201  l->add(5)
2202  l->insert(99, 1)
2203  assert_equal([2, 99, 3, 4, 5], l)
2204enddef
2205
2206def Test_no_insert_xit()
2207  CheckDefExecFailure(['a = 1'], 'E1100:')
2208  CheckDefExecFailure(['c = 1'], 'E1100:')
2209  CheckDefExecFailure(['i = 1'], 'E1100:')
2210  CheckDefExecFailure(['t = 1'], 'E1100:')
2211  CheckDefExecFailure(['x = 1'], 'E1100:')
2212
2213  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
2214  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
2215  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
2216  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
2217  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
2218  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
2219  CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
2220  CheckScriptFailure(['vim9script', 'o'], 'E1100:')
2221  CheckScriptFailure(['vim9script', 't'], 'E1100:')
2222  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
2223  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
2224enddef
2225
2226def IfElse(what: number): string
2227  var res = ''
2228  if what == 1
2229    res = "one"
2230  elseif what == 2
2231    res = "two"
2232  else
2233    res = "three"
2234  endif
2235  return res
2236enddef
2237
2238def Test_if_elseif_else()
2239  assert_equal('one', IfElse(1))
2240  assert_equal('two', IfElse(2))
2241  assert_equal('three', IfElse(3))
2242enddef
2243
2244def Test_if_elseif_else_fails()
2245  CheckDefFailure(['elseif true'], 'E582:')
2246  CheckDefFailure(['else'], 'E581:')
2247  CheckDefFailure(['endif'], 'E580:')
2248  CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
2249  CheckDefFailure(['if true', 'echo 1'], 'E171:')
2250
2251  var lines =<< trim END
2252      var s = ''
2253      if s = ''
2254      endif
2255  END
2256  CheckDefFailure(lines, 'E488:')
2257
2258  lines =<< trim END
2259      var s = ''
2260      if s == ''
2261      elseif s = ''
2262      endif
2263  END
2264  CheckDefFailure(lines, 'E488:')
2265enddef
2266
2267let g:bool_true = v:true
2268let g:bool_false = v:false
2269
2270def Test_if_const_expr()
2271  var res = false
2272  if true ? true : false
2273    res = true
2274  endif
2275  assert_equal(true, res)
2276
2277  g:glob = 2
2278  if false
2279    execute('g:glob = 3')
2280  endif
2281  assert_equal(2, g:glob)
2282  if true
2283    execute('g:glob = 3')
2284  endif
2285  assert_equal(3, g:glob)
2286
2287  res = false
2288  if g:bool_true ? true : false
2289    res = true
2290  endif
2291  assert_equal(true, res)
2292
2293  res = false
2294  if true ? g:bool_true : false
2295    res = true
2296  endif
2297  assert_equal(true, res)
2298
2299  res = false
2300  if true ? true : g:bool_false
2301    res = true
2302  endif
2303  assert_equal(true, res)
2304
2305  res = false
2306  if true ? false : true
2307    res = true
2308  endif
2309  assert_equal(false, res)
2310
2311  res = false
2312  if false ? false : true
2313    res = true
2314  endif
2315  assert_equal(true, res)
2316
2317  res = false
2318  if false ? true : false
2319    res = true
2320  endif
2321  assert_equal(false, res)
2322
2323  res = false
2324  if has('xyz') ? true : false
2325    res = true
2326  endif
2327  assert_equal(false, res)
2328
2329  res = false
2330  if true && true
2331    res = true
2332  endif
2333  assert_equal(true, res)
2334
2335  res = false
2336  if true && false
2337    res = true
2338  endif
2339  assert_equal(false, res)
2340
2341  res = false
2342  if g:bool_true && false
2343    res = true
2344  endif
2345  assert_equal(false, res)
2346
2347  res = false
2348  if true && g:bool_false
2349    res = true
2350  endif
2351  assert_equal(false, res)
2352
2353  res = false
2354  if false && false
2355    res = true
2356  endif
2357  assert_equal(false, res)
2358
2359  res = false
2360  if true || false
2361    res = true
2362  endif
2363  assert_equal(true, res)
2364
2365  res = false
2366  if g:bool_true || false
2367    res = true
2368  endif
2369  assert_equal(true, res)
2370
2371  res = false
2372  if true || g:bool_false
2373    res = true
2374  endif
2375  assert_equal(true, res)
2376
2377  res = false
2378  if false || false
2379    res = true
2380  endif
2381  assert_equal(false, res)
2382
2383  # with constant "false" expression may be invalid so long as the syntax is OK
2384  if false | eval 1 + 2 | endif
2385  if false | eval burp + 234 | endif
2386  if false | echo burp 234 'asd' | endif
2387  if false
2388    burp
2389  endif
2390
2391  # expression with line breaks skipped
2392  if false
2393      ('aaa'
2394      .. 'bbb'
2395      .. 'ccc'
2396      )->setline(1)
2397  endif
2398enddef
2399
2400def Test_if_const_expr_fails()
2401  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
2402  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
2403  CheckDefFailure(["if has('aaa'"], 'E110:')
2404  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
2405enddef
2406
2407def RunNested(i: number): number
2408  var x: number = 0
2409  if i % 2
2410    if 1
2411      # comment
2412    else
2413      # comment
2414    endif
2415    x += 1
2416  else
2417    x += 1000
2418  endif
2419  return x
2420enddef
2421
2422def Test_nested_if()
2423  assert_equal(1, RunNested(1))
2424  assert_equal(1000, RunNested(2))
2425enddef
2426
2427def Test_execute_cmd()
2428  # missing argument is ignored
2429  execute
2430  execute # comment
2431
2432  new
2433  setline(1, 'default')
2434  execute 'setline(1, "execute-string")'
2435  assert_equal('execute-string', getline(1))
2436
2437  execute "setline(1, 'execute-string')"
2438  assert_equal('execute-string', getline(1))
2439
2440  var cmd1 = 'setline(1,'
2441  var cmd2 = '"execute-var")'
2442  execute cmd1 cmd2 # comment
2443  assert_equal('execute-var', getline(1))
2444
2445  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
2446  assert_equal('execute-var-string', getline(1))
2447
2448  var cmd_first = 'call '
2449  var cmd_last = 'setline(1, "execute-var-var")'
2450  execute cmd_first .. cmd_last
2451  assert_equal('execute-var-var', getline(1))
2452  bwipe!
2453
2454  var n = true
2455  execute 'echomsg' (n ? '"true"' : '"no"')
2456  assert_match('^true$', Screenline(&lines))
2457
2458  echomsg [1, 2, 3] {a: 1, b: 2}
2459  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
2460
2461  CheckDefFailure(['execute xxx'], 'E1001:', 1)
2462  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
2463  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
2464enddef
2465
2466def Test_execute_cmd_vimscript()
2467  # only checks line continuation
2468  var lines =<< trim END
2469      vim9script
2470      execute 'g:someVar'
2471                .. ' = ' ..
2472                   '28'
2473      assert_equal(28, g:someVar)
2474      unlet g:someVar
2475  END
2476  CheckScriptSuccess(lines)
2477enddef
2478
2479def Test_echo_cmd()
2480  echo 'some' # comment
2481  echon 'thing'
2482  assert_match('^something$', Screenline(&lines))
2483
2484  echo "some" # comment
2485  echon "thing"
2486  assert_match('^something$', Screenline(&lines))
2487
2488  var str1 = 'some'
2489  var str2 = 'more'
2490  echo str1 str2
2491  assert_match('^some more$', Screenline(&lines))
2492
2493  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
2494enddef
2495
2496def Test_echomsg_cmd()
2497  echomsg 'some' 'more' # comment
2498  assert_match('^some more$', Screenline(&lines))
2499  echo 'clear'
2500  :1messages
2501  assert_match('^some more$', Screenline(&lines))
2502
2503  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
2504enddef
2505
2506def Test_echomsg_cmd_vimscript()
2507  # only checks line continuation
2508  var lines =<< trim END
2509      vim9script
2510      echomsg 'here'
2511                .. ' is ' ..
2512                   'a message'
2513      assert_match('^here is a message$', Screenline(&lines))
2514  END
2515  CheckScriptSuccess(lines)
2516enddef
2517
2518def Test_echoerr_cmd()
2519  var local = 'local'
2520  try
2521    echoerr 'something' local 'wrong' # comment
2522  catch
2523    assert_match('something local wrong', v:exception)
2524  endtry
2525enddef
2526
2527def Test_echoerr_cmd_vimscript()
2528  # only checks line continuation
2529  var lines =<< trim END
2530      vim9script
2531      try
2532        echoerr 'this'
2533                .. ' is ' ..
2534                   'wrong'
2535      catch
2536        assert_match('this is wrong', v:exception)
2537      endtry
2538  END
2539  CheckScriptSuccess(lines)
2540enddef
2541
2542def Test_echoconsole_cmd()
2543  var local = 'local'
2544  echoconsole 'something' local # comment
2545  # output goes anywhere
2546enddef
2547
2548def Test_for_outside_of_function()
2549  var lines =<< trim END
2550    vim9script
2551    new
2552    for var in range(0, 3)
2553      append(line('$'), var)
2554    endfor
2555    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
2556    bwipe!
2557
2558    var result = ''
2559    for i in [1, 2, 3]
2560      var loop = ' loop ' .. i
2561      result ..= loop
2562    endfor
2563    assert_equal(' loop 1 loop 2 loop 3', result)
2564  END
2565  writefile(lines, 'Xvim9for.vim')
2566  source Xvim9for.vim
2567  delete('Xvim9for.vim')
2568enddef
2569
2570def Test_for_skipped_block()
2571  # test skipped blocks at outside of function
2572  var lines =<< trim END
2573    var result = []
2574    if true
2575      for n in [1, 2]
2576        result += [n]
2577      endfor
2578    else
2579      for n in [3, 4]
2580        result += [n]
2581      endfor
2582    endif
2583    assert_equal([1, 2], result)
2584
2585    result = []
2586    if false
2587      for n in [1, 2]
2588        result += [n]
2589      endfor
2590    else
2591      for n in [3, 4]
2592        result += [n]
2593      endfor
2594    endif
2595    assert_equal([3, 4], result)
2596  END
2597  CheckDefAndScriptSuccess(lines)
2598
2599  # test skipped blocks at inside of function
2600  lines =<< trim END
2601    def DefTrue()
2602      var result = []
2603      if true
2604        for n in [1, 2]
2605          result += [n]
2606        endfor
2607      else
2608        for n in [3, 4]
2609          result += [n]
2610        endfor
2611      endif
2612      assert_equal([1, 2], result)
2613    enddef
2614    DefTrue()
2615
2616    def DefFalse()
2617      var result = []
2618      if false
2619        for n in [1, 2]
2620          result += [n]
2621        endfor
2622      else
2623        for n in [3, 4]
2624          result += [n]
2625        endfor
2626      endif
2627      assert_equal([3, 4], result)
2628    enddef
2629    DefFalse()
2630  END
2631  CheckDefAndScriptSuccess(lines)
2632enddef
2633
2634def Test_for_loop()
2635  var lines =<< trim END
2636      var result = ''
2637      for cnt in range(7)
2638        if cnt == 4
2639          break
2640        endif
2641        if cnt == 2
2642          continue
2643        endif
2644        result ..= cnt .. '_'
2645      endfor
2646      assert_equal('0_1_3_', result)
2647
2648      var concat = ''
2649      for str in eval('["one", "two"]')
2650        concat ..= str
2651      endfor
2652      assert_equal('onetwo', concat)
2653
2654      var total = 0
2655      for nr in
2656          [1, 2, 3]
2657        total += nr
2658      endfor
2659      assert_equal(6, total)
2660
2661      total = 0
2662      for nr
2663        in [1, 2, 3]
2664        total += nr
2665      endfor
2666      assert_equal(6, total)
2667
2668      total = 0
2669      for nr
2670        in
2671        [1, 2, 3]
2672        total += nr
2673      endfor
2674      assert_equal(6, total)
2675
2676      # with type
2677      total = 0
2678      for n: number in [1, 2, 3]
2679        total += n
2680      endfor
2681      assert_equal(6, total)
2682
2683      var chars = ''
2684      for s: string in 'foobar'
2685        chars ..= s
2686      endfor
2687      assert_equal('foobar', chars)
2688
2689      chars = ''
2690      for x: string in {a: 'a', b: 'b'}->values()
2691        chars ..= x
2692      endfor
2693      assert_equal('ab', chars)
2694
2695      # unpack with type
2696      var res = ''
2697      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
2698        res ..= n .. s
2699      endfor
2700      assert_equal('1a2b', res)
2701
2702      # unpack with one var
2703      var reslist = []
2704      for [x] in [['aaa'], ['bbb']]
2705        reslist->add(x)
2706      endfor
2707      assert_equal(['aaa', 'bbb'], reslist)
2708
2709      # loop over string
2710      res = ''
2711      for c in 'aéc̀d'
2712        res ..= c .. '-'
2713      endfor
2714      assert_equal('a-é-c̀-d-', res)
2715
2716      res = ''
2717      for c in ''
2718        res ..= c .. '-'
2719      endfor
2720      assert_equal('', res)
2721
2722      res = ''
2723      for c in test_null_string()
2724        res ..= c .. '-'
2725      endfor
2726      assert_equal('', res)
2727
2728      var foo: list<dict<any>> = [
2729              {a: 'Cat'}
2730            ]
2731      for dd in foo
2732        dd.counter = 12
2733      endfor
2734      assert_equal([{a: 'Cat', counter: 12}], foo)
2735
2736      reslist = []
2737      for _ in range(3)
2738        reslist->add('x')
2739      endfor
2740      assert_equal(['x', 'x', 'x'], reslist)
2741  END
2742  CheckDefAndScriptSuccess(lines)
2743enddef
2744
2745def Test_for_loop_with_closure()
2746  var lines =<< trim END
2747      var flist: list<func>
2748      for i in range(5)
2749        var inloop = i
2750        flist[i] = () => inloop
2751      endfor
2752      for i in range(5)
2753        assert_equal(4, flist[i]())
2754      endfor
2755  END
2756  CheckDefAndScriptSuccess(lines)
2757
2758  lines =<< trim END
2759      var flist: list<func>
2760      for i in range(5)
2761        var inloop = i
2762        flist[i] = () => {
2763              return inloop
2764            }
2765      endfor
2766      for i in range(5)
2767        assert_equal(4, flist[i]())
2768      endfor
2769  END
2770  CheckDefAndScriptSuccess(lines)
2771enddef
2772
2773def Test_for_loop_fails()
2774  CheckDefAndScriptFailure2(['for '], 'E1097:', 'E690:')
2775  CheckDefAndScriptFailure2(['for x'], 'E1097:', 'E690:')
2776  CheckDefAndScriptFailure2(['for x in'], 'E1097:', 'E15:')
2777  CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
2778  CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
2779  CheckDefAndScriptFailure2(['var x = 5', 'for x in range(5)', 'endfor'], 'E1017:', 'E1041:')
2780  CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
2781  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2782  delfunc! g:Func
2783  CheckDefFailure(['for i in xxx'], 'E1001:')
2784  CheckDefFailure(['endfor'], 'E588:')
2785  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2786
2787  # wrong type detected at compile time
2788  CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2789
2790  # wrong type detected at runtime
2791  g:adict = {a: 1}
2792  CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2793  unlet g:adict
2794
2795  var lines =<< trim END
2796      var d: list<dict<any>> = [{a: 0}]
2797      for e in d
2798        e = {a: 0, b: ''}
2799      endfor
2800  END
2801  CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
2802
2803  lines =<< trim END
2804      for nr: number in ['foo']
2805      endfor
2806  END
2807  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
2808
2809  lines =<< trim END
2810      for n : number in [1, 2]
2811        echo n
2812      endfor
2813  END
2814  CheckDefAndScriptFailure(lines, 'E1059:', 1)
2815
2816  lines =<< trim END
2817      var d: dict<number> = {a: 1, b: 2}
2818      for [k: job, v: job] in d->items()
2819        echo k v
2820      endfor
2821  END
2822  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
2823enddef
2824
2825def Test_for_loop_script_var()
2826  # cannot use s:var in a :def function
2827  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2828
2829  # can use s:var in Vim9 script, with or without s:
2830  var lines =<< trim END
2831    vim9script
2832    var total = 0
2833    for s:var in [1, 2, 3]
2834      total += s:var
2835    endfor
2836    assert_equal(6, total)
2837
2838    total = 0
2839    for var in [1, 2, 3]
2840      total += var
2841    endfor
2842    assert_equal(6, total)
2843  END
2844enddef
2845
2846def Test_for_loop_unpack()
2847  var lines =<< trim END
2848      var result = []
2849      for [v1, v2] in [[1, 2], [3, 4]]
2850        result->add(v1)
2851        result->add(v2)
2852      endfor
2853      assert_equal([1, 2, 3, 4], result)
2854
2855      result = []
2856      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2857        result->add(v1)
2858        result->add(v2)
2859        result->add(v3)
2860      endfor
2861      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2862
2863      result = []
2864      for [&ts, &sw] in [[1, 2], [3, 4]]
2865        result->add(&ts)
2866        result->add(&sw)
2867      endfor
2868      assert_equal([1, 2, 3, 4], result)
2869
2870      var slist: list<string>
2871      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2872        slist->add($LOOPVAR)
2873        slist->add(@r)
2874        slist->add(v:errmsg)
2875      endfor
2876      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2877
2878      slist = []
2879      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2880        slist->add(g:globalvar)
2881        slist->add(b:bufvar)
2882        slist->add(w:winvar)
2883        slist->add(t:tabvar)
2884      endfor
2885      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2886      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2887
2888      var res = []
2889      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
2890        res->add(n)
2891      endfor
2892      assert_equal([2, 5], res)
2893  END
2894  CheckDefAndScriptSuccess(lines)
2895
2896  lines =<< trim END
2897      for [v1, v2] in [[1, 2, 3], [3, 4]]
2898        echo v1 v2
2899      endfor
2900  END
2901  CheckDefExecFailure(lines, 'E710:', 1)
2902
2903  lines =<< trim END
2904      for [v1, v2] in [[1], [3, 4]]
2905        echo v1 v2
2906      endfor
2907  END
2908  CheckDefExecFailure(lines, 'E711:', 1)
2909
2910  lines =<< trim END
2911      for [v1, v1] in [[1, 2], [3, 4]]
2912        echo v1
2913      endfor
2914  END
2915  CheckDefExecFailure(lines, 'E1017:', 1)
2916enddef
2917
2918def Test_for_loop_with_try_continue()
2919  var lines =<< trim END
2920      var looped = 0
2921      var cleanup = 0
2922      for i in range(3)
2923        looped += 1
2924        try
2925          eval [][0]
2926        catch
2927          continue
2928        finally
2929          cleanup += 1
2930        endtry
2931      endfor
2932      assert_equal(3, looped)
2933      assert_equal(3, cleanup)
2934  END
2935  CheckDefAndScriptSuccess(lines)
2936enddef
2937
2938def Test_while_skipped_block()
2939  # test skipped blocks at outside of function
2940  var lines =<< trim END
2941    var result = []
2942    var n = 0
2943    if true
2944      n = 1
2945      while n < 3
2946        result += [n]
2947        n += 1
2948      endwhile
2949    else
2950      n = 3
2951      while n < 5
2952        result += [n]
2953        n += 1
2954      endwhile
2955    endif
2956    assert_equal([1, 2], result)
2957
2958    result = []
2959    if false
2960      n = 1
2961      while n < 3
2962        result += [n]
2963        n += 1
2964      endwhile
2965    else
2966      n = 3
2967      while n < 5
2968        result += [n]
2969        n += 1
2970      endwhile
2971    endif
2972    assert_equal([3, 4], result)
2973  END
2974  CheckDefAndScriptSuccess(lines)
2975
2976  # test skipped blocks at inside of function
2977  lines =<< trim END
2978    def DefTrue()
2979      var result = []
2980      var n = 0
2981      if true
2982        n = 1
2983        while n < 3
2984          result += [n]
2985          n += 1
2986        endwhile
2987      else
2988        n = 3
2989        while n < 5
2990          result += [n]
2991          n += 1
2992        endwhile
2993      endif
2994      assert_equal([1, 2], result)
2995    enddef
2996    DefTrue()
2997
2998    def DefFalse()
2999      var result = []
3000      var n = 0
3001      if false
3002        n = 1
3003        while n < 3
3004          result += [n]
3005          n += 1
3006        endwhile
3007      else
3008        n = 3
3009        while n < 5
3010          result += [n]
3011          n += 1
3012        endwhile
3013      endif
3014      assert_equal([3, 4], result)
3015    enddef
3016    DefFalse()
3017  END
3018  CheckDefAndScriptSuccess(lines)
3019enddef
3020
3021def Test_while_loop()
3022  var result = ''
3023  var cnt = 0
3024  while cnt < 555
3025    if cnt == 3
3026      break
3027    endif
3028    cnt += 1
3029    if cnt == 2
3030      continue
3031    endif
3032    result ..= cnt .. '_'
3033  endwhile
3034  assert_equal('1_3_', result)
3035
3036  var s = ''
3037  while s == 'x' # {comment}
3038  endwhile
3039enddef
3040
3041def Test_while_loop_fails()
3042  CheckDefFailure(['while xxx'], 'E1001:')
3043  CheckDefFailure(['endwhile'], 'E588:')
3044  CheckDefFailure(['continue'], 'E586:')
3045  CheckDefFailure(['if true', 'continue'], 'E586:')
3046  CheckDefFailure(['break'], 'E587:')
3047  CheckDefFailure(['if true', 'break'], 'E587:')
3048  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
3049
3050  var lines =<< trim END
3051      var s = ''
3052      while s = ''
3053      endwhile
3054  END
3055  CheckDefFailure(lines, 'E488:')
3056enddef
3057
3058def Test_interrupt_loop()
3059  var caught = false
3060  var x = 0
3061  try
3062    while 1
3063      x += 1
3064      if x == 100
3065        feedkeys("\<C-C>", 'Lt')
3066      endif
3067    endwhile
3068  catch
3069    caught = true
3070    assert_equal(100, x)
3071  endtry
3072  assert_true(caught, 'should have caught an exception')
3073  # consume the CTRL-C
3074  getchar(0)
3075enddef
3076
3077def Test_automatic_line_continuation()
3078  var mylist = [
3079      'one',
3080      'two',
3081      'three',
3082      ] # comment
3083  assert_equal(['one', 'two', 'three'], mylist)
3084
3085  var mydict = {
3086      ['one']: 1,
3087      ['two']: 2,
3088      ['three']:
3089          3,
3090      } # comment
3091  assert_equal({one: 1, two: 2, three: 3}, mydict)
3092  mydict = {
3093      one: 1,  # comment
3094      two:     # comment
3095           2,  # comment
3096      three: 3 # comment
3097      }
3098  assert_equal({one: 1, two: 2, three: 3}, mydict)
3099  mydict = {
3100      one: 1,
3101      two:
3102           2,
3103      three: 3
3104      }
3105  assert_equal({one: 1, two: 2, three: 3}, mydict)
3106
3107  assert_equal(
3108        ['one', 'two', 'three'],
3109        split('one two three')
3110        )
3111enddef
3112
3113def Test_vim9_comment()
3114  CheckScriptSuccess([
3115      'vim9script',
3116      '# something',
3117      '#something',
3118      '#{something',
3119      ])
3120
3121  split Xfile
3122  CheckScriptSuccess([
3123      'vim9script',
3124      'edit #something',
3125      ])
3126  CheckScriptSuccess([
3127      'vim9script',
3128      'edit #{something',
3129      ])
3130  close
3131
3132  CheckScriptFailure([
3133      'vim9script',
3134      ':# something',
3135      ], 'E488:')
3136  CheckScriptFailure([
3137      '# something',
3138      ], 'E488:')
3139  CheckScriptFailure([
3140      ':# something',
3141      ], 'E488:')
3142
3143  { # block start
3144  } # block end
3145  CheckDefFailure([
3146      '{# comment',
3147      ], 'E488:')
3148  CheckDefFailure([
3149      '{',
3150      '}# comment',
3151      ], 'E488:')
3152
3153  echo "yes" # comment
3154  CheckDefFailure([
3155      'echo "yes"# comment',
3156      ], 'E488:')
3157  CheckScriptSuccess([
3158      'vim9script',
3159      'echo "yes" # something',
3160      ])
3161  CheckScriptFailure([
3162      'vim9script',
3163      'echo "yes"# something',
3164      ], 'E121:')
3165  CheckScriptFailure([
3166      'vim9script',
3167      'echo# something',
3168      ], 'E1144:')
3169  CheckScriptFailure([
3170      'echo "yes" # something',
3171      ], 'E121:')
3172
3173  exe "echo" # comment
3174  CheckDefFailure([
3175      'exe "echo"# comment',
3176      ], 'E488:')
3177  CheckScriptSuccess([
3178      'vim9script',
3179      'exe "echo" # something',
3180      ])
3181  CheckScriptFailure([
3182      'vim9script',
3183      'exe "echo"# something',
3184      ], 'E121:')
3185  CheckScriptFailure([
3186      'vim9script',
3187      'exe# something',
3188      ], 'E1144:')
3189  CheckScriptFailure([
3190      'exe "echo" # something',
3191      ], 'E121:')
3192
3193  CheckDefFailure([
3194      'try# comment',
3195      '  echo "yes"',
3196      'catch',
3197      'endtry',
3198      ], 'E1144:')
3199  CheckScriptFailure([
3200      'vim9script',
3201      'try# comment',
3202      'echo "yes"',
3203      ], 'E1144:')
3204  CheckDefFailure([
3205      'try',
3206      '  throw#comment',
3207      'catch',
3208      'endtry',
3209      ], 'E1144:')
3210  CheckDefFailure([
3211      'try',
3212      '  throw "yes"#comment',
3213      'catch',
3214      'endtry',
3215      ], 'E488:')
3216  CheckDefFailure([
3217      'try',
3218      '  echo "yes"',
3219      'catch# comment',
3220      'endtry',
3221      ], 'E1144:')
3222  CheckScriptFailure([
3223      'vim9script',
3224      'try',
3225      '  echo "yes"',
3226      'catch# comment',
3227      'endtry',
3228      ], 'E1144:')
3229  CheckDefFailure([
3230      'try',
3231      '  echo "yes"',
3232      'catch /pat/# comment',
3233      'endtry',
3234      ], 'E488:')
3235  CheckDefFailure([
3236      'try',
3237      'echo "yes"',
3238      'catch',
3239      'endtry# comment',
3240      ], 'E1144:')
3241  CheckScriptFailure([
3242      'vim9script',
3243      'try',
3244      '  echo "yes"',
3245      'catch',
3246      'endtry# comment',
3247      ], 'E1144:')
3248
3249  CheckScriptSuccess([
3250      'vim9script',
3251      'hi # comment',
3252      ])
3253  CheckScriptFailure([
3254      'vim9script',
3255      'hi# comment',
3256      ], 'E1144:')
3257  CheckScriptSuccess([
3258      'vim9script',
3259      'hi Search # comment',
3260      ])
3261  CheckScriptFailure([
3262      'vim9script',
3263      'hi Search# comment',
3264      ], 'E416:')
3265  CheckScriptSuccess([
3266      'vim9script',
3267      'hi link This Search # comment',
3268      ])
3269  CheckScriptFailure([
3270      'vim9script',
3271      'hi link This That# comment',
3272      ], 'E413:')
3273  CheckScriptSuccess([
3274      'vim9script',
3275      'hi clear This # comment',
3276      'hi clear # comment',
3277      ])
3278  # not tested, because it doesn't give an error but a warning:
3279  # hi clear This# comment',
3280  CheckScriptFailure([
3281      'vim9script',
3282      'hi clear# comment',
3283      ], 'E416:')
3284
3285  CheckScriptSuccess([
3286      'vim9script',
3287      'hi Group term=bold',
3288      'match Group /todo/ # comment',
3289      ])
3290  CheckScriptFailure([
3291      'vim9script',
3292      'hi Group term=bold',
3293      'match Group /todo/# comment',
3294      ], 'E488:')
3295  CheckScriptSuccess([
3296      'vim9script',
3297      'match # comment',
3298      ])
3299  CheckScriptFailure([
3300      'vim9script',
3301      'match# comment',
3302      ], 'E1144:')
3303  CheckScriptSuccess([
3304      'vim9script',
3305      'match none # comment',
3306      ])
3307  CheckScriptFailure([
3308      'vim9script',
3309      'match none# comment',
3310      ], 'E475:')
3311
3312  CheckScriptSuccess([
3313      'vim9script',
3314      'menutrans clear # comment',
3315      ])
3316  CheckScriptFailure([
3317      'vim9script',
3318      'menutrans clear# comment text',
3319      ], 'E474:')
3320
3321  CheckScriptSuccess([
3322      'vim9script',
3323      'syntax clear # comment',
3324      ])
3325  CheckScriptFailure([
3326      'vim9script',
3327      'syntax clear# comment text',
3328      ], 'E28:')
3329  CheckScriptSuccess([
3330      'vim9script',
3331      'syntax keyword Word some',
3332      'syntax clear Word # comment',
3333      ])
3334  CheckScriptFailure([
3335      'vim9script',
3336      'syntax keyword Word some',
3337      'syntax clear Word# comment text',
3338      ], 'E28:')
3339
3340  CheckScriptSuccess([
3341      'vim9script',
3342      'syntax list # comment',
3343      ])
3344  CheckScriptFailure([
3345      'vim9script',
3346      'syntax list# comment text',
3347      ], 'E28:')
3348
3349  CheckScriptSuccess([
3350      'vim9script',
3351      'syntax match Word /pat/ oneline # comment',
3352      ])
3353  CheckScriptFailure([
3354      'vim9script',
3355      'syntax match Word /pat/ oneline# comment',
3356      ], 'E475:')
3357
3358  CheckScriptSuccess([
3359      'vim9script',
3360      'syntax keyword Word word # comm[ent',
3361      ])
3362  CheckScriptFailure([
3363      'vim9script',
3364      'syntax keyword Word word# comm[ent',
3365      ], 'E789:')
3366
3367  CheckScriptSuccess([
3368      'vim9script',
3369      'syntax match Word /pat/ # comment',
3370      ])
3371  CheckScriptFailure([
3372      'vim9script',
3373      'syntax match Word /pat/# comment',
3374      ], 'E402:')
3375
3376  CheckScriptSuccess([
3377      'vim9script',
3378      'syntax match Word /pat/ contains=Something # comment',
3379      ])
3380  CheckScriptFailure([
3381      'vim9script',
3382      'syntax match Word /pat/ contains=Something# comment',
3383      ], 'E475:')
3384  CheckScriptFailure([
3385      'vim9script',
3386      'syntax match Word /pat/ contains= # comment',
3387      ], 'E406:')
3388  CheckScriptFailure([
3389      'vim9script',
3390      'syntax match Word /pat/ contains=# comment',
3391      ], 'E475:')
3392
3393  CheckScriptSuccess([
3394      'vim9script',
3395      'syntax region Word start=/pat/ end=/pat/ # comment',
3396      ])
3397  CheckScriptFailure([
3398      'vim9script',
3399      'syntax region Word start=/pat/ end=/pat/# comment',
3400      ], 'E402:')
3401
3402  CheckScriptSuccess([
3403      'vim9script',
3404      'syntax sync # comment',
3405      ])
3406  CheckScriptFailure([
3407      'vim9script',
3408      'syntax sync# comment',
3409      ], 'E404:')
3410  CheckScriptSuccess([
3411      'vim9script',
3412      'syntax sync ccomment # comment',
3413      ])
3414  CheckScriptFailure([
3415      'vim9script',
3416      'syntax sync ccomment# comment',
3417      ], 'E404:')
3418
3419  CheckScriptSuccess([
3420      'vim9script',
3421      'syntax cluster Some contains=Word # comment',
3422      ])
3423  CheckScriptFailure([
3424      'vim9script',
3425      'syntax cluster Some contains=Word# comment',
3426      ], 'E475:')
3427
3428  CheckScriptSuccess([
3429      'vim9script',
3430      'command Echo echo # comment',
3431      'command Echo # comment',
3432      'delcommand Echo',
3433      ])
3434  CheckScriptFailure([
3435      'vim9script',
3436      'command Echo echo# comment',
3437      'Echo',
3438      ], 'E1144:')
3439  delcommand Echo
3440
3441  var curdir = getcwd()
3442  CheckScriptSuccess([
3443      'command Echo cd " comment',
3444      'Echo',
3445      'delcommand Echo',
3446      ])
3447  CheckScriptSuccess([
3448      'vim9script',
3449      'command Echo cd # comment',
3450      'Echo',
3451      'delcommand Echo',
3452      ])
3453  CheckScriptFailure([
3454      'vim9script',
3455      'command Echo cd " comment',
3456      'Echo',
3457      ], 'E344:')
3458  delcommand Echo
3459  chdir(curdir)
3460
3461  CheckScriptFailure([
3462      'vim9script',
3463      'command Echo# comment',
3464      ], 'E182:')
3465  CheckScriptFailure([
3466      'vim9script',
3467      'command Echo echo',
3468      'command Echo# comment',
3469      ], 'E182:')
3470  delcommand Echo
3471
3472  CheckScriptSuccess([
3473      'vim9script',
3474      'function # comment',
3475      ])
3476  CheckScriptFailure([
3477      'vim9script',
3478      'function " comment',
3479      ], 'E129:')
3480  CheckScriptFailure([
3481      'vim9script',
3482      'function# comment',
3483      ], 'E1144:')
3484  CheckScriptSuccess([
3485      'vim9script',
3486      'function CheckScriptSuccess # comment',
3487      ])
3488  CheckScriptFailure([
3489      'vim9script',
3490      'function CheckScriptSuccess# comment',
3491      ], 'E488:')
3492
3493  CheckScriptSuccess([
3494      'vim9script',
3495      'func g:DeleteMeA()',
3496      'endfunc',
3497      'delfunction g:DeleteMeA # comment',
3498      ])
3499  CheckScriptFailure([
3500      'vim9script',
3501      'func g:DeleteMeB()',
3502      'endfunc',
3503      'delfunction g:DeleteMeB# comment',
3504      ], 'E488:')
3505
3506  CheckScriptSuccess([
3507      'vim9script',
3508      'call execute("ls") # comment',
3509      ])
3510  CheckScriptFailure([
3511      'vim9script',
3512      'call execute("ls")# comment',
3513      ], 'E488:')
3514
3515  CheckScriptFailure([
3516      'def Test() " comment',
3517      'enddef',
3518      ], 'E488:')
3519  CheckScriptFailure([
3520      'vim9script',
3521      'def Test() " comment',
3522      'enddef',
3523      ], 'E488:')
3524
3525  CheckScriptSuccess([
3526      'func Test() " comment',
3527      'endfunc',
3528      'delfunc Test',
3529      ])
3530  CheckScriptSuccess([
3531      'vim9script',
3532      'func Test() " comment',
3533      'endfunc',
3534      ])
3535
3536  CheckScriptSuccess([
3537      'def Test() # comment',
3538      'enddef',
3539      ])
3540  CheckScriptFailure([
3541      'func Test() # comment',
3542      'endfunc',
3543      ], 'E488:')
3544
3545  var lines =<< trim END
3546      vim9script
3547      syn region Text
3548      \ start='foo'
3549      #\ comment
3550      \ end='bar'
3551      syn region Text start='foo'
3552      #\ comment
3553      \ end='bar'
3554  END
3555  CheckScriptSuccess(lines)
3556
3557  lines =<< trim END
3558      vim9script
3559      syn region Text
3560      \ start='foo'
3561      "\ comment
3562      \ end='bar'
3563  END
3564  CheckScriptFailure(lines, 'E399:')
3565enddef
3566
3567def Test_vim9_comment_gui()
3568  CheckCanRunGui
3569
3570  CheckScriptFailure([
3571      'vim9script',
3572      'gui#comment'
3573      ], 'E1144:')
3574  CheckScriptFailure([
3575      'vim9script',
3576      'gui -f#comment'
3577      ], 'E194:')
3578enddef
3579
3580def Test_vim9_comment_not_compiled()
3581  au TabEnter *.vim g:entered = 1
3582  au TabEnter *.x g:entered = 2
3583
3584  edit test.vim
3585  doautocmd TabEnter #comment
3586  assert_equal(1, g:entered)
3587
3588  doautocmd TabEnter f.x
3589  assert_equal(2, g:entered)
3590
3591  g:entered = 0
3592  doautocmd TabEnter f.x #comment
3593  assert_equal(2, g:entered)
3594
3595  assert_fails('doautocmd Syntax#comment', 'E216:')
3596
3597  au! TabEnter
3598  unlet g:entered
3599
3600  CheckScriptSuccess([
3601      'vim9script',
3602      'g:var = 123',
3603      'b:var = 456',
3604      'w:var = 777',
3605      't:var = 888',
3606      'unlet g:var w:var # something',
3607      ])
3608
3609  CheckScriptFailure([
3610      'vim9script',
3611      'let var = 123',
3612      ], 'E1126: Cannot use :let in Vim9 script')
3613
3614  CheckScriptFailure([
3615      'vim9script',
3616      'var g:var = 123',
3617      ], 'E1016: Cannot declare a global variable:')
3618
3619  CheckScriptFailure([
3620      'vim9script',
3621      'var b:var = 123',
3622      ], 'E1016: Cannot declare a buffer variable:')
3623
3624  CheckScriptFailure([
3625      'vim9script',
3626      'var w:var = 123',
3627      ], 'E1016: Cannot declare a window variable:')
3628
3629  CheckScriptFailure([
3630      'vim9script',
3631      'var t:var = 123',
3632      ], 'E1016: Cannot declare a tab variable:')
3633
3634  CheckScriptFailure([
3635      'vim9script',
3636      'var v:version = 123',
3637      ], 'E1016: Cannot declare a v: variable:')
3638
3639  CheckScriptFailure([
3640      'vim9script',
3641      'var $VARIABLE = "text"',
3642      ], 'E1016: Cannot declare an environment variable:')
3643
3644  CheckScriptFailure([
3645      'vim9script',
3646      'g:var = 123',
3647      'unlet g:var# comment1',
3648      ], 'E108:')
3649
3650  CheckScriptFailure([
3651      'let g:var = 123',
3652      'unlet g:var # something',
3653      ], 'E488:')
3654
3655  CheckScriptSuccess([
3656      'vim9script',
3657      'if 1 # comment2',
3658      '  echo "yes"',
3659      'elseif 2 #comment',
3660      '  echo "no"',
3661      'endif',
3662      ])
3663
3664  CheckScriptFailure([
3665      'vim9script',
3666      'if 1# comment3',
3667      '  echo "yes"',
3668      'endif',
3669      ], 'E488:')
3670
3671  CheckScriptFailure([
3672      'vim9script',
3673      'if 0 # comment4',
3674      '  echo "yes"',
3675      'elseif 2#comment',
3676      '  echo "no"',
3677      'endif',
3678      ], 'E488:')
3679
3680  CheckScriptSuccess([
3681      'vim9script',
3682      'var v = 1 # comment5',
3683      ])
3684
3685  CheckScriptFailure([
3686      'vim9script',
3687      'var v = 1# comment6',
3688      ], 'E488:')
3689
3690  CheckScriptSuccess([
3691      'vim9script',
3692      'new'
3693      'setline(1, ["# define pat", "last"])',
3694      ':$',
3695      'dsearch /pat/ #comment',
3696      'bwipe!',
3697      ])
3698
3699  CheckScriptFailure([
3700      'vim9script',
3701      'new'
3702      'setline(1, ["# define pat", "last"])',
3703      ':$',
3704      'dsearch /pat/#comment',
3705      'bwipe!',
3706      ], 'E488:')
3707
3708  CheckScriptFailure([
3709      'vim9script',
3710      'func! SomeFunc()',
3711      ], 'E477:')
3712enddef
3713
3714def Test_finish()
3715  var lines =<< trim END
3716    vim9script
3717    g:res = 'one'
3718    if v:false | finish | endif
3719    g:res = 'two'
3720    finish
3721    g:res = 'three'
3722  END
3723  writefile(lines, 'Xfinished')
3724  source Xfinished
3725  assert_equal('two', g:res)
3726
3727  unlet g:res
3728  delete('Xfinished')
3729enddef
3730
3731def Test_forward_declaration()
3732  var lines =<< trim END
3733    vim9script
3734    def GetValue(): string
3735      return theVal
3736    enddef
3737    var theVal = 'something'
3738    g:initVal = GetValue()
3739    theVal = 'else'
3740    g:laterVal = GetValue()
3741  END
3742  writefile(lines, 'Xforward')
3743  source Xforward
3744  assert_equal('something', g:initVal)
3745  assert_equal('else', g:laterVal)
3746
3747  unlet g:initVal
3748  unlet g:laterVal
3749  delete('Xforward')
3750enddef
3751
3752def Test_source_vim9_from_legacy()
3753  var vim9_lines =<< trim END
3754    vim9script
3755    var local = 'local'
3756    g:global = 'global'
3757    export var exported = 'exported'
3758    export def GetText(): string
3759       return 'text'
3760    enddef
3761  END
3762  writefile(vim9_lines, 'Xvim9_script.vim')
3763
3764  var legacy_lines =<< trim END
3765    source Xvim9_script.vim
3766
3767    call assert_false(exists('local'))
3768    call assert_false(exists('exported'))
3769    call assert_false(exists('s:exported'))
3770    call assert_equal('global', global)
3771    call assert_equal('global', g:global)
3772
3773    " imported variable becomes script-local
3774    import exported from './Xvim9_script.vim'
3775    call assert_equal('exported', s:exported)
3776    call assert_false(exists('exported'))
3777
3778    " imported function becomes script-local
3779    import GetText from './Xvim9_script.vim'
3780    call assert_equal('text', s:GetText())
3781    call assert_false(exists('*GetText'))
3782  END
3783  writefile(legacy_lines, 'Xlegacy_script.vim')
3784
3785  source Xlegacy_script.vim
3786  assert_equal('global', g:global)
3787  unlet g:global
3788
3789  delete('Xlegacy_script.vim')
3790  delete('Xvim9_script.vim')
3791enddef
3792
3793def Test_declare_script_in_func()
3794  var lines =<< trim END
3795      vim9script
3796      func Declare()
3797        let s:local = 123
3798      endfunc
3799      Declare()
3800      assert_equal(123, local)
3801
3802      var error: string
3803      try
3804        local = 'asdf'
3805      catch
3806        error = v:exception
3807      endtry
3808      assert_match('E1012: Type mismatch; expected number but got string', error)
3809
3810      lockvar local
3811      try
3812        local = 999
3813      catch
3814        error = v:exception
3815      endtry
3816      assert_match('E741: Value is locked: local', error)
3817  END
3818  CheckScriptSuccess(lines)
3819enddef
3820
3821
3822func Test_vim9script_not_global()
3823  " check that items defined in Vim9 script are script-local, not global
3824  let vim9lines =<< trim END
3825    vim9script
3826    var name = 'local'
3827    func TheFunc()
3828      echo 'local'
3829    endfunc
3830    def DefFunc()
3831      echo 'local'
3832    enddef
3833  END
3834  call writefile(vim9lines, 'Xvim9script.vim')
3835  source Xvim9script.vim
3836  try
3837    echo g:var
3838    assert_report('did not fail')
3839  catch /E121:/
3840    " caught
3841  endtry
3842  try
3843    call TheFunc()
3844    assert_report('did not fail')
3845  catch /E117:/
3846    " caught
3847  endtry
3848  try
3849    call DefFunc()
3850    assert_report('did not fail')
3851  catch /E117:/
3852    " caught
3853  endtry
3854
3855  call delete('Xvim9script.vim')
3856endfunc
3857
3858def Test_vim9_copen()
3859  # this was giving an error for setting w:quickfix_title
3860  copen
3861  quit
3862enddef
3863
3864" test using an auto-loaded function and variable
3865def Test_vim9_autoload()
3866  var lines =<< trim END
3867     vim9script
3868     def some#gettest(): string
3869       return 'test'
3870     enddef
3871     g:some#name = 'name'
3872     g:some#dict = {key: 'value'}
3873
3874     def some#varargs(a1: string, ...l: list<string>): string
3875       return a1 .. l[0] .. l[1]
3876     enddef
3877  END
3878
3879  mkdir('Xdir/autoload', 'p')
3880  writefile(lines, 'Xdir/autoload/some.vim')
3881  var save_rtp = &rtp
3882  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3883
3884  assert_equal('test', g:some#gettest())
3885  assert_equal('name', g:some#name)
3886  assert_equal('value', g:some#dict.key)
3887  g:some#other = 'other'
3888  assert_equal('other', g:some#other)
3889
3890  assert_equal('abc', some#varargs('a', 'b', 'c'))
3891
3892  # upper case script name works
3893  lines =<< trim END
3894     vim9script
3895     def Other#getOther(): string
3896       return 'other'
3897     enddef
3898  END
3899  writefile(lines, 'Xdir/autoload/Other.vim')
3900  assert_equal('other', g:Other#getOther())
3901
3902  delete('Xdir', 'rf')
3903  &rtp = save_rtp
3904enddef
3905
3906" test using a vim9script that is auto-loaded from an autocmd
3907def Test_vim9_aucmd_autoload()
3908  var lines =<< trim END
3909     vim9script
3910     def foo#test()
3911         echomsg getreg('"')
3912     enddef
3913  END
3914
3915  mkdir('Xdir/autoload', 'p')
3916  writefile(lines, 'Xdir/autoload/foo.vim')
3917  var save_rtp = &rtp
3918  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3919  augroup test
3920    autocmd TextYankPost * call foo#test()
3921  augroup END
3922
3923  normal Y
3924
3925  augroup test
3926    autocmd!
3927  augroup END
3928  delete('Xdir', 'rf')
3929  &rtp = save_rtp
3930enddef
3931
3932" This was causing a crash because suppress_errthrow wasn't reset.
3933def Test_vim9_autoload_error()
3934  var lines =<< trim END
3935      vim9script
3936      def crash#func()
3937          try
3938              for x in List()
3939              endfor
3940          catch
3941          endtry
3942          g:ok = true
3943      enddef
3944      fu List()
3945          invalid
3946      endfu
3947      try
3948          alsoinvalid
3949      catch /wontmatch/
3950      endtry
3951  END
3952  call mkdir('Xruntime/autoload', 'p')
3953  call writefile(lines, 'Xruntime/autoload/crash.vim')
3954
3955  # run in a separate Vim to avoid the side effects of assert_fails()
3956  lines =<< trim END
3957    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
3958    call crash#func()
3959    call writefile(['ok'], 'Xdidit')
3960    qall!
3961  END
3962  writefile(lines, 'Xscript')
3963  RunVim([], [], '-S Xscript')
3964  assert_equal(['ok'], readfile('Xdidit'))
3965
3966  delete('Xdidit')
3967  delete('Xscript')
3968  delete('Xruntime', 'rf')
3969
3970  lines =<< trim END
3971    vim9script
3972    var foo#bar = 'asdf'
3973  END
3974  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
3975enddef
3976
3977def Test_script_var_in_autocmd()
3978  # using a script variable from an autocommand, defined in a :def function in a
3979  # legacy Vim script, cannot check the variable type.
3980  var lines =<< trim END
3981    let s:counter = 1
3982    def s:Func()
3983      au! CursorHold
3984      au CursorHold * s:counter += 1
3985    enddef
3986    call s:Func()
3987    doau CursorHold
3988    call assert_equal(2, s:counter)
3989    au! CursorHold
3990  END
3991  CheckScriptSuccess(lines)
3992enddef
3993
3994def Test_error_in_autoload_script()
3995  var save_rtp = &rtp
3996  var dir = getcwd() .. '/Xruntime'
3997  &rtp = dir
3998  mkdir(dir .. '/autoload', 'p')
3999
4000  var lines =<< trim END
4001      vim9script noclear
4002      def script#autoloaded()
4003      enddef
4004      def Broken()
4005        var x: any = ''
4006        eval x != 0
4007      enddef
4008      Broken()
4009  END
4010  writefile(lines, dir .. '/autoload/script.vim')
4011
4012  lines =<< trim END
4013      vim9script
4014      def CallAutoloaded()
4015        script#autoloaded()
4016      enddef
4017
4018      function Legacy()
4019        try
4020          call s:CallAutoloaded()
4021        catch
4022          call assert_match('E1030: Using a String as a Number', v:exception)
4023        endtry
4024      endfunction
4025
4026      Legacy()
4027  END
4028  CheckScriptSuccess(lines)
4029
4030  &rtp = save_rtp
4031  delete(dir, 'rf')
4032enddef
4033
4034def Test_cmdline_win()
4035  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
4036  # the command line window.
4037  mkdir('rtp/syntax', 'p')
4038  var export_lines =<< trim END
4039    vim9script
4040    export var That = 'yes'
4041  END
4042  writefile(export_lines, 'rtp/syntax/Xexport.vim')
4043  var import_lines =<< trim END
4044    vim9script
4045    import That from './Xexport.vim'
4046  END
4047  writefile(import_lines, 'rtp/syntax/vim.vim')
4048  var save_rtp = &rtp
4049  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
4050  syntax on
4051  augroup CmdWin
4052    autocmd CmdwinEnter * g:got_there = 'yes'
4053  augroup END
4054  # this will open and also close the cmdline window
4055  feedkeys('q:', 'xt')
4056  assert_equal('yes', g:got_there)
4057
4058  augroup CmdWin
4059    au!
4060  augroup END
4061  &rtp = save_rtp
4062  delete('rtp', 'rf')
4063enddef
4064
4065def Test_invalid_sid()
4066  assert_fails('func <SNR>1234_func', 'E123:')
4067
4068  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
4069    assert_equal([], readfile('Xdidit'))
4070  endif
4071  delete('Xdidit')
4072enddef
4073
4074def Test_restoring_cpo()
4075  writefile(['vim9script', 'set nocp'], 'Xsourced')
4076  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
4077  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
4078    assert_equal(['done'], readfile('Xdone'))
4079  endif
4080  delete('Xsourced')
4081  delete('Xclose')
4082  delete('Xdone')
4083
4084  writefile(['vim9script'], 'XanotherScript')
4085  set cpo=aABceFsMny>
4086  edit XanotherScript
4087  so %
4088  assert_equal('aABceFsMny>', &cpo)
4089  :1del
4090  w
4091  so %
4092  assert_equal('aABceFsMny>', &cpo)
4093
4094  delete('XanotherScript')
4095  set cpo&vim
4096enddef
4097
4098" Use :function so we can use Check commands
4099func Test_no_redraw_when_restoring_cpo()
4100  CheckScreendump
4101  CheckFeature timers
4102
4103  let lines =<< trim END
4104    vim9script
4105    def script#func()
4106    enddef
4107  END
4108  call mkdir('Xdir/autoload', 'p')
4109  call writefile(lines, 'Xdir/autoload/script.vim')
4110
4111  let lines =<< trim END
4112      vim9script
4113      set cpo+=M
4114      exe 'set rtp^=' .. getcwd() .. '/Xdir'
4115      au CmdlineEnter : ++once timer_start(0, (_) => script#func())
4116      setline(1, 'some text')
4117  END
4118  call writefile(lines, 'XTest_redraw_cpo')
4119  let buf = RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
4120  call term_sendkeys(buf, "V:")
4121  call VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
4122
4123  " clean up
4124  call term_sendkeys(buf, "\<Esc>u")
4125  call StopVimInTerminal(buf)
4126  call delete('XTest_redraw_cpo')
4127  call delete('Xdir', 'rf')
4128endfunc
4129
4130
4131def Test_unset_any_variable()
4132  var lines =<< trim END
4133    var name: any
4134    assert_equal(0, name)
4135  END
4136  CheckDefAndScriptSuccess(lines)
4137enddef
4138
4139func Test_define_func_at_command_line()
4140  CheckRunVimInTerminal
4141
4142  " call indirectly to avoid compilation error for missing functions
4143  call Run_Test_define_func_at_command_line()
4144endfunc
4145
4146def Run_Test_define_func_at_command_line()
4147  # run in a separate Vim instance to avoid the script context
4148  var lines =<< trim END
4149    func CheckAndQuit()
4150      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
4151      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
4152    endfunc
4153  END
4154  writefile([''], 'Xdidcmd')
4155  writefile(lines, 'XcallFunc')
4156  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
4157  # define Afunc() on the command line
4158  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
4159  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
4160  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
4161
4162  call StopVimInTerminal(buf)
4163  delete('XcallFunc')
4164  delete('Xdidcmd')
4165enddef
4166
4167def Test_script_var_scope()
4168  var lines =<< trim END
4169      vim9script
4170      if true
4171        if true
4172          var one = 'one'
4173          echo one
4174        endif
4175        echo one
4176      endif
4177  END
4178  CheckScriptFailure(lines, 'E121:', 7)
4179
4180  lines =<< trim END
4181      vim9script
4182      if true
4183        if false
4184          var one = 'one'
4185          echo one
4186        else
4187          var one = 'one'
4188          echo one
4189        endif
4190        echo one
4191      endif
4192  END
4193  CheckScriptFailure(lines, 'E121:', 10)
4194
4195  lines =<< trim END
4196      vim9script
4197      while true
4198        var one = 'one'
4199        echo one
4200        break
4201      endwhile
4202      echo one
4203  END
4204  CheckScriptFailure(lines, 'E121:', 7)
4205
4206  lines =<< trim END
4207      vim9script
4208      for i in range(1)
4209        var one = 'one'
4210        echo one
4211      endfor
4212      echo one
4213  END
4214  CheckScriptFailure(lines, 'E121:', 6)
4215
4216  lines =<< trim END
4217      vim9script
4218      {
4219        var one = 'one'
4220        assert_equal('one', one)
4221      }
4222      assert_false(exists('one'))
4223      assert_false(exists('s:one'))
4224  END
4225  CheckScriptSuccess(lines)
4226
4227  lines =<< trim END
4228      vim9script
4229      {
4230        var one = 'one'
4231        echo one
4232      }
4233      echo one
4234  END
4235  CheckScriptFailure(lines, 'E121:', 6)
4236enddef
4237
4238def Test_catch_exception_in_callback()
4239  var lines =<< trim END
4240    vim9script
4241    def Callback(...l: list<any>)
4242      try
4243        var x: string
4244        var y: string
4245        # this error should be caught with CHECKLEN
4246        [x, y] = ['']
4247      catch
4248        g:caught = 'yes'
4249      endtry
4250    enddef
4251    popup_menu('popup', {callback: Callback})
4252    feedkeys("\r", 'xt')
4253  END
4254  CheckScriptSuccess(lines)
4255
4256  unlet g:caught
4257enddef
4258
4259def Test_no_unknown_error_after_error()
4260  if !has('unix') || !has('job')
4261    throw 'Skipped: not unix of missing +job feature'
4262  endif
4263  var lines =<< trim END
4264      vim9script
4265      var source: list<number>
4266      def Out_cb(...l: list<any>)
4267          eval [][0]
4268      enddef
4269      def Exit_cb(...l: list<any>)
4270          sleep 1m
4271          source += l
4272      enddef
4273      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
4274      while job_status(myjob) == 'run'
4275        sleep 10m
4276      endwhile
4277      # wait for Exit_cb() to be called
4278      sleep 200m
4279  END
4280  writefile(lines, 'Xdef')
4281  assert_fails('so Xdef', ['E684:', 'E1012:'])
4282  delete('Xdef')
4283enddef
4284
4285def InvokeNormal()
4286  exe "norm! :m+1\r"
4287enddef
4288
4289def Test_invoke_normal_in_visual_mode()
4290  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
4291  new
4292  setline(1, ['aaa', 'bbb'])
4293  feedkeys("V\<F3>", 'xt')
4294  assert_equal(['bbb', 'aaa'], getline(1, 2))
4295  xunmap <F3>
4296enddef
4297
4298def Test_white_space_after_command()
4299  var lines =<< trim END
4300    exit_cb: Func})
4301  END
4302  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4303
4304  lines =<< trim END
4305    e#
4306  END
4307  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4308enddef
4309
4310def Test_script_var_gone_when_sourced_twice()
4311  var lines =<< trim END
4312      vim9script
4313      if exists('g:guard')
4314        finish
4315      endif
4316      g:guard = 1
4317      var name = 'thename'
4318      def g:GetName(): string
4319        return name
4320      enddef
4321      def g:SetName(arg: string)
4322        name = arg
4323      enddef
4324  END
4325  writefile(lines, 'XscriptTwice.vim')
4326  so XscriptTwice.vim
4327  assert_equal('thename', g:GetName())
4328  g:SetName('newname')
4329  assert_equal('newname', g:GetName())
4330  so XscriptTwice.vim
4331  assert_fails('call g:GetName()', 'E1149:')
4332  assert_fails('call g:SetName("x")', 'E1149:')
4333
4334  delfunc g:GetName
4335  delfunc g:SetName
4336  delete('XscriptTwice.vim')
4337  unlet g:guard
4338enddef
4339
4340def Test_import_gone_when_sourced_twice()
4341  var exportlines =<< trim END
4342      vim9script
4343      if exists('g:guard')
4344        finish
4345      endif
4346      g:guard = 1
4347      export var name = 'someName'
4348  END
4349  writefile(exportlines, 'XexportScript.vim')
4350
4351  var lines =<< trim END
4352      vim9script
4353      import name from './XexportScript.vim'
4354      def g:GetName(): string
4355        return name
4356      enddef
4357  END
4358  writefile(lines, 'XscriptImport.vim')
4359  so XscriptImport.vim
4360  assert_equal('someName', g:GetName())
4361
4362  so XexportScript.vim
4363  assert_fails('call g:GetName()', 'E1149:')
4364
4365  delfunc g:GetName
4366  delete('XexportScript.vim')
4367  delete('XscriptImport.vim')
4368  unlet g:guard
4369enddef
4370
4371def Test_unsupported_commands()
4372  var lines =<< trim END
4373      ka
4374  END
4375  CheckDefFailure(lines, 'E476:')
4376  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4377
4378  lines =<< trim END
4379      :1ka
4380  END
4381  CheckDefFailure(lines, 'E476:')
4382  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4383
4384  lines =<< trim END
4385    t
4386  END
4387  CheckDefFailure(lines, 'E1100:')
4388  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4389
4390  lines =<< trim END
4391    x
4392  END
4393  CheckDefFailure(lines, 'E1100:')
4394  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4395
4396  lines =<< trim END
4397    xit
4398  END
4399  CheckDefFailure(lines, 'E1100:')
4400  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4401enddef
4402
4403def Test_mapping_line_number()
4404  var lines =<< trim END
4405      vim9script
4406      def g:FuncA()
4407          # Some comment
4408          FuncB(0)
4409      enddef
4410          # Some comment
4411      def FuncB(
4412          # Some comment
4413          n: number
4414      )
4415          exe 'nno '
4416              # Some comment
4417              .. '<F3> a'
4418              .. 'b'
4419              .. 'c'
4420      enddef
4421  END
4422  CheckScriptSuccess(lines)
4423  var res = execute('verbose nmap <F3>')
4424  assert_match('No mapping found', res)
4425
4426  g:FuncA()
4427  res = execute('verbose nmap <F3>')
4428  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
4429
4430  nunmap <F3>
4431  delfunc g:FuncA
4432enddef
4433
4434def Test_option_set()
4435  # legacy script allows for white space
4436  var lines =<< trim END
4437      set foldlevel  =11
4438      call assert_equal(11, &foldlevel)
4439  END
4440  CheckScriptSuccess(lines)
4441
4442  set foldlevel
4443  set foldlevel=12
4444  assert_equal(12, &foldlevel)
4445  set foldlevel+=2
4446  assert_equal(14, &foldlevel)
4447  set foldlevel-=3
4448  assert_equal(11, &foldlevel)
4449
4450  lines =<< trim END
4451      set foldlevel =1
4452  END
4453  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
4454
4455  lines =<< trim END
4456      set foldlevel +=1
4457  END
4458  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
4459
4460  lines =<< trim END
4461      set foldlevel ^=1
4462  END
4463  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
4464
4465  lines =<< trim END
4466      set foldlevel -=1
4467  END
4468  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
4469
4470  set foldlevel&
4471enddef
4472
4473def Test_option_modifier()
4474  # legacy script allows for white space
4475  var lines =<< trim END
4476      set hlsearch &  hlsearch  !
4477      call assert_equal(1, &hlsearch)
4478  END
4479  CheckScriptSuccess(lines)
4480
4481  set hlsearch
4482  set hlsearch!
4483  assert_equal(false, &hlsearch)
4484
4485  set hlsearch
4486  set hlsearch&
4487  assert_equal(false, &hlsearch)
4488
4489  lines =<< trim END
4490      set hlsearch &
4491  END
4492  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
4493
4494  lines =<< trim END
4495      set hlsearch   !
4496  END
4497  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
4498
4499  set hlsearch&
4500enddef
4501
4502" This must be called last, it may cause following :def functions to fail
4503def Test_xxx_echoerr_line_number()
4504  var lines =<< trim END
4505      echoerr 'some'
4506         .. ' error'
4507         .. ' continued'
4508  END
4509  CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
4510enddef
4511
4512def ProfiledWithLambda()
4513  var n = 3
4514  echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
4515enddef
4516
4517def ProfiledNested()
4518  var x = 0
4519  def Nested(): any
4520      return x
4521  enddef
4522  Nested()
4523enddef
4524
4525def ProfiledNestedProfiled()
4526  var x = 0
4527  def Nested(): any
4528      return x
4529  enddef
4530  Nested()
4531enddef
4532
4533" Execute this near the end, profiling doesn't stop until Vim exists.
4534" This only tests that it works, not the profiling output.
4535def Test_xx_profile_with_lambda()
4536  CheckFeature profile
4537
4538  profile start Xprofile.log
4539  profile func ProfiledWithLambda
4540  ProfiledWithLambda()
4541
4542  profile func ProfiledNested
4543  ProfiledNested()
4544
4545  # Also profile the nested function.  Use a different function, although the
4546  # contents is the same, to make sure it was not already compiled.
4547  profile func *
4548  ProfiledNestedProfiled()
4549
4550  profdel func *
4551  profile pause
4552enddef
4553
4554" Keep this last, it messes up highlighting.
4555def Test_substitute_cmd()
4556  new
4557  setline(1, 'something')
4558  :substitute(some(other(
4559  assert_equal('otherthing', getline(1))
4560  bwipe!
4561
4562  # also when the context is Vim9 script
4563  var lines =<< trim END
4564    vim9script
4565    new
4566    setline(1, 'something')
4567    :substitute(some(other(
4568    assert_equal('otherthing', getline(1))
4569    bwipe!
4570  END
4571  writefile(lines, 'Xvim9lines')
4572  source Xvim9lines
4573
4574  delete('Xvim9lines')
4575enddef
4576
4577" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
4578