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