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