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