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
2375enddef
2376
2377def Test_if_const_expr_fails()
2378  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
2379  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
2380  CheckDefFailure(["if has('aaa'"], 'E110:')
2381  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
2382enddef
2383
2384def RunNested(i: number): number
2385  var x: number = 0
2386  if i % 2
2387    if 1
2388      # comment
2389    else
2390      # comment
2391    endif
2392    x += 1
2393  else
2394    x += 1000
2395  endif
2396  return x
2397enddef
2398
2399def Test_nested_if()
2400  assert_equal(1, RunNested(1))
2401  assert_equal(1000, RunNested(2))
2402enddef
2403
2404def Test_execute_cmd()
2405  # missing argument is ignored
2406  execute
2407  execute # comment
2408
2409  new
2410  setline(1, 'default')
2411  execute 'setline(1, "execute-string")'
2412  assert_equal('execute-string', getline(1))
2413
2414  execute "setline(1, 'execute-string')"
2415  assert_equal('execute-string', getline(1))
2416
2417  var cmd1 = 'setline(1,'
2418  var cmd2 = '"execute-var")'
2419  execute cmd1 cmd2 # comment
2420  assert_equal('execute-var', getline(1))
2421
2422  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
2423  assert_equal('execute-var-string', getline(1))
2424
2425  var cmd_first = 'call '
2426  var cmd_last = 'setline(1, "execute-var-var")'
2427  execute cmd_first .. cmd_last
2428  assert_equal('execute-var-var', getline(1))
2429  bwipe!
2430
2431  var n = true
2432  execute 'echomsg' (n ? '"true"' : '"no"')
2433  assert_match('^true$', Screenline(&lines))
2434
2435  echomsg [1, 2, 3] {a: 1, b: 2}
2436  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
2437
2438  CheckDefFailure(['execute xxx'], 'E1001:', 1)
2439  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
2440  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
2441enddef
2442
2443def Test_execute_cmd_vimscript()
2444  # only checks line continuation
2445  var lines =<< trim END
2446      vim9script
2447      execute 'g:someVar'
2448                .. ' = ' ..
2449                   '28'
2450      assert_equal(28, g:someVar)
2451      unlet g:someVar
2452  END
2453  CheckScriptSuccess(lines)
2454enddef
2455
2456def Test_echo_cmd()
2457  echo 'some' # comment
2458  echon 'thing'
2459  assert_match('^something$', Screenline(&lines))
2460
2461  echo "some" # comment
2462  echon "thing"
2463  assert_match('^something$', Screenline(&lines))
2464
2465  var str1 = 'some'
2466  var str2 = 'more'
2467  echo str1 str2
2468  assert_match('^some more$', Screenline(&lines))
2469
2470  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
2471enddef
2472
2473def Test_echomsg_cmd()
2474  echomsg 'some' 'more' # comment
2475  assert_match('^some more$', Screenline(&lines))
2476  echo 'clear'
2477  :1messages
2478  assert_match('^some more$', Screenline(&lines))
2479
2480  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
2481enddef
2482
2483def Test_echomsg_cmd_vimscript()
2484  # only checks line continuation
2485  var lines =<< trim END
2486      vim9script
2487      echomsg 'here'
2488                .. ' is ' ..
2489                   'a message'
2490      assert_match('^here is a message$', Screenline(&lines))
2491  END
2492  CheckScriptSuccess(lines)
2493enddef
2494
2495def Test_echoerr_cmd()
2496  var local = 'local'
2497  try
2498    echoerr 'something' local 'wrong' # comment
2499  catch
2500    assert_match('something local wrong', v:exception)
2501  endtry
2502enddef
2503
2504def Test_echoerr_cmd_vimscript()
2505  # only checks line continuation
2506  var lines =<< trim END
2507      vim9script
2508      try
2509        echoerr 'this'
2510                .. ' is ' ..
2511                   'wrong'
2512      catch
2513        assert_match('this is wrong', v:exception)
2514      endtry
2515  END
2516  CheckScriptSuccess(lines)
2517enddef
2518
2519def Test_echoconsole_cmd()
2520  var local = 'local'
2521  echoconsole 'something' local # comment
2522  # output goes anywhere
2523enddef
2524
2525def Test_for_outside_of_function()
2526  var lines =<< trim END
2527    vim9script
2528    new
2529    for var in range(0, 3)
2530      append(line('$'), var)
2531    endfor
2532    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
2533    bwipe!
2534
2535    var result = ''
2536    for i in [1, 2, 3]
2537      var loop = ' loop ' .. i
2538      result ..= loop
2539    endfor
2540    assert_equal(' loop 1 loop 2 loop 3', result)
2541  END
2542  writefile(lines, 'Xvim9for.vim')
2543  source Xvim9for.vim
2544  delete('Xvim9for.vim')
2545enddef
2546
2547def Test_for_loop()
2548  var lines =<< trim END
2549      var result = ''
2550      for cnt in range(7)
2551        if cnt == 4
2552          break
2553        endif
2554        if cnt == 2
2555          continue
2556        endif
2557        result ..= cnt .. '_'
2558      endfor
2559      assert_equal('0_1_3_', result)
2560
2561      var concat = ''
2562      for str in eval('["one", "two"]')
2563        concat ..= str
2564      endfor
2565      assert_equal('onetwo', concat)
2566
2567      var total = 0
2568      for nr in
2569          [1, 2, 3]
2570        total += nr
2571      endfor
2572      assert_equal(6, total)
2573
2574      total = 0
2575      for nr
2576        in [1, 2, 3]
2577        total += nr
2578      endfor
2579      assert_equal(6, total)
2580
2581      total = 0
2582      for nr
2583        in
2584        [1, 2, 3]
2585        total += nr
2586      endfor
2587      assert_equal(6, total)
2588
2589      # with type
2590      total = 0
2591      for n: number in [1, 2, 3]
2592        total += n
2593      endfor
2594      assert_equal(6, total)
2595
2596      var chars = ''
2597      for s: string in 'foobar'
2598        chars ..= s
2599      endfor
2600      assert_equal('foobar', chars)
2601
2602      chars = ''
2603      for x: string in {a: 'a', b: 'b'}->values()
2604        chars ..= x
2605      endfor
2606      assert_equal('ab', chars)
2607
2608      # unpack with type
2609      var res = ''
2610      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
2611        res ..= n .. s
2612      endfor
2613      assert_equal('1a2b', res)
2614
2615      # unpack with one var
2616      var reslist = []
2617      for [x] in [['aaa'], ['bbb']]
2618        reslist->add(x)
2619      endfor
2620      assert_equal(['aaa', 'bbb'], reslist)
2621
2622      # loop over string
2623      res = ''
2624      for c in 'aéc̀d'
2625        res ..= c .. '-'
2626      endfor
2627      assert_equal('a-é-c̀-d-', res)
2628
2629      res = ''
2630      for c in ''
2631        res ..= c .. '-'
2632      endfor
2633      assert_equal('', res)
2634
2635      res = ''
2636      for c in test_null_string()
2637        res ..= c .. '-'
2638      endfor
2639      assert_equal('', res)
2640
2641      var foo: list<dict<any>> = [
2642              {a: 'Cat'}
2643            ]
2644      for dd in foo
2645        dd.counter = 12
2646      endfor
2647      assert_equal([{a: 'Cat', counter: 12}], foo)
2648
2649      reslist = []
2650      for _ in range(3)
2651        reslist->add('x')
2652      endfor
2653      assert_equal(['x', 'x', 'x'], reslist)
2654  END
2655  CheckDefAndScriptSuccess(lines)
2656enddef
2657
2658def Test_for_loop_with_closure()
2659  var lines =<< trim END
2660      var flist: list<func>
2661      for i in range(5)
2662        var inloop = i
2663        flist[i] = () => inloop
2664      endfor
2665      for i in range(5)
2666        assert_equal(4, flist[i]())
2667      endfor
2668  END
2669  CheckDefAndScriptSuccess(lines)
2670
2671  lines =<< trim END
2672      var flist: list<func>
2673      for i in range(5)
2674        var inloop = i
2675        flist[i] = () => {
2676              return inloop
2677            }
2678      endfor
2679      for i in range(5)
2680        assert_equal(4, flist[i]())
2681      endfor
2682  END
2683  CheckDefAndScriptSuccess(lines)
2684enddef
2685
2686def Test_for_loop_fails()
2687  CheckDefAndScriptFailure2(['for '], 'E1097:', 'E690:')
2688  CheckDefAndScriptFailure2(['for x'], 'E1097:', 'E690:')
2689  CheckDefAndScriptFailure2(['for x in'], 'E1097:', 'E15:')
2690  CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
2691  CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
2692  CheckDefAndScriptFailure2(['var x = 5', 'for x in range(5)', 'endfor'], 'E1017:', 'E1041:')
2693  CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
2694  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2695  delfunc! g:Func
2696  CheckDefFailure(['for i in xxx'], 'E1001:')
2697  CheckDefFailure(['endfor'], 'E588:')
2698  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2699
2700  # wrong type detected at compile time
2701  CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2702
2703  # wrong type detected at runtime
2704  g:adict = {a: 1}
2705  CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2706  unlet g:adict
2707
2708  var lines =<< trim END
2709      var d: list<dict<any>> = [{a: 0}]
2710      for e in d
2711        e = {a: 0, b: ''}
2712      endfor
2713  END
2714  CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
2715
2716  lines =<< trim END
2717      for nr: number in ['foo']
2718      endfor
2719  END
2720  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
2721
2722  lines =<< trim END
2723      for n : number in [1, 2]
2724        echo n
2725      endfor
2726  END
2727  CheckDefAndScriptFailure(lines, 'E1059:', 1)
2728
2729  lines =<< trim END
2730      var d: dict<number> = {a: 1, b: 2}
2731      for [k: job, v: job] in d->items()
2732        echo k v
2733      endfor
2734  END
2735  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
2736enddef
2737
2738def Test_for_loop_script_var()
2739  # cannot use s:var in a :def function
2740  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2741
2742  # can use s:var in Vim9 script, with or without s:
2743  var lines =<< trim END
2744    vim9script
2745    var total = 0
2746    for s:var in [1, 2, 3]
2747      total += s:var
2748    endfor
2749    assert_equal(6, total)
2750
2751    total = 0
2752    for var in [1, 2, 3]
2753      total += var
2754    endfor
2755    assert_equal(6, total)
2756  END
2757enddef
2758
2759def Test_for_loop_unpack()
2760  var lines =<< trim END
2761      var result = []
2762      for [v1, v2] in [[1, 2], [3, 4]]
2763        result->add(v1)
2764        result->add(v2)
2765      endfor
2766      assert_equal([1, 2, 3, 4], result)
2767
2768      result = []
2769      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2770        result->add(v1)
2771        result->add(v2)
2772        result->add(v3)
2773      endfor
2774      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2775
2776      result = []
2777      for [&ts, &sw] in [[1, 2], [3, 4]]
2778        result->add(&ts)
2779        result->add(&sw)
2780      endfor
2781      assert_equal([1, 2, 3, 4], result)
2782
2783      var slist: list<string>
2784      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2785        slist->add($LOOPVAR)
2786        slist->add(@r)
2787        slist->add(v:errmsg)
2788      endfor
2789      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2790
2791      slist = []
2792      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2793        slist->add(g:globalvar)
2794        slist->add(b:bufvar)
2795        slist->add(w:winvar)
2796        slist->add(t:tabvar)
2797      endfor
2798      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2799      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2800
2801      var res = []
2802      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
2803        res->add(n)
2804      endfor
2805      assert_equal([2, 5], res)
2806  END
2807  CheckDefAndScriptSuccess(lines)
2808
2809  lines =<< trim END
2810      for [v1, v2] in [[1, 2, 3], [3, 4]]
2811        echo v1 v2
2812      endfor
2813  END
2814  CheckDefExecFailure(lines, 'E710:', 1)
2815
2816  lines =<< trim END
2817      for [v1, v2] in [[1], [3, 4]]
2818        echo v1 v2
2819      endfor
2820  END
2821  CheckDefExecFailure(lines, 'E711:', 1)
2822
2823  lines =<< trim END
2824      for [v1, v1] in [[1, 2], [3, 4]]
2825        echo v1
2826      endfor
2827  END
2828  CheckDefExecFailure(lines, 'E1017:', 1)
2829enddef
2830
2831def Test_for_loop_with_try_continue()
2832  var lines =<< trim END
2833      var looped = 0
2834      var cleanup = 0
2835      for i in range(3)
2836        looped += 1
2837        try
2838          eval [][0]
2839        catch
2840          continue
2841        finally
2842          cleanup += 1
2843        endtry
2844      endfor
2845      assert_equal(3, looped)
2846      assert_equal(3, cleanup)
2847  END
2848  CheckDefAndScriptSuccess(lines)
2849enddef
2850
2851def Test_while_loop()
2852  var result = ''
2853  var cnt = 0
2854  while cnt < 555
2855    if cnt == 3
2856      break
2857    endif
2858    cnt += 1
2859    if cnt == 2
2860      continue
2861    endif
2862    result ..= cnt .. '_'
2863  endwhile
2864  assert_equal('1_3_', result)
2865
2866  var s = ''
2867  while s == 'x' # {comment}
2868  endwhile
2869enddef
2870
2871def Test_while_loop_fails()
2872  CheckDefFailure(['while xxx'], 'E1001:')
2873  CheckDefFailure(['endwhile'], 'E588:')
2874  CheckDefFailure(['continue'], 'E586:')
2875  CheckDefFailure(['if true', 'continue'], 'E586:')
2876  CheckDefFailure(['break'], 'E587:')
2877  CheckDefFailure(['if true', 'break'], 'E587:')
2878  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
2879
2880  var lines =<< trim END
2881      var s = ''
2882      while s = ''
2883      endwhile
2884  END
2885  CheckDefFailure(lines, 'E488:')
2886enddef
2887
2888def Test_interrupt_loop()
2889  var caught = false
2890  var x = 0
2891  try
2892    while 1
2893      x += 1
2894      if x == 100
2895        feedkeys("\<C-C>", 'Lt')
2896      endif
2897    endwhile
2898  catch
2899    caught = true
2900    assert_equal(100, x)
2901  endtry
2902  assert_true(caught, 'should have caught an exception')
2903  # consume the CTRL-C
2904  getchar(0)
2905enddef
2906
2907def Test_automatic_line_continuation()
2908  var mylist = [
2909      'one',
2910      'two',
2911      'three',
2912      ] # comment
2913  assert_equal(['one', 'two', 'three'], mylist)
2914
2915  var mydict = {
2916      ['one']: 1,
2917      ['two']: 2,
2918      ['three']:
2919          3,
2920      } # comment
2921  assert_equal({one: 1, two: 2, three: 3}, mydict)
2922  mydict = {
2923      one: 1,  # comment
2924      two:     # comment
2925           2,  # comment
2926      three: 3 # comment
2927      }
2928  assert_equal({one: 1, two: 2, three: 3}, mydict)
2929  mydict = {
2930      one: 1,
2931      two:
2932           2,
2933      three: 3
2934      }
2935  assert_equal({one: 1, two: 2, three: 3}, mydict)
2936
2937  assert_equal(
2938        ['one', 'two', 'three'],
2939        split('one two three')
2940        )
2941enddef
2942
2943def Test_vim9_comment()
2944  CheckScriptSuccess([
2945      'vim9script',
2946      '# something',
2947      '#something',
2948      '#{something',
2949      ])
2950
2951  split Xfile
2952  CheckScriptSuccess([
2953      'vim9script',
2954      'edit #something',
2955      ])
2956  CheckScriptSuccess([
2957      'vim9script',
2958      'edit #{something',
2959      ])
2960  close
2961
2962  CheckScriptFailure([
2963      'vim9script',
2964      ':# something',
2965      ], 'E488:')
2966  CheckScriptFailure([
2967      '# something',
2968      ], 'E488:')
2969  CheckScriptFailure([
2970      ':# something',
2971      ], 'E488:')
2972
2973  { # block start
2974  } # block end
2975  CheckDefFailure([
2976      '{# comment',
2977      ], 'E488:')
2978  CheckDefFailure([
2979      '{',
2980      '}# comment',
2981      ], 'E488:')
2982
2983  echo "yes" # comment
2984  CheckDefFailure([
2985      'echo "yes"# comment',
2986      ], 'E488:')
2987  CheckScriptSuccess([
2988      'vim9script',
2989      'echo "yes" # something',
2990      ])
2991  CheckScriptFailure([
2992      'vim9script',
2993      'echo "yes"# something',
2994      ], 'E121:')
2995  CheckScriptFailure([
2996      'vim9script',
2997      'echo# something',
2998      ], 'E1144:')
2999  CheckScriptFailure([
3000      'echo "yes" # something',
3001      ], 'E121:')
3002
3003  exe "echo" # comment
3004  CheckDefFailure([
3005      'exe "echo"# comment',
3006      ], 'E488:')
3007  CheckScriptSuccess([
3008      'vim9script',
3009      'exe "echo" # something',
3010      ])
3011  CheckScriptFailure([
3012      'vim9script',
3013      'exe "echo"# something',
3014      ], 'E121:')
3015  CheckScriptFailure([
3016      'vim9script',
3017      'exe# something',
3018      ], 'E1144:')
3019  CheckScriptFailure([
3020      'exe "echo" # something',
3021      ], 'E121:')
3022
3023  CheckDefFailure([
3024      'try# comment',
3025      '  echo "yes"',
3026      'catch',
3027      'endtry',
3028      ], 'E1144:')
3029  CheckScriptFailure([
3030      'vim9script',
3031      'try# comment',
3032      'echo "yes"',
3033      ], 'E1144:')
3034  CheckDefFailure([
3035      'try',
3036      '  throw#comment',
3037      'catch',
3038      'endtry',
3039      ], 'E1144:')
3040  CheckDefFailure([
3041      'try',
3042      '  throw "yes"#comment',
3043      'catch',
3044      'endtry',
3045      ], 'E488:')
3046  CheckDefFailure([
3047      'try',
3048      '  echo "yes"',
3049      'catch# comment',
3050      'endtry',
3051      ], 'E1144:')
3052  CheckScriptFailure([
3053      'vim9script',
3054      'try',
3055      '  echo "yes"',
3056      'catch# comment',
3057      'endtry',
3058      ], 'E1144:')
3059  CheckDefFailure([
3060      'try',
3061      '  echo "yes"',
3062      'catch /pat/# comment',
3063      'endtry',
3064      ], 'E488:')
3065  CheckDefFailure([
3066      'try',
3067      'echo "yes"',
3068      'catch',
3069      'endtry# comment',
3070      ], 'E1144:')
3071  CheckScriptFailure([
3072      'vim9script',
3073      'try',
3074      '  echo "yes"',
3075      'catch',
3076      'endtry# comment',
3077      ], 'E1144:')
3078
3079  CheckScriptSuccess([
3080      'vim9script',
3081      'hi # comment',
3082      ])
3083  CheckScriptFailure([
3084      'vim9script',
3085      'hi# comment',
3086      ], 'E1144:')
3087  CheckScriptSuccess([
3088      'vim9script',
3089      'hi Search # comment',
3090      ])
3091  CheckScriptFailure([
3092      'vim9script',
3093      'hi Search# comment',
3094      ], 'E416:')
3095  CheckScriptSuccess([
3096      'vim9script',
3097      'hi link This Search # comment',
3098      ])
3099  CheckScriptFailure([
3100      'vim9script',
3101      'hi link This That# comment',
3102      ], 'E413:')
3103  CheckScriptSuccess([
3104      'vim9script',
3105      'hi clear This # comment',
3106      'hi clear # comment',
3107      ])
3108  # not tested, because it doesn't give an error but a warning:
3109  # hi clear This# comment',
3110  CheckScriptFailure([
3111      'vim9script',
3112      'hi clear# comment',
3113      ], 'E416:')
3114
3115  CheckScriptSuccess([
3116      'vim9script',
3117      'hi Group term=bold',
3118      'match Group /todo/ # comment',
3119      ])
3120  CheckScriptFailure([
3121      'vim9script',
3122      'hi Group term=bold',
3123      'match Group /todo/# comment',
3124      ], 'E488:')
3125  CheckScriptSuccess([
3126      'vim9script',
3127      'match # comment',
3128      ])
3129  CheckScriptFailure([
3130      'vim9script',
3131      'match# comment',
3132      ], 'E1144:')
3133  CheckScriptSuccess([
3134      'vim9script',
3135      'match none # comment',
3136      ])
3137  CheckScriptFailure([
3138      'vim9script',
3139      'match none# comment',
3140      ], 'E475:')
3141
3142  CheckScriptSuccess([
3143      'vim9script',
3144      'menutrans clear # comment',
3145      ])
3146  CheckScriptFailure([
3147      'vim9script',
3148      'menutrans clear# comment text',
3149      ], 'E474:')
3150
3151  CheckScriptSuccess([
3152      'vim9script',
3153      'syntax clear # comment',
3154      ])
3155  CheckScriptFailure([
3156      'vim9script',
3157      'syntax clear# comment text',
3158      ], 'E28:')
3159  CheckScriptSuccess([
3160      'vim9script',
3161      'syntax keyword Word some',
3162      'syntax clear Word # comment',
3163      ])
3164  CheckScriptFailure([
3165      'vim9script',
3166      'syntax keyword Word some',
3167      'syntax clear Word# comment text',
3168      ], 'E28:')
3169
3170  CheckScriptSuccess([
3171      'vim9script',
3172      'syntax list # comment',
3173      ])
3174  CheckScriptFailure([
3175      'vim9script',
3176      'syntax list# comment text',
3177      ], 'E28:')
3178
3179  CheckScriptSuccess([
3180      'vim9script',
3181      'syntax match Word /pat/ oneline # comment',
3182      ])
3183  CheckScriptFailure([
3184      'vim9script',
3185      'syntax match Word /pat/ oneline# comment',
3186      ], 'E475:')
3187
3188  CheckScriptSuccess([
3189      'vim9script',
3190      'syntax keyword Word word # comm[ent',
3191      ])
3192  CheckScriptFailure([
3193      'vim9script',
3194      'syntax keyword Word word# comm[ent',
3195      ], 'E789:')
3196
3197  CheckScriptSuccess([
3198      'vim9script',
3199      'syntax match Word /pat/ # comment',
3200      ])
3201  CheckScriptFailure([
3202      'vim9script',
3203      'syntax match Word /pat/# comment',
3204      ], 'E402:')
3205
3206  CheckScriptSuccess([
3207      'vim9script',
3208      'syntax match Word /pat/ contains=Something # comment',
3209      ])
3210  CheckScriptFailure([
3211      'vim9script',
3212      'syntax match Word /pat/ contains=Something# comment',
3213      ], 'E475:')
3214  CheckScriptFailure([
3215      'vim9script',
3216      'syntax match Word /pat/ contains= # comment',
3217      ], 'E406:')
3218  CheckScriptFailure([
3219      'vim9script',
3220      'syntax match Word /pat/ contains=# comment',
3221      ], 'E475:')
3222
3223  CheckScriptSuccess([
3224      'vim9script',
3225      'syntax region Word start=/pat/ end=/pat/ # comment',
3226      ])
3227  CheckScriptFailure([
3228      'vim9script',
3229      'syntax region Word start=/pat/ end=/pat/# comment',
3230      ], 'E402:')
3231
3232  CheckScriptSuccess([
3233      'vim9script',
3234      'syntax sync # comment',
3235      ])
3236  CheckScriptFailure([
3237      'vim9script',
3238      'syntax sync# comment',
3239      ], 'E404:')
3240  CheckScriptSuccess([
3241      'vim9script',
3242      'syntax sync ccomment # comment',
3243      ])
3244  CheckScriptFailure([
3245      'vim9script',
3246      'syntax sync ccomment# comment',
3247      ], 'E404:')
3248
3249  CheckScriptSuccess([
3250      'vim9script',
3251      'syntax cluster Some contains=Word # comment',
3252      ])
3253  CheckScriptFailure([
3254      'vim9script',
3255      'syntax cluster Some contains=Word# comment',
3256      ], 'E475:')
3257
3258  CheckScriptSuccess([
3259      'vim9script',
3260      'command Echo echo # comment',
3261      'command Echo # comment',
3262      'delcommand Echo',
3263      ])
3264  CheckScriptFailure([
3265      'vim9script',
3266      'command Echo echo# comment',
3267      'Echo',
3268      ], 'E1144:')
3269  delcommand Echo
3270
3271  var curdir = getcwd()
3272  CheckScriptSuccess([
3273      'command Echo cd " comment',
3274      'Echo',
3275      'delcommand Echo',
3276      ])
3277  CheckScriptSuccess([
3278      'vim9script',
3279      'command Echo cd # comment',
3280      'Echo',
3281      'delcommand Echo',
3282      ])
3283  CheckScriptFailure([
3284      'vim9script',
3285      'command Echo cd " comment',
3286      'Echo',
3287      ], 'E344:')
3288  delcommand Echo
3289  chdir(curdir)
3290
3291  CheckScriptFailure([
3292      'vim9script',
3293      'command Echo# comment',
3294      ], 'E182:')
3295  CheckScriptFailure([
3296      'vim9script',
3297      'command Echo echo',
3298      'command Echo# comment',
3299      ], 'E182:')
3300  delcommand Echo
3301
3302  CheckScriptSuccess([
3303      'vim9script',
3304      'function # comment',
3305      ])
3306  CheckScriptFailure([
3307      'vim9script',
3308      'function " comment',
3309      ], 'E129:')
3310  CheckScriptFailure([
3311      'vim9script',
3312      'function# comment',
3313      ], 'E1144:')
3314  CheckScriptSuccess([
3315      'vim9script',
3316      'function CheckScriptSuccess # comment',
3317      ])
3318  CheckScriptFailure([
3319      'vim9script',
3320      'function CheckScriptSuccess# comment',
3321      ], 'E488:')
3322
3323  CheckScriptSuccess([
3324      'vim9script',
3325      'func g:DeleteMeA()',
3326      'endfunc',
3327      'delfunction g:DeleteMeA # comment',
3328      ])
3329  CheckScriptFailure([
3330      'vim9script',
3331      'func g:DeleteMeB()',
3332      'endfunc',
3333      'delfunction g:DeleteMeB# comment',
3334      ], 'E488:')
3335
3336  CheckScriptSuccess([
3337      'vim9script',
3338      'call execute("ls") # comment',
3339      ])
3340  CheckScriptFailure([
3341      'vim9script',
3342      'call execute("ls")# comment',
3343      ], 'E488:')
3344
3345  CheckScriptFailure([
3346      'def Test() " comment',
3347      'enddef',
3348      ], 'E488:')
3349  CheckScriptFailure([
3350      'vim9script',
3351      'def Test() " comment',
3352      'enddef',
3353      ], 'E488:')
3354
3355  CheckScriptSuccess([
3356      'func Test() " comment',
3357      'endfunc',
3358      'delfunc Test',
3359      ])
3360  CheckScriptSuccess([
3361      'vim9script',
3362      'func Test() " comment',
3363      'endfunc',
3364      ])
3365
3366  CheckScriptSuccess([
3367      'def Test() # comment',
3368      'enddef',
3369      ])
3370  CheckScriptFailure([
3371      'func Test() # comment',
3372      'endfunc',
3373      ], 'E488:')
3374
3375  var lines =<< trim END
3376      vim9script
3377      syn region Text
3378      \ start='foo'
3379      #\ comment
3380      \ end='bar'
3381      syn region Text start='foo'
3382      #\ comment
3383      \ end='bar'
3384  END
3385  CheckScriptSuccess(lines)
3386
3387  lines =<< trim END
3388      vim9script
3389      syn region Text
3390      \ start='foo'
3391      "\ comment
3392      \ end='bar'
3393  END
3394  CheckScriptFailure(lines, 'E399:')
3395enddef
3396
3397def Test_vim9_comment_gui()
3398  CheckCanRunGui
3399
3400  CheckScriptFailure([
3401      'vim9script',
3402      'gui#comment'
3403      ], 'E1144:')
3404  CheckScriptFailure([
3405      'vim9script',
3406      'gui -f#comment'
3407      ], 'E499:')
3408enddef
3409
3410def Test_vim9_comment_not_compiled()
3411  au TabEnter *.vim g:entered = 1
3412  au TabEnter *.x g:entered = 2
3413
3414  edit test.vim
3415  doautocmd TabEnter #comment
3416  assert_equal(1, g:entered)
3417
3418  doautocmd TabEnter f.x
3419  assert_equal(2, g:entered)
3420
3421  g:entered = 0
3422  doautocmd TabEnter f.x #comment
3423  assert_equal(2, g:entered)
3424
3425  assert_fails('doautocmd Syntax#comment', 'E216:')
3426
3427  au! TabEnter
3428  unlet g:entered
3429
3430  CheckScriptSuccess([
3431      'vim9script',
3432      'g:var = 123',
3433      'b:var = 456',
3434      'w:var = 777',
3435      't:var = 888',
3436      'unlet g:var w:var # something',
3437      ])
3438
3439  CheckScriptFailure([
3440      'vim9script',
3441      'let var = 123',
3442      ], 'E1126: Cannot use :let in Vim9 script')
3443
3444  CheckScriptFailure([
3445      'vim9script',
3446      'var g:var = 123',
3447      ], 'E1016: Cannot declare a global variable:')
3448
3449  CheckScriptFailure([
3450      'vim9script',
3451      'var b:var = 123',
3452      ], 'E1016: Cannot declare a buffer variable:')
3453
3454  CheckScriptFailure([
3455      'vim9script',
3456      'var w:var = 123',
3457      ], 'E1016: Cannot declare a window variable:')
3458
3459  CheckScriptFailure([
3460      'vim9script',
3461      'var t:var = 123',
3462      ], 'E1016: Cannot declare a tab variable:')
3463
3464  CheckScriptFailure([
3465      'vim9script',
3466      'var v:version = 123',
3467      ], 'E1016: Cannot declare a v: variable:')
3468
3469  CheckScriptFailure([
3470      'vim9script',
3471      'var $VARIABLE = "text"',
3472      ], 'E1016: Cannot declare an environment variable:')
3473
3474  CheckScriptFailure([
3475      'vim9script',
3476      'g:var = 123',
3477      'unlet g:var# comment1',
3478      ], 'E108:')
3479
3480  CheckScriptFailure([
3481      'let g:var = 123',
3482      'unlet g:var # something',
3483      ], 'E488:')
3484
3485  CheckScriptSuccess([
3486      'vim9script',
3487      'if 1 # comment2',
3488      '  echo "yes"',
3489      'elseif 2 #comment',
3490      '  echo "no"',
3491      'endif',
3492      ])
3493
3494  CheckScriptFailure([
3495      'vim9script',
3496      'if 1# comment3',
3497      '  echo "yes"',
3498      'endif',
3499      ], 'E488:')
3500
3501  CheckScriptFailure([
3502      'vim9script',
3503      'if 0 # comment4',
3504      '  echo "yes"',
3505      'elseif 2#comment',
3506      '  echo "no"',
3507      'endif',
3508      ], 'E488:')
3509
3510  CheckScriptSuccess([
3511      'vim9script',
3512      'var v = 1 # comment5',
3513      ])
3514
3515  CheckScriptFailure([
3516      'vim9script',
3517      'var v = 1# comment6',
3518      ], 'E488:')
3519
3520  CheckScriptSuccess([
3521      'vim9script',
3522      'new'
3523      'setline(1, ["# define pat", "last"])',
3524      ':$',
3525      'dsearch /pat/ #comment',
3526      'bwipe!',
3527      ])
3528
3529  CheckScriptFailure([
3530      'vim9script',
3531      'new'
3532      'setline(1, ["# define pat", "last"])',
3533      ':$',
3534      'dsearch /pat/#comment',
3535      'bwipe!',
3536      ], 'E488:')
3537
3538  CheckScriptFailure([
3539      'vim9script',
3540      'func! SomeFunc()',
3541      ], 'E477:')
3542enddef
3543
3544def Test_finish()
3545  var lines =<< trim END
3546    vim9script
3547    g:res = 'one'
3548    if v:false | finish | endif
3549    g:res = 'two'
3550    finish
3551    g:res = 'three'
3552  END
3553  writefile(lines, 'Xfinished')
3554  source Xfinished
3555  assert_equal('two', g:res)
3556
3557  unlet g:res
3558  delete('Xfinished')
3559enddef
3560
3561def Test_forward_declaration()
3562  var lines =<< trim END
3563    vim9script
3564    def GetValue(): string
3565      return theVal
3566    enddef
3567    var theVal = 'something'
3568    g:initVal = GetValue()
3569    theVal = 'else'
3570    g:laterVal = GetValue()
3571  END
3572  writefile(lines, 'Xforward')
3573  source Xforward
3574  assert_equal('something', g:initVal)
3575  assert_equal('else', g:laterVal)
3576
3577  unlet g:initVal
3578  unlet g:laterVal
3579  delete('Xforward')
3580enddef
3581
3582def Test_source_vim9_from_legacy()
3583  var vim9_lines =<< trim END
3584    vim9script
3585    var local = 'local'
3586    g:global = 'global'
3587    export var exported = 'exported'
3588    export def GetText(): string
3589       return 'text'
3590    enddef
3591  END
3592  writefile(vim9_lines, 'Xvim9_script.vim')
3593
3594  var legacy_lines =<< trim END
3595    source Xvim9_script.vim
3596
3597    call assert_false(exists('local'))
3598    call assert_false(exists('exported'))
3599    call assert_false(exists('s:exported'))
3600    call assert_equal('global', global)
3601    call assert_equal('global', g:global)
3602
3603    " imported variable becomes script-local
3604    import exported from './Xvim9_script.vim'
3605    call assert_equal('exported', s:exported)
3606    call assert_false(exists('exported'))
3607
3608    " imported function becomes script-local
3609    import GetText from './Xvim9_script.vim'
3610    call assert_equal('text', s:GetText())
3611    call assert_false(exists('*GetText'))
3612  END
3613  writefile(legacy_lines, 'Xlegacy_script.vim')
3614
3615  source Xlegacy_script.vim
3616  assert_equal('global', g:global)
3617  unlet g:global
3618
3619  delete('Xlegacy_script.vim')
3620  delete('Xvim9_script.vim')
3621enddef
3622
3623def Test_declare_script_in_func()
3624  var lines =<< trim END
3625      vim9script
3626      func Declare()
3627        let s:local = 123
3628      endfunc
3629      Declare()
3630      assert_equal(123, local)
3631
3632      var error: string
3633      try
3634        local = 'asdf'
3635      catch
3636        error = v:exception
3637      endtry
3638      assert_match('E1012: Type mismatch; expected number but got string', error)
3639
3640      lockvar local
3641      try
3642        local = 999
3643      catch
3644        error = v:exception
3645      endtry
3646      assert_match('E741: Value is locked: local', error)
3647  END
3648  CheckScriptSuccess(lines)
3649enddef
3650
3651
3652func Test_vim9script_not_global()
3653  " check that items defined in Vim9 script are script-local, not global
3654  let vim9lines =<< trim END
3655    vim9script
3656    var name = 'local'
3657    func TheFunc()
3658      echo 'local'
3659    endfunc
3660    def DefFunc()
3661      echo 'local'
3662    enddef
3663  END
3664  call writefile(vim9lines, 'Xvim9script.vim')
3665  source Xvim9script.vim
3666  try
3667    echo g:var
3668    assert_report('did not fail')
3669  catch /E121:/
3670    " caught
3671  endtry
3672  try
3673    call TheFunc()
3674    assert_report('did not fail')
3675  catch /E117:/
3676    " caught
3677  endtry
3678  try
3679    call DefFunc()
3680    assert_report('did not fail')
3681  catch /E117:/
3682    " caught
3683  endtry
3684
3685  call delete('Xvim9script.vim')
3686endfunc
3687
3688def Test_vim9_copen()
3689  # this was giving an error for setting w:quickfix_title
3690  copen
3691  quit
3692enddef
3693
3694" test using an auto-loaded function and variable
3695def Test_vim9_autoload()
3696  var lines =<< trim END
3697     vim9script
3698     def some#gettest(): string
3699       return 'test'
3700     enddef
3701     g:some#name = 'name'
3702     g:some#dict = {key: 'value'}
3703
3704     def some#varargs(a1: string, ...l: list<string>): string
3705       return a1 .. l[0] .. l[1]
3706     enddef
3707  END
3708
3709  mkdir('Xdir/autoload', 'p')
3710  writefile(lines, 'Xdir/autoload/some.vim')
3711  var save_rtp = &rtp
3712  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3713
3714  assert_equal('test', g:some#gettest())
3715  assert_equal('name', g:some#name)
3716  assert_equal('value', g:some#dict.key)
3717  g:some#other = 'other'
3718  assert_equal('other', g:some#other)
3719
3720  assert_equal('abc', some#varargs('a', 'b', 'c'))
3721
3722  # upper case script name works
3723  lines =<< trim END
3724     vim9script
3725     def Other#getOther(): string
3726       return 'other'
3727     enddef
3728  END
3729  writefile(lines, 'Xdir/autoload/Other.vim')
3730  assert_equal('other', g:Other#getOther())
3731
3732  delete('Xdir', 'rf')
3733  &rtp = save_rtp
3734enddef
3735
3736" test using a vim9script that is auto-loaded from an autocmd
3737def Test_vim9_aucmd_autoload()
3738  var lines =<< trim END
3739     vim9script
3740     def foo#test()
3741         echomsg getreg('"')
3742     enddef
3743  END
3744
3745  mkdir('Xdir/autoload', 'p')
3746  writefile(lines, 'Xdir/autoload/foo.vim')
3747  var save_rtp = &rtp
3748  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3749  augroup test
3750    autocmd TextYankPost * call foo#test()
3751  augroup END
3752
3753  normal Y
3754
3755  augroup test
3756    autocmd!
3757  augroup END
3758  delete('Xdir', 'rf')
3759  &rtp = save_rtp
3760enddef
3761
3762" This was causing a crash because suppress_errthrow wasn't reset.
3763def Test_vim9_autoload_error()
3764  var lines =<< trim END
3765      vim9script
3766      def crash#func()
3767          try
3768              for x in List()
3769              endfor
3770          catch
3771          endtry
3772          g:ok = true
3773      enddef
3774      fu List()
3775          invalid
3776      endfu
3777      try
3778          alsoinvalid
3779      catch /wontmatch/
3780      endtry
3781  END
3782  call mkdir('Xruntime/autoload', 'p')
3783  call writefile(lines, 'Xruntime/autoload/crash.vim')
3784
3785  # run in a separate Vim to avoid the side effects of assert_fails()
3786  lines =<< trim END
3787    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
3788    call crash#func()
3789    call writefile(['ok'], 'Xdidit')
3790    qall!
3791  END
3792  writefile(lines, 'Xscript')
3793  RunVim([], [], '-S Xscript')
3794  assert_equal(['ok'], readfile('Xdidit'))
3795
3796  delete('Xdidit')
3797  delete('Xscript')
3798  delete('Xruntime', 'rf')
3799
3800  lines =<< trim END
3801    vim9script
3802    var foo#bar = 'asdf'
3803  END
3804  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
3805enddef
3806
3807def Test_script_var_in_autocmd()
3808  # using a script variable from an autocommand, defined in a :def function in a
3809  # legacy Vim script, cannot check the variable type.
3810  var lines =<< trim END
3811    let s:counter = 1
3812    def s:Func()
3813      au! CursorHold
3814      au CursorHold * s:counter += 1
3815    enddef
3816    call s:Func()
3817    doau CursorHold
3818    call assert_equal(2, s:counter)
3819    au! CursorHold
3820  END
3821  CheckScriptSuccess(lines)
3822enddef
3823
3824def Test_error_in_autoload_script()
3825  var save_rtp = &rtp
3826  var dir = getcwd() .. '/Xruntime'
3827  &rtp = dir
3828  mkdir(dir .. '/autoload', 'p')
3829
3830  var lines =<< trim END
3831      vim9script noclear
3832      def script#autoloaded()
3833      enddef
3834      def Broken()
3835        var x: any = ''
3836        eval x != 0
3837      enddef
3838      Broken()
3839  END
3840  writefile(lines, dir .. '/autoload/script.vim')
3841
3842  lines =<< trim END
3843      vim9script
3844      def CallAutoloaded()
3845        script#autoloaded()
3846      enddef
3847
3848      function Legacy()
3849        try
3850          call s:CallAutoloaded()
3851        catch
3852          call assert_match('E1030: Using a String as a Number', v:exception)
3853        endtry
3854      endfunction
3855
3856      Legacy()
3857  END
3858  CheckScriptSuccess(lines)
3859
3860  &rtp = save_rtp
3861  delete(dir, 'rf')
3862enddef
3863
3864def Test_cmdline_win()
3865  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
3866  # the command line window.
3867  mkdir('rtp/syntax', 'p')
3868  var export_lines =<< trim END
3869    vim9script
3870    export var That = 'yes'
3871  END
3872  writefile(export_lines, 'rtp/syntax/Xexport.vim')
3873  var import_lines =<< trim END
3874    vim9script
3875    import That from './Xexport.vim'
3876  END
3877  writefile(import_lines, 'rtp/syntax/vim.vim')
3878  var save_rtp = &rtp
3879  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
3880  syntax on
3881  augroup CmdWin
3882    autocmd CmdwinEnter * g:got_there = 'yes'
3883  augroup END
3884  # this will open and also close the cmdline window
3885  feedkeys('q:', 'xt')
3886  assert_equal('yes', g:got_there)
3887
3888  augroup CmdWin
3889    au!
3890  augroup END
3891  &rtp = save_rtp
3892  delete('rtp', 'rf')
3893enddef
3894
3895def Test_invalid_sid()
3896  assert_fails('func <SNR>1234_func', 'E123:')
3897
3898  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
3899    assert_equal([], readfile('Xdidit'))
3900  endif
3901  delete('Xdidit')
3902enddef
3903
3904def Test_restoring_cpo()
3905  writefile(['vim9script', 'set nocp'], 'Xsourced')
3906  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
3907  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
3908    assert_equal(['done'], readfile('Xdone'))
3909  endif
3910  delete('Xsourced')
3911  delete('Xclose')
3912  delete('Xdone')
3913
3914  writefile(['vim9script'], 'XanotherScript')
3915  set cpo=aABceFsMny>
3916  edit XanotherScript
3917  so %
3918  assert_equal('aABceFsMny>', &cpo)
3919  :1del
3920  w
3921  so %
3922  assert_equal('aABceFsMny>', &cpo)
3923
3924  delete('XanotherScript')
3925  set cpo&vim
3926enddef
3927
3928" Use :function so we can use Check commands
3929func Test_no_redraw_when_restoring_cpo()
3930  CheckScreendump
3931  CheckFeature timers
3932
3933  let lines =<< trim END
3934    vim9script
3935    def script#func()
3936    enddef
3937  END
3938  call mkdir('Xdir/autoload', 'p')
3939  call writefile(lines, 'Xdir/autoload/script.vim')
3940
3941  let lines =<< trim END
3942      vim9script
3943      set cpo+=M
3944      exe 'set rtp^=' .. getcwd() .. '/Xdir'
3945      au CmdlineEnter : ++once timer_start(0, (_) => script#func())
3946      setline(1, 'some text')
3947  END
3948  call writefile(lines, 'XTest_redraw_cpo')
3949  let buf = RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
3950  call term_sendkeys(buf, "V:")
3951  call VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
3952
3953  " clean up
3954  call term_sendkeys(buf, "\<Esc>u")
3955  call StopVimInTerminal(buf)
3956  call delete('XTest_redraw_cpo')
3957  call delete('Xdir', 'rf')
3958endfunc
3959
3960
3961def Test_unset_any_variable()
3962  var lines =<< trim END
3963    var name: any
3964    assert_equal(0, name)
3965  END
3966  CheckDefAndScriptSuccess(lines)
3967enddef
3968
3969func Test_define_func_at_command_line()
3970  CheckRunVimInTerminal
3971
3972  " call indirectly to avoid compilation error for missing functions
3973  call Run_Test_define_func_at_command_line()
3974endfunc
3975
3976def Run_Test_define_func_at_command_line()
3977  # run in a separate Vim instance to avoid the script context
3978  var lines =<< trim END
3979    func CheckAndQuit()
3980      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
3981      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
3982    endfunc
3983  END
3984  writefile([''], 'Xdidcmd')
3985  writefile(lines, 'XcallFunc')
3986  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
3987  # define Afunc() on the command line
3988  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
3989  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
3990  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
3991
3992  call StopVimInTerminal(buf)
3993  delete('XcallFunc')
3994  delete('Xdidcmd')
3995enddef
3996
3997def Test_script_var_scope()
3998  var lines =<< trim END
3999      vim9script
4000      if true
4001        if true
4002          var one = 'one'
4003          echo one
4004        endif
4005        echo one
4006      endif
4007  END
4008  CheckScriptFailure(lines, 'E121:', 7)
4009
4010  lines =<< trim END
4011      vim9script
4012      if true
4013        if false
4014          var one = 'one'
4015          echo one
4016        else
4017          var one = 'one'
4018          echo one
4019        endif
4020        echo one
4021      endif
4022  END
4023  CheckScriptFailure(lines, 'E121:', 10)
4024
4025  lines =<< trim END
4026      vim9script
4027      while true
4028        var one = 'one'
4029        echo one
4030        break
4031      endwhile
4032      echo one
4033  END
4034  CheckScriptFailure(lines, 'E121:', 7)
4035
4036  lines =<< trim END
4037      vim9script
4038      for i in range(1)
4039        var one = 'one'
4040        echo one
4041      endfor
4042      echo one
4043  END
4044  CheckScriptFailure(lines, 'E121:', 6)
4045
4046  lines =<< trim END
4047      vim9script
4048      {
4049        var one = 'one'
4050        assert_equal('one', one)
4051      }
4052      assert_false(exists('one'))
4053      assert_false(exists('s:one'))
4054  END
4055  CheckScriptSuccess(lines)
4056
4057  lines =<< trim END
4058      vim9script
4059      {
4060        var one = 'one'
4061        echo one
4062      }
4063      echo one
4064  END
4065  CheckScriptFailure(lines, 'E121:', 6)
4066enddef
4067
4068def Test_catch_exception_in_callback()
4069  var lines =<< trim END
4070    vim9script
4071    def Callback(...l: list<any>)
4072      try
4073        var x: string
4074        var y: string
4075        # this error should be caught with CHECKLEN
4076        [x, y] = ['']
4077      catch
4078        g:caught = 'yes'
4079      endtry
4080    enddef
4081    popup_menu('popup', {callback: Callback})
4082    feedkeys("\r", 'xt')
4083  END
4084  CheckScriptSuccess(lines)
4085
4086  unlet g:caught
4087enddef
4088
4089def Test_no_unknown_error_after_error()
4090  if !has('unix') || !has('job')
4091    throw 'Skipped: not unix of missing +job feature'
4092  endif
4093  var lines =<< trim END
4094      vim9script
4095      var source: list<number>
4096      def Out_cb(...l: list<any>)
4097          eval [][0]
4098      enddef
4099      def Exit_cb(...l: list<any>)
4100          sleep 1m
4101          source += l
4102      enddef
4103      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
4104      while job_status(myjob) == 'run'
4105        sleep 10m
4106      endwhile
4107      # wait for Exit_cb() to be called
4108      sleep 200m
4109  END
4110  writefile(lines, 'Xdef')
4111  assert_fails('so Xdef', ['E684:', 'E1012:'])
4112  delete('Xdef')
4113enddef
4114
4115def InvokeNormal()
4116  exe "norm! :m+1\r"
4117enddef
4118
4119def Test_invoke_normal_in_visual_mode()
4120  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
4121  new
4122  setline(1, ['aaa', 'bbb'])
4123  feedkeys("V\<F3>", 'xt')
4124  assert_equal(['bbb', 'aaa'], getline(1, 2))
4125  xunmap <F3>
4126enddef
4127
4128def Test_white_space_after_command()
4129  var lines =<< trim END
4130    exit_cb: Func})
4131  END
4132  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4133
4134  lines =<< trim END
4135    e#
4136  END
4137  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4138enddef
4139
4140def Test_script_var_gone_when_sourced_twice()
4141  var lines =<< trim END
4142      vim9script
4143      if exists('g:guard')
4144        finish
4145      endif
4146      g:guard = 1
4147      var name = 'thename'
4148      def g:GetName(): string
4149        return name
4150      enddef
4151      def g:SetName(arg: string)
4152        name = arg
4153      enddef
4154  END
4155  writefile(lines, 'XscriptTwice.vim')
4156  so XscriptTwice.vim
4157  assert_equal('thename', g:GetName())
4158  g:SetName('newname')
4159  assert_equal('newname', g:GetName())
4160  so XscriptTwice.vim
4161  assert_fails('call g:GetName()', 'E1149:')
4162  assert_fails('call g:SetName("x")', 'E1149:')
4163
4164  delfunc g:GetName
4165  delfunc g:SetName
4166  delete('XscriptTwice.vim')
4167  unlet g:guard
4168enddef
4169
4170def Test_import_gone_when_sourced_twice()
4171  var exportlines =<< trim END
4172      vim9script
4173      if exists('g:guard')
4174        finish
4175      endif
4176      g:guard = 1
4177      export var name = 'someName'
4178  END
4179  writefile(exportlines, 'XexportScript.vim')
4180
4181  var lines =<< trim END
4182      vim9script
4183      import name from './XexportScript.vim'
4184      def g:GetName(): string
4185        return name
4186      enddef
4187  END
4188  writefile(lines, 'XscriptImport.vim')
4189  so XscriptImport.vim
4190  assert_equal('someName', g:GetName())
4191
4192  so XexportScript.vim
4193  assert_fails('call g:GetName()', 'E1149:')
4194
4195  delfunc g:GetName
4196  delete('XexportScript.vim')
4197  delete('XscriptImport.vim')
4198  unlet g:guard
4199enddef
4200
4201def Test_unsupported_commands()
4202  var lines =<< trim END
4203      ka
4204  END
4205  CheckDefFailure(lines, 'E476:')
4206  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4207
4208  lines =<< trim END
4209      :1ka
4210  END
4211  CheckDefFailure(lines, 'E476:')
4212  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4213
4214  lines =<< trim END
4215    t
4216  END
4217  CheckDefFailure(lines, 'E1100:')
4218  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4219
4220  lines =<< trim END
4221    x
4222  END
4223  CheckDefFailure(lines, 'E1100:')
4224  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4225
4226  lines =<< trim END
4227    xit
4228  END
4229  CheckDefFailure(lines, 'E1100:')
4230  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4231enddef
4232
4233def Test_mapping_line_number()
4234  var lines =<< trim END
4235      vim9script
4236      def g:FuncA()
4237          # Some comment
4238          FuncB(0)
4239      enddef
4240          # Some comment
4241      def FuncB(
4242          # Some comment
4243          n: number
4244      )
4245          exe 'nno '
4246              # Some comment
4247              .. '<F3> a'
4248              .. 'b'
4249              .. 'c'
4250      enddef
4251  END
4252  CheckScriptSuccess(lines)
4253  var res = execute('verbose nmap <F3>')
4254  assert_match('No mapping found', res)
4255
4256  g:FuncA()
4257  res = execute('verbose nmap <F3>')
4258  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
4259
4260  nunmap <F3>
4261  delfunc g:FuncA
4262enddef
4263
4264def Test_option_set()
4265  # legacy script allows for white space
4266  var lines =<< trim END
4267      set foldlevel  =11
4268      call assert_equal(11, &foldlevel)
4269  END
4270  CheckScriptSuccess(lines)
4271
4272  set foldlevel
4273  set foldlevel=12
4274  assert_equal(12, &foldlevel)
4275  set foldlevel+=2
4276  assert_equal(14, &foldlevel)
4277  set foldlevel-=3
4278  assert_equal(11, &foldlevel)
4279
4280  lines =<< trim END
4281      set foldlevel =1
4282  END
4283  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
4284
4285  lines =<< trim END
4286      set foldlevel +=1
4287  END
4288  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
4289
4290  lines =<< trim END
4291      set foldlevel ^=1
4292  END
4293  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
4294
4295  lines =<< trim END
4296      set foldlevel -=1
4297  END
4298  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
4299
4300  set foldlevel&
4301enddef
4302
4303def Test_option_modifier()
4304  # legacy script allows for white space
4305  var lines =<< trim END
4306      set hlsearch &  hlsearch  !
4307      call assert_equal(1, &hlsearch)
4308  END
4309  CheckScriptSuccess(lines)
4310
4311  set hlsearch
4312  set hlsearch!
4313  assert_equal(false, &hlsearch)
4314
4315  set hlsearch
4316  set hlsearch&
4317  assert_equal(false, &hlsearch)
4318
4319  lines =<< trim END
4320      set hlsearch &
4321  END
4322  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
4323
4324  lines =<< trim END
4325      set hlsearch   !
4326  END
4327  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
4328
4329  set hlsearch&
4330enddef
4331
4332" This must be called last, it may cause following :def functions to fail
4333def Test_xxx_echoerr_line_number()
4334  var lines =<< trim END
4335      echoerr 'some'
4336         .. ' error'
4337         .. ' continued'
4338  END
4339  CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
4340enddef
4341
4342def ProfiledWithLambda()
4343  var n = 3
4344  echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
4345enddef
4346
4347def ProfiledNested()
4348  var x = 0
4349  def Nested(): any
4350      return x
4351  enddef
4352  Nested()
4353enddef
4354
4355def ProfiledNestedProfiled()
4356  var x = 0
4357  def Nested(): any
4358      return x
4359  enddef
4360  Nested()
4361enddef
4362
4363" Execute this near the end, profiling doesn't stop until Vim exists.
4364" This only tests that it works, not the profiling output.
4365def Test_xx_profile_with_lambda()
4366  CheckFeature profile
4367
4368  profile start Xprofile.log
4369  profile func ProfiledWithLambda
4370  ProfiledWithLambda()
4371
4372  profile func ProfiledNested
4373  ProfiledNested()
4374
4375  # Also profile the nested function.  Use a different function, although the
4376  # contents is the same, to make sure it was not already compiled.
4377  profile func *
4378  ProfiledNestedProfiled()
4379
4380  profdel func *
4381  profile pause
4382enddef
4383
4384" Keep this last, it messes up highlighting.
4385def Test_substitute_cmd()
4386  new
4387  setline(1, 'something')
4388  :substitute(some(other(
4389  assert_equal('otherthing', getline(1))
4390  bwipe!
4391
4392  # also when the context is Vim9 script
4393  var lines =<< trim END
4394    vim9script
4395    new
4396    setline(1, 'something')
4397    :substitute(some(other(
4398    assert_equal('otherthing', getline(1))
4399    bwipe!
4400  END
4401  writefile(lines, 'Xvim9lines')
4402  source Xvim9lines
4403
4404  delete('Xvim9lines')
4405enddef
4406
4407" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
4408