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