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