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