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