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