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