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