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