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