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_funcref()
1481  var lines =<< trim END
1482      vim9script
1483      export def F(): number
1484        return 42
1485      enddef
1486      export const G = F
1487  END
1488  writefile(lines, 'Xlib.vim')
1489
1490  lines =<< trim END
1491      vim9script
1492      import {G} from './Xlib.vim'
1493      const Foo = G()
1494      assert_equal(42, Foo)
1495
1496      def DoTest()
1497        const Goo = G()
1498        assert_equal(42, Goo)
1499      enddef
1500      DoTest()
1501  END
1502  CheckScriptSuccess(lines)
1503
1504  delete('Xlib.vim')
1505enddef
1506
1507def Test_import_star_fails()
1508  writefile([], 'Xfoo.vim')
1509  var lines =<< trim END
1510      import * as foo from './Xfoo.vim'
1511      foo = 'bar'
1512  END
1513  CheckDefAndScriptFailure2(lines, 'E1094:', 'E1236: Cannot use foo itself')
1514  lines =<< trim END
1515      vim9script
1516      import * as foo from './Xfoo.vim'
1517      var that = foo
1518  END
1519  CheckScriptFailure(lines, 'E1029: Expected ''.''')
1520
1521  lines =<< trim END
1522      vim9script
1523      import * as 9foo from './Xfoo.vim'
1524  END
1525  CheckScriptFailure(lines, 'E1047:')
1526  lines =<< trim END
1527      vim9script
1528      import * as the#foo from './Xfoo.vim'
1529  END
1530  CheckScriptFailure(lines, 'E1047:')
1531  lines =<< trim END
1532      vim9script
1533      import * as g:foo from './Xfoo.vim'
1534  END
1535  CheckScriptFailure(lines, 'E1047:')
1536
1537  delete('Xfoo.vim')
1538enddef
1539
1540def Test_import_as()
1541  var export_lines =<< trim END
1542    vim9script
1543    export var one = 1
1544    export var yes = 'yes'
1545    export var slist: list<string>
1546  END
1547  writefile(export_lines, 'XexportAs')
1548
1549  var import_lines =<< trim END
1550    vim9script
1551    var one = 'notused'
1552    var yes = 777
1553    import one as thatOne from './XexportAs'
1554    assert_equal(1, thatOne)
1555    import yes as yesYes from './XexportAs'
1556    assert_equal('yes', yesYes)
1557  END
1558  CheckScriptSuccess(import_lines)
1559
1560  import_lines =<< trim END
1561    vim9script
1562    import {one as thatOne, yes as yesYes} from './XexportAs'
1563    assert_equal(1, thatOne)
1564    assert_equal('yes', yesYes)
1565    assert_fails('echo one', 'E121:')
1566    assert_fails('echo yes', 'E121:')
1567  END
1568  CheckScriptSuccess(import_lines)
1569
1570  import_lines =<< trim END
1571    vim9script
1572    import {slist as impSlist} from './XexportAs'
1573    impSlist->add(123)
1574  END
1575  CheckScriptFailure(import_lines, 'E1012: Type mismatch; expected string but got number')
1576
1577  delete('XexportAs')
1578enddef
1579
1580func g:Trigger()
1581  source Ximport.vim
1582  return "echo 'yes'\<CR>"
1583endfunc
1584
1585def Test_import_export_expr_map()
1586  # check that :import and :export work when buffer is locked
1587  var export_lines =<< trim END
1588    vim9script
1589    export def That(): string
1590      return 'yes'
1591    enddef
1592  END
1593  writefile(export_lines, 'Xexport_that.vim')
1594
1595  var import_lines =<< trim END
1596    vim9script
1597    import That from './Xexport_that.vim'
1598    assert_equal('yes', That())
1599  END
1600  writefile(import_lines, 'Ximport.vim')
1601
1602  nnoremap <expr> trigger g:Trigger()
1603  feedkeys('trigger', "xt")
1604
1605  delete('Xexport_that.vim')
1606  delete('Ximport.vim')
1607  nunmap trigger
1608enddef
1609
1610def Test_import_in_filetype()
1611  # check that :import works when the buffer is locked
1612  mkdir('ftplugin', 'p')
1613  var export_lines =<< trim END
1614    vim9script
1615    export var That = 'yes'
1616  END
1617  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1618
1619  var import_lines =<< trim END
1620    vim9script
1621    import That from './Xexport_ft.vim'
1622    assert_equal('yes', That)
1623    g:did_load_mytpe = 1
1624  END
1625  writefile(import_lines, 'ftplugin/qf.vim')
1626
1627  var save_rtp = &rtp
1628  &rtp = getcwd() .. ',' .. &rtp
1629
1630  filetype plugin on
1631  copen
1632  assert_equal(1, g:did_load_mytpe)
1633
1634  quit!
1635  delete('Xexport_ft.vim')
1636  delete('ftplugin', 'rf')
1637  &rtp = save_rtp
1638enddef
1639
1640def Test_use_import_in_mapping()
1641  var lines =<< trim END
1642      vim9script
1643      export def Funcx()
1644        g:result = 42
1645      enddef
1646  END
1647  writefile(lines, 'XsomeExport.vim')
1648  lines =<< trim END
1649      vim9script
1650      import Funcx from './XsomeExport.vim'
1651      nnoremap <F3> :call <sid>Funcx()<cr>
1652  END
1653  writefile(lines, 'Xmapscript.vim')
1654
1655  source Xmapscript.vim
1656  feedkeys("\<F3>", "xt")
1657  assert_equal(42, g:result)
1658
1659  unlet g:result
1660  delete('XsomeExport.vim')
1661  delete('Xmapscript.vim')
1662  nunmap <F3>
1663enddef
1664
1665def Test_vim9script_mix()
1666  var lines =<< trim END
1667    if has(g:feature)
1668      " legacy script
1669      let g:legacy = 1
1670      finish
1671    endif
1672    vim9script
1673    g:legacy = 0
1674  END
1675  g:feature = 'eval'
1676  g:legacy = -1
1677  CheckScriptSuccess(lines)
1678  assert_equal(1, g:legacy)
1679
1680  g:feature = 'noteval'
1681  g:legacy = -1
1682  CheckScriptSuccess(lines)
1683  assert_equal(0, g:legacy)
1684enddef
1685
1686def Test_vim9script_fails()
1687  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1688  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1689  CheckScriptFailure(['export var some = 123'], 'E1042:')
1690  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1691  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1692  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1693
1694  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1695  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1696
1697  assert_fails('vim9script', 'E1038:')
1698  assert_fails('export something', 'E1043:')
1699enddef
1700
1701func Test_import_fails_without_script()
1702  CheckRunVimInTerminal
1703
1704  " call indirectly to avoid compilation error for missing functions
1705  call Run_Test_import_fails_on_command_line()
1706endfunc
1707
1708def Run_Test_import_fails_on_command_line()
1709  var export =<< trim END
1710    vim9script
1711    export def Foo(): number
1712        return 0
1713    enddef
1714  END
1715  writefile(export, 'XexportCmd.vim')
1716
1717  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1718                rows: 6, wait_for_ruler: 0})
1719  WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
1720
1721  delete('XexportCmd.vim')
1722  StopVimInTerminal(buf)
1723enddef
1724
1725def Test_vim9script_reload_noclear()
1726  var lines =<< trim END
1727    vim9script
1728    export var exported = 'thexport'
1729
1730    export def TheFunc(x = 0)
1731    enddef
1732  END
1733  writefile(lines, 'XExportReload')
1734  lines =<< trim END
1735    vim9script noclear
1736    g:loadCount += 1
1737    var s:reloaded = 'init'
1738    import exported from './XExportReload'
1739
1740    def Again(): string
1741      return 'again'
1742    enddef
1743
1744    import TheFunc from './XExportReload'
1745    TheFunc()
1746
1747    if exists('s:loaded') | finish | endif
1748    var s:loaded = true
1749
1750    var s:notReloaded = 'yes'
1751    s:reloaded = 'first'
1752    def g:Values(): list<string>
1753      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
1754    enddef
1755
1756    def Once(): string
1757      return 'once'
1758    enddef
1759  END
1760  writefile(lines, 'XReloaded')
1761  g:loadCount = 0
1762  source XReloaded
1763  assert_equal(1, g:loadCount)
1764  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
1765  source XReloaded
1766  assert_equal(2, g:loadCount)
1767  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1768  source XReloaded
1769  assert_equal(3, g:loadCount)
1770  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1771
1772  delete('XReloaded')
1773  delete('XExportReload')
1774  delfunc g:Values
1775  unlet g:loadCount
1776
1777  lines =<< trim END
1778      vim9script
1779      def Inner()
1780      enddef
1781  END
1782  lines->writefile('XreloadScript.vim')
1783  source XreloadScript.vim
1784
1785  lines =<< trim END
1786      vim9script
1787      def Outer()
1788        def Inner()
1789        enddef
1790      enddef
1791      defcompile
1792  END
1793  lines->writefile('XreloadScript.vim')
1794  source XreloadScript.vim
1795
1796  delete('XreloadScript.vim')
1797enddef
1798
1799def Test_vim9script_reload_import()
1800  var lines =<< trim END
1801    vim9script
1802    const var = ''
1803    var valone = 1234
1804    def MyFunc(arg: string)
1805       valone = 5678
1806    enddef
1807  END
1808  var morelines =<< trim END
1809    var valtwo = 222
1810    export def GetValtwo(): number
1811      return valtwo
1812    enddef
1813  END
1814  writefile(lines + morelines, 'Xreload.vim')
1815  source Xreload.vim
1816  source Xreload.vim
1817  source Xreload.vim
1818
1819  # cannot declare a var twice
1820  lines =<< trim END
1821    vim9script
1822    var valone = 1234
1823    var valone = 5678
1824  END
1825  writefile(lines, 'Xreload.vim')
1826  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1827
1828  delete('Xreload.vim')
1829  delete('Ximport.vim')
1830enddef
1831
1832" if a script is reloaded with a script-local variable that changed its type, a
1833" compiled function using that variable must fail.
1834def Test_script_reload_change_type()
1835  var lines =<< trim END
1836    vim9script noclear
1837    var str = 'string'
1838    def g:GetStr(): string
1839      return str .. 'xxx'
1840    enddef
1841  END
1842  writefile(lines, 'Xreload.vim')
1843  source Xreload.vim
1844  echo g:GetStr()
1845
1846  lines =<< trim END
1847    vim9script noclear
1848    var str = 1234
1849  END
1850  writefile(lines, 'Xreload.vim')
1851  source Xreload.vim
1852  assert_fails('echo g:GetStr()', 'E1150:')
1853
1854  delfunc g:GetStr
1855  delete('Xreload.vim')
1856enddef
1857
1858" Define CallFunc so that the test can be compiled
1859command CallFunc echo 'nop'
1860
1861def Test_script_reload_from_function()
1862  var lines =<< trim END
1863      vim9script
1864
1865      if exists('g:loaded')
1866        finish
1867      endif
1868      g:loaded = 1
1869      delcommand CallFunc
1870      command CallFunc Func()
1871      def Func()
1872        so XreloadFunc.vim
1873        g:didTheFunc = 1
1874      enddef
1875  END
1876  writefile(lines, 'XreloadFunc.vim')
1877  source XreloadFunc.vim
1878  CallFunc
1879  assert_equal(1, g:didTheFunc)
1880
1881  delete('XreloadFunc.vim')
1882  delcommand CallFunc
1883  unlet g:loaded
1884  unlet g:didTheFunc
1885enddef
1886
1887def Test_script_var_shadows_function()
1888  var lines =<< trim END
1889      vim9script
1890      def Func(): number
1891        return 123
1892      enddef
1893      var Func = 1
1894  END
1895  CheckScriptFailure(lines, 'E1041:', 5)
1896enddef
1897
1898def Test_script_var_shadows_command()
1899  var lines =<< trim END
1900      var undo = 1
1901      undo = 2
1902      assert_equal(2, undo)
1903  END
1904  CheckDefAndScriptSuccess(lines)
1905
1906  lines =<< trim END
1907      var undo = 1
1908      undo
1909  END
1910  CheckDefAndScriptFailure(lines, 'E1207:', 2)
1911enddef
1912
1913def s:RetSome(): string
1914  return 'some'
1915enddef
1916
1917" Not exported function that is referenced needs to be accessed by the
1918" script-local name.
1919def Test_vim9script_funcref()
1920  var sortlines =<< trim END
1921      vim9script
1922      def Compare(i1: number, i2: number): number
1923        return i2 - i1
1924      enddef
1925
1926      export def FastSort(): list<number>
1927        return range(5)->sort(Compare)
1928      enddef
1929
1930      export def GetString(arg: string): string
1931        return arg
1932      enddef
1933  END
1934  writefile(sortlines, 'Xsort.vim')
1935
1936  var lines =<< trim END
1937    vim9script
1938    import FastSort from './Xsort.vim'
1939    def Test()
1940      g:result = FastSort()
1941    enddef
1942    Test()
1943
1944    # using a function imported with "as"
1945    import * as anAlias from './Xsort.vim'
1946    assert_equal('yes', anAlias.GetString('yes'))
1947
1948    # using the function from a compiled function
1949    def TestMore(): string
1950      var s = s:anAlias.GetString('foo')
1951      return s .. anAlias.GetString('bar')
1952    enddef
1953    assert_equal('foobar', TestMore())
1954
1955    # error when using a function that isn't exported
1956    assert_fails('anAlias.Compare(1, 2)', 'E1049:')
1957  END
1958  writefile(lines, 'Xscript.vim')
1959
1960  source Xscript.vim
1961  assert_equal([4, 3, 2, 1, 0], g:result)
1962
1963  unlet g:result
1964  delete('Xsort.vim')
1965  delete('Xscript.vim')
1966
1967  var Funcref = function('s:RetSome')
1968  assert_equal('some', Funcref())
1969enddef
1970
1971" Check that when searching for "FilterFunc" it finds the import in the
1972" script where FastFilter() is called from, both as a string and as a direct
1973" function reference.
1974def Test_vim9script_funcref_other_script()
1975  var filterLines =<< trim END
1976    vim9script
1977    export def FilterFunc(idx: number, val: number): bool
1978      return idx % 2 == 1
1979    enddef
1980    export def FastFilter(): list<number>
1981      return range(10)->filter('FilterFunc')
1982    enddef
1983    export def FastFilterDirect(): list<number>
1984      return range(10)->filter(FilterFunc)
1985    enddef
1986  END
1987  writefile(filterLines, 'Xfilter.vim')
1988
1989  var lines =<< trim END
1990    vim9script
1991    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1992    def Test()
1993      var x: list<number> = FastFilter()
1994    enddef
1995    Test()
1996    def TestDirect()
1997      var x: list<number> = FastFilterDirect()
1998    enddef
1999    TestDirect()
2000  END
2001  CheckScriptSuccess(lines)
2002  delete('Xfilter.vim')
2003enddef
2004
2005def Test_vim9script_reload_delfunc()
2006  var first_lines =<< trim END
2007    vim9script
2008    def FuncYes(): string
2009      return 'yes'
2010    enddef
2011  END
2012  var withno_lines =<< trim END
2013    def FuncNo(): string
2014      return 'no'
2015    enddef
2016    def g:DoCheck(no_exists: bool)
2017      assert_equal('yes', FuncYes())
2018      assert_equal('no', FuncNo())
2019    enddef
2020  END
2021  var nono_lines =<< trim END
2022    def g:DoCheck(no_exists: bool)
2023      assert_equal('yes', FuncYes())
2024      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
2025    enddef
2026  END
2027
2028  # FuncNo() is defined
2029  writefile(first_lines + withno_lines, 'Xreloaded.vim')
2030  source Xreloaded.vim
2031  g:DoCheck(true)
2032
2033  # FuncNo() is not redefined
2034  writefile(first_lines + nono_lines, 'Xreloaded.vim')
2035  source Xreloaded.vim
2036  g:DoCheck(false)
2037
2038  # FuncNo() is back
2039  writefile(first_lines + withno_lines, 'Xreloaded.vim')
2040  source Xreloaded.vim
2041  g:DoCheck(false)
2042
2043  delete('Xreloaded.vim')
2044enddef
2045
2046def Test_vim9script_reload_delvar()
2047  # write the script with a script-local variable
2048  var lines =<< trim END
2049    vim9script
2050    var name = 'string'
2051  END
2052  writefile(lines, 'XreloadVar.vim')
2053  source XreloadVar.vim
2054
2055  # now write the script using the same variable locally - works
2056  lines =<< trim END
2057    vim9script
2058    def Func()
2059      var name = 'string'
2060    enddef
2061  END
2062  writefile(lines, 'XreloadVar.vim')
2063  source XreloadVar.vim
2064
2065  delete('XreloadVar.vim')
2066enddef
2067
2068def Test_import_absolute()
2069  var import_lines = [
2070        'vim9script',
2071        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
2072        'def UseExported()',
2073        '  g:imported_abs = exported',
2074        '  exported = 8888',
2075        '  g:imported_after = exported',
2076        'enddef',
2077        'UseExported()',
2078        'g:import_disassembled = execute("disass UseExported")',
2079        ]
2080  writefile(import_lines, 'Ximport_abs.vim')
2081  writefile(s:export_script_lines, 'Xexport_abs.vim')
2082
2083  source Ximport_abs.vim
2084
2085  assert_equal(9876, g:imported_abs)
2086  assert_equal(8888, g:imported_after)
2087  assert_match('<SNR>\d\+_UseExported\_s*' ..
2088          'g:imported_abs = exported\_s*' ..
2089          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2090          '1 STOREG g:imported_abs\_s*' ..
2091          'exported = 8888\_s*' ..
2092          '2 PUSHNR 8888\_s*' ..
2093          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
2094          'g:imported_after = exported\_s*' ..
2095          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
2096          '5 STOREG g:imported_after',
2097        g:import_disassembled)
2098
2099  Undo_export_script_lines()
2100  unlet g:imported_abs
2101  unlet g:import_disassembled
2102
2103  delete('Ximport_abs.vim')
2104  delete('Xexport_abs.vim')
2105enddef
2106
2107def Test_import_rtp()
2108  var import_lines = [
2109        'vim9script',
2110        'import exported from "Xexport_rtp.vim"',
2111        'g:imported_rtp = exported',
2112        ]
2113  writefile(import_lines, 'Ximport_rtp.vim')
2114  mkdir('import', 'p')
2115  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
2116
2117  var save_rtp = &rtp
2118  &rtp = getcwd()
2119  source Ximport_rtp.vim
2120  &rtp = save_rtp
2121
2122  assert_equal(9876, g:imported_rtp)
2123
2124  Undo_export_script_lines()
2125  unlet g:imported_rtp
2126  delete('Ximport_rtp.vim')
2127  delete('import', 'rf')
2128enddef
2129
2130def Test_import_compile_error()
2131  var export_lines = [
2132        'vim9script',
2133        'export def ExpFunc(): string',
2134        '  return notDefined',
2135        'enddef',
2136        ]
2137  writefile(export_lines, 'Xexported.vim')
2138
2139  var import_lines = [
2140        'vim9script',
2141        'import ExpFunc from "./Xexported.vim"',
2142        'def ImpFunc()',
2143        '  echo ExpFunc()',
2144        'enddef',
2145        'defcompile',
2146        ]
2147  writefile(import_lines, 'Ximport.vim')
2148
2149  try
2150    source Ximport.vim
2151  catch /E1001/
2152    # Error should be fore the Xexported.vim file.
2153    assert_match('E1001: Variable not found: notDefined', v:exception)
2154    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
2155  endtry
2156
2157  delete('Xexported.vim')
2158  delete('Ximport.vim')
2159enddef
2160
2161def Test_func_redefine_error()
2162  var lines = [
2163        'vim9script',
2164        'def Func()',
2165        '  eval [][0]',
2166        'enddef',
2167        'Func()',
2168        ]
2169  writefile(lines, 'Xtestscript.vim')
2170
2171  for count in range(3)
2172    try
2173      source Xtestscript.vim
2174    catch /E684/
2175      # function name should contain <SNR> every time
2176      assert_match('E684: list index out of range', v:exception)
2177      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
2178    endtry
2179  endfor
2180
2181  delete('Xtestscript.vim')
2182enddef
2183
2184def Test_func_overrules_import_fails()
2185  var export_lines =<< trim END
2186      vim9script
2187      export def Func()
2188        echo 'imported'
2189      enddef
2190  END
2191  writefile(export_lines, 'XexportedFunc.vim')
2192
2193  var lines =<< trim END
2194    vim9script
2195    import Func from './XexportedFunc.vim'
2196    def Func()
2197      echo 'local to function'
2198    enddef
2199  END
2200  CheckScriptFailure(lines, 'E1073:')
2201
2202  lines =<< trim END
2203    vim9script
2204    import Func from './XexportedFunc.vim'
2205    def Outer()
2206      def Func()
2207        echo 'local to function'
2208      enddef
2209    enddef
2210    defcompile
2211  END
2212  CheckScriptFailure(lines, 'E1073:')
2213
2214  delete('XexportedFunc.vim')
2215enddef
2216
2217def Test_func_redefine_fails()
2218  var lines =<< trim END
2219    vim9script
2220    def Func()
2221      echo 'one'
2222    enddef
2223    def Func()
2224      echo 'two'
2225    enddef
2226  END
2227  CheckScriptFailure(lines, 'E1073:')
2228
2229  lines =<< trim END
2230    vim9script
2231    def Foo(): string
2232      return 'foo'
2233      enddef
2234    def Func()
2235      var  Foo = {-> 'lambda'}
2236    enddef
2237    defcompile
2238  END
2239  CheckScriptFailure(lines, 'E1073:')
2240enddef
2241
2242def Test_fixed_size_list()
2243  # will be allocated as one piece of memory, check that changes work
2244  var l = [1, 2, 3, 4]
2245  l->remove(0)
2246  l->add(5)
2247  l->insert(99, 1)
2248  assert_equal([2, 99, 3, 4, 5], l)
2249enddef
2250
2251def Test_no_insert_xit()
2252  CheckDefExecFailure(['a = 1'], 'E1100:')
2253  CheckDefExecFailure(['c = 1'], 'E1100:')
2254  CheckDefExecFailure(['i = 1'], 'E1100:')
2255  CheckDefExecFailure(['t = 1'], 'E1100:')
2256  CheckDefExecFailure(['x = 1'], 'E1100:')
2257
2258  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
2259  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
2260  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
2261  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
2262  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
2263  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
2264  CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
2265  CheckScriptFailure(['vim9script', 'o'], 'E1100:')
2266  CheckScriptFailure(['vim9script', 't'], 'E1100:')
2267  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
2268  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
2269enddef
2270
2271def IfElse(what: number): string
2272  var res = ''
2273  if what == 1
2274    res = "one"
2275  elseif what == 2
2276    res = "two"
2277  else
2278    res = "three"
2279  endif
2280  return res
2281enddef
2282
2283def Test_if_elseif_else()
2284  assert_equal('one', IfElse(1))
2285  assert_equal('two', IfElse(2))
2286  assert_equal('three', IfElse(3))
2287enddef
2288
2289def Test_if_elseif_else_fails()
2290  CheckDefFailure(['elseif true'], 'E582:')
2291  CheckDefFailure(['else'], 'E581:')
2292  CheckDefFailure(['endif'], 'E580:')
2293  CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
2294  CheckDefFailure(['if true', 'echo 1'], 'E171:')
2295
2296  var lines =<< trim END
2297      var s = ''
2298      if s = ''
2299      endif
2300  END
2301  CheckDefFailure(lines, 'E488:')
2302
2303  lines =<< trim END
2304      var s = ''
2305      if s == ''
2306      elseif s = ''
2307      endif
2308  END
2309  CheckDefFailure(lines, 'E488:')
2310enddef
2311
2312let g:bool_true = v:true
2313let g:bool_false = v:false
2314
2315def Test_if_const_expr()
2316  var res = false
2317  if true ? true : false
2318    res = true
2319  endif
2320  assert_equal(true, res)
2321
2322  g:glob = 2
2323  if false
2324    execute('g:glob = 3')
2325  endif
2326  assert_equal(2, g:glob)
2327  if true
2328    execute('g:glob = 3')
2329  endif
2330  assert_equal(3, g:glob)
2331
2332  res = false
2333  if g:bool_true ? true : false
2334    res = true
2335  endif
2336  assert_equal(true, res)
2337
2338  res = false
2339  if true ? g:bool_true : false
2340    res = true
2341  endif
2342  assert_equal(true, res)
2343
2344  res = false
2345  if true ? true : g:bool_false
2346    res = true
2347  endif
2348  assert_equal(true, res)
2349
2350  res = false
2351  if true ? false : true
2352    res = true
2353  endif
2354  assert_equal(false, res)
2355
2356  res = false
2357  if false ? false : true
2358    res = true
2359  endif
2360  assert_equal(true, res)
2361
2362  res = false
2363  if false ? true : false
2364    res = true
2365  endif
2366  assert_equal(false, res)
2367
2368  res = false
2369  if has('xyz') ? true : false
2370    res = true
2371  endif
2372  assert_equal(false, res)
2373
2374  res = false
2375  if true && true
2376    res = true
2377  endif
2378  assert_equal(true, res)
2379
2380  res = false
2381  if true && false
2382    res = true
2383  endif
2384  assert_equal(false, res)
2385
2386  res = false
2387  if g:bool_true && false
2388    res = true
2389  endif
2390  assert_equal(false, res)
2391
2392  res = false
2393  if true && g:bool_false
2394    res = true
2395  endif
2396  assert_equal(false, res)
2397
2398  res = false
2399  if false && false
2400    res = true
2401  endif
2402  assert_equal(false, res)
2403
2404  res = false
2405  if true || false
2406    res = true
2407  endif
2408  assert_equal(true, res)
2409
2410  res = false
2411  if g:bool_true || false
2412    res = true
2413  endif
2414  assert_equal(true, res)
2415
2416  res = false
2417  if true || g:bool_false
2418    res = true
2419  endif
2420  assert_equal(true, res)
2421
2422  res = false
2423  if false || false
2424    res = true
2425  endif
2426  assert_equal(false, res)
2427
2428  # with constant "false" expression may be invalid so long as the syntax is OK
2429  if false | eval 1 + 2 | endif
2430  if false | eval burp + 234 | endif
2431  if false | echo burp 234 'asd' | endif
2432  if false
2433    burp
2434  endif
2435
2436  # expression with line breaks skipped
2437  if false
2438      ('aaa'
2439      .. 'bbb'
2440      .. 'ccc'
2441      )->setline(1)
2442  endif
2443enddef
2444
2445def Test_if_const_expr_fails()
2446  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
2447  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
2448  CheckDefFailure(["if has('aaa'"], 'E110:')
2449  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
2450enddef
2451
2452def RunNested(i: number): number
2453  var x: number = 0
2454  if i % 2
2455    if 1
2456      # comment
2457    else
2458      # comment
2459    endif
2460    x += 1
2461  else
2462    x += 1000
2463  endif
2464  return x
2465enddef
2466
2467def Test_nested_if()
2468  assert_equal(1, RunNested(1))
2469  assert_equal(1000, RunNested(2))
2470enddef
2471
2472def Test_execute_cmd()
2473  # missing argument is ignored
2474  execute
2475  execute # comment
2476
2477  new
2478  setline(1, 'default')
2479  execute 'setline(1, "execute-string")'
2480  assert_equal('execute-string', getline(1))
2481
2482  execute "setline(1, 'execute-string')"
2483  assert_equal('execute-string', getline(1))
2484
2485  var cmd1 = 'setline(1,'
2486  var cmd2 = '"execute-var")'
2487  execute cmd1 cmd2 # comment
2488  assert_equal('execute-var', getline(1))
2489
2490  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
2491  assert_equal('execute-var-string', getline(1))
2492
2493  var cmd_first = 'call '
2494  var cmd_last = 'setline(1, "execute-var-var")'
2495  execute cmd_first .. cmd_last
2496  assert_equal('execute-var-var', getline(1))
2497  bwipe!
2498
2499  var n = true
2500  execute 'echomsg' (n ? '"true"' : '"no"')
2501  assert_match('^true$', Screenline(&lines))
2502
2503  echomsg [1, 2, 3] {a: 1, b: 2}
2504  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
2505
2506  CheckDefFailure(['execute xxx'], 'E1001:', 1)
2507  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
2508  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
2509enddef
2510
2511def Test_execute_cmd_vimscript()
2512  # only checks line continuation
2513  var lines =<< trim END
2514      vim9script
2515      execute 'g:someVar'
2516                .. ' = ' ..
2517                   '28'
2518      assert_equal(28, g:someVar)
2519      unlet g:someVar
2520  END
2521  CheckScriptSuccess(lines)
2522enddef
2523
2524def Test_echo_cmd()
2525  echo 'some' # comment
2526  echon 'thing'
2527  assert_match('^something$', Screenline(&lines))
2528
2529  echo "some" # comment
2530  echon "thing"
2531  assert_match('^something$', Screenline(&lines))
2532
2533  var str1 = 'some'
2534  var str2 = 'more'
2535  echo str1 str2
2536  assert_match('^some more$', Screenline(&lines))
2537
2538  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
2539enddef
2540
2541def Test_echomsg_cmd()
2542  echomsg 'some' 'more' # comment
2543  assert_match('^some more$', Screenline(&lines))
2544  echo 'clear'
2545  :1messages
2546  assert_match('^some more$', Screenline(&lines))
2547
2548  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
2549enddef
2550
2551def Test_echomsg_cmd_vimscript()
2552  # only checks line continuation
2553  var lines =<< trim END
2554      vim9script
2555      echomsg 'here'
2556                .. ' is ' ..
2557                   'a message'
2558      assert_match('^here is a message$', Screenline(&lines))
2559  END
2560  CheckScriptSuccess(lines)
2561enddef
2562
2563def Test_echoerr_cmd()
2564  var local = 'local'
2565  try
2566    echoerr 'something' local 'wrong' # comment
2567  catch
2568    assert_match('something local wrong', v:exception)
2569  endtry
2570enddef
2571
2572def Test_echoerr_cmd_vimscript()
2573  # only checks line continuation
2574  var lines =<< trim END
2575      vim9script
2576      try
2577        echoerr 'this'
2578                .. ' is ' ..
2579                   'wrong'
2580      catch
2581        assert_match('this is wrong', v:exception)
2582      endtry
2583  END
2584  CheckScriptSuccess(lines)
2585enddef
2586
2587def Test_echoconsole_cmd()
2588  var local = 'local'
2589  echoconsole 'something' local # comment
2590  # output goes anywhere
2591enddef
2592
2593def Test_for_outside_of_function()
2594  var lines =<< trim END
2595    vim9script
2596    new
2597    for var in range(0, 3)
2598      append(line('$'), var)
2599    endfor
2600    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
2601    bwipe!
2602
2603    var result = ''
2604    for i in [1, 2, 3]
2605      var loop = ' loop ' .. i
2606      result ..= loop
2607    endfor
2608    assert_equal(' loop 1 loop 2 loop 3', result)
2609  END
2610  writefile(lines, 'Xvim9for.vim')
2611  source Xvim9for.vim
2612  delete('Xvim9for.vim')
2613enddef
2614
2615def Test_for_skipped_block()
2616  # test skipped blocks at outside of function
2617  var lines =<< trim END
2618    var result = []
2619    if true
2620      for n in [1, 2]
2621        result += [n]
2622      endfor
2623    else
2624      for n in [3, 4]
2625        result += [n]
2626      endfor
2627    endif
2628    assert_equal([1, 2], result)
2629
2630    result = []
2631    if false
2632      for n in [1, 2]
2633        result += [n]
2634      endfor
2635    else
2636      for n in [3, 4]
2637        result += [n]
2638      endfor
2639    endif
2640    assert_equal([3, 4], result)
2641  END
2642  CheckDefAndScriptSuccess(lines)
2643
2644  # test skipped blocks at inside of function
2645  lines =<< trim END
2646    def DefTrue()
2647      var result = []
2648      if true
2649        for n in [1, 2]
2650          result += [n]
2651        endfor
2652      else
2653        for n in [3, 4]
2654          result += [n]
2655        endfor
2656      endif
2657      assert_equal([1, 2], result)
2658    enddef
2659    DefTrue()
2660
2661    def DefFalse()
2662      var result = []
2663      if false
2664        for n in [1, 2]
2665          result += [n]
2666        endfor
2667      else
2668        for n in [3, 4]
2669          result += [n]
2670        endfor
2671      endif
2672      assert_equal([3, 4], result)
2673    enddef
2674    DefFalse()
2675  END
2676  CheckDefAndScriptSuccess(lines)
2677enddef
2678
2679def Test_for_loop()
2680  var lines =<< trim END
2681      var result = ''
2682      for cnt in range(7)
2683        if cnt == 4
2684          break
2685        endif
2686        if cnt == 2
2687          continue
2688        endif
2689        result ..= cnt .. '_'
2690      endfor
2691      assert_equal('0_1_3_', result)
2692
2693      var concat = ''
2694      for str in eval('["one", "two"]')
2695        concat ..= str
2696      endfor
2697      assert_equal('onetwo', concat)
2698
2699      var total = 0
2700      for nr in
2701          [1, 2, 3]
2702        total += nr
2703      endfor
2704      assert_equal(6, total)
2705
2706      total = 0
2707      for nr
2708        in [1, 2, 3]
2709        total += nr
2710      endfor
2711      assert_equal(6, total)
2712
2713      total = 0
2714      for nr
2715        in
2716        [1, 2, 3]
2717        total += nr
2718      endfor
2719      assert_equal(6, total)
2720
2721      # with type
2722      total = 0
2723      for n: number in [1, 2, 3]
2724        total += n
2725      endfor
2726      assert_equal(6, total)
2727
2728      var chars = ''
2729      for s: string in 'foobar'
2730        chars ..= s
2731      endfor
2732      assert_equal('foobar', chars)
2733
2734      chars = ''
2735      for x: string in {a: 'a', b: 'b'}->values()
2736        chars ..= x
2737      endfor
2738      assert_equal('ab', chars)
2739
2740      # unpack with type
2741      var res = ''
2742      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
2743        res ..= n .. s
2744      endfor
2745      assert_equal('1a2b', res)
2746
2747      # unpack with one var
2748      var reslist = []
2749      for [x] in [['aaa'], ['bbb']]
2750        reslist->add(x)
2751      endfor
2752      assert_equal(['aaa', 'bbb'], reslist)
2753
2754      # loop over string
2755      res = ''
2756      for c in 'aéc̀d'
2757        res ..= c .. '-'
2758      endfor
2759      assert_equal('a-é-c̀-d-', res)
2760
2761      res = ''
2762      for c in ''
2763        res ..= c .. '-'
2764      endfor
2765      assert_equal('', res)
2766
2767      res = ''
2768      for c in test_null_string()
2769        res ..= c .. '-'
2770      endfor
2771      assert_equal('', res)
2772
2773      var foo: list<dict<any>> = [
2774              {a: 'Cat'}
2775            ]
2776      for dd in foo
2777        dd.counter = 12
2778      endfor
2779      assert_equal([{a: 'Cat', counter: 12}], foo)
2780
2781      reslist = []
2782      for _ in range(3)
2783        reslist->add('x')
2784      endfor
2785      assert_equal(['x', 'x', 'x'], reslist)
2786  END
2787  CheckDefAndScriptSuccess(lines)
2788enddef
2789
2790def Test_for_loop_with_closure()
2791  var lines =<< trim END
2792      var flist: list<func>
2793      for i in range(5)
2794        var inloop = i
2795        flist[i] = () => inloop
2796      endfor
2797      for i in range(5)
2798        assert_equal(4, flist[i]())
2799      endfor
2800  END
2801  CheckDefAndScriptSuccess(lines)
2802
2803  lines =<< trim END
2804      var flist: list<func>
2805      for i in range(5)
2806        var inloop = i
2807        flist[i] = () => {
2808              return inloop
2809            }
2810      endfor
2811      for i in range(5)
2812        assert_equal(4, flist[i]())
2813      endfor
2814  END
2815  CheckDefAndScriptSuccess(lines)
2816enddef
2817
2818def Test_for_loop_fails()
2819  CheckDefAndScriptFailure2(['for '], 'E1097:', 'E690:')
2820  CheckDefAndScriptFailure2(['for x'], 'E1097:', 'E690:')
2821  CheckDefAndScriptFailure2(['for x in'], 'E1097:', 'E15:')
2822  CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
2823  CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
2824  CheckDefAndScriptFailure2(['var x = 5', 'for x in range(5)', 'endfor'], 'E1017:', 'E1041:')
2825  CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
2826  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2827  delfunc! g:Func
2828  CheckDefFailure(['for i in xxx'], 'E1001:')
2829  CheckDefFailure(['endfor'], 'E588:')
2830  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2831
2832  # wrong type detected at compile time
2833  CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2834
2835  # wrong type detected at runtime
2836  g:adict = {a: 1}
2837  CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2838  unlet g:adict
2839
2840  var lines =<< trim END
2841      var d: list<dict<any>> = [{a: 0}]
2842      for e in d
2843        e = {a: 0, b: ''}
2844      endfor
2845  END
2846  CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
2847
2848  lines =<< trim END
2849      for nr: number in ['foo']
2850      endfor
2851  END
2852  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
2853
2854  lines =<< trim END
2855      for n : number in [1, 2]
2856        echo n
2857      endfor
2858  END
2859  CheckDefAndScriptFailure(lines, 'E1059:', 1)
2860
2861  lines =<< trim END
2862      var d: dict<number> = {a: 1, b: 2}
2863      for [k: job, v: job] in d->items()
2864        echo k v
2865      endfor
2866  END
2867  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
2868enddef
2869
2870def Test_for_loop_script_var()
2871  # cannot use s:var in a :def function
2872  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2873
2874  # can use s:var in Vim9 script, with or without s:
2875  var lines =<< trim END
2876    vim9script
2877    var total = 0
2878    for s:var in [1, 2, 3]
2879      total += s:var
2880    endfor
2881    assert_equal(6, total)
2882
2883    total = 0
2884    for var in [1, 2, 3]
2885      total += var
2886    endfor
2887    assert_equal(6, total)
2888  END
2889enddef
2890
2891def Test_for_loop_unpack()
2892  var lines =<< trim END
2893      var result = []
2894      for [v1, v2] in [[1, 2], [3, 4]]
2895        result->add(v1)
2896        result->add(v2)
2897      endfor
2898      assert_equal([1, 2, 3, 4], result)
2899
2900      result = []
2901      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2902        result->add(v1)
2903        result->add(v2)
2904        result->add(v3)
2905      endfor
2906      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2907
2908      result = []
2909      for [&ts, &sw] in [[1, 2], [3, 4]]
2910        result->add(&ts)
2911        result->add(&sw)
2912      endfor
2913      assert_equal([1, 2, 3, 4], result)
2914
2915      var slist: list<string>
2916      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2917        slist->add($LOOPVAR)
2918        slist->add(@r)
2919        slist->add(v:errmsg)
2920      endfor
2921      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2922
2923      slist = []
2924      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2925        slist->add(g:globalvar)
2926        slist->add(b:bufvar)
2927        slist->add(w:winvar)
2928        slist->add(t:tabvar)
2929      endfor
2930      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2931      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2932
2933      var res = []
2934      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
2935        res->add(n)
2936      endfor
2937      assert_equal([2, 5], res)
2938  END
2939  CheckDefAndScriptSuccess(lines)
2940
2941  lines =<< trim END
2942      for [v1, v2] in [[1, 2, 3], [3, 4]]
2943        echo v1 v2
2944      endfor
2945  END
2946  CheckDefExecFailure(lines, 'E710:', 1)
2947
2948  lines =<< trim END
2949      for [v1, v2] in [[1], [3, 4]]
2950        echo v1 v2
2951      endfor
2952  END
2953  CheckDefExecFailure(lines, 'E711:', 1)
2954
2955  lines =<< trim END
2956      for [v1, v1] in [[1, 2], [3, 4]]
2957        echo v1
2958      endfor
2959  END
2960  CheckDefExecFailure(lines, 'E1017:', 1)
2961enddef
2962
2963def Test_for_loop_with_try_continue()
2964  var lines =<< trim END
2965      var looped = 0
2966      var cleanup = 0
2967      for i in range(3)
2968        looped += 1
2969        try
2970          eval [][0]
2971        catch
2972          continue
2973        finally
2974          cleanup += 1
2975        endtry
2976      endfor
2977      assert_equal(3, looped)
2978      assert_equal(3, cleanup)
2979  END
2980  CheckDefAndScriptSuccess(lines)
2981enddef
2982
2983def Test_while_skipped_block()
2984  # test skipped blocks at outside of function
2985  var lines =<< trim END
2986    var result = []
2987    var n = 0
2988    if true
2989      n = 1
2990      while n < 3
2991        result += [n]
2992        n += 1
2993      endwhile
2994    else
2995      n = 3
2996      while n < 5
2997        result += [n]
2998        n += 1
2999      endwhile
3000    endif
3001    assert_equal([1, 2], result)
3002
3003    result = []
3004    if false
3005      n = 1
3006      while n < 3
3007        result += [n]
3008        n += 1
3009      endwhile
3010    else
3011      n = 3
3012      while n < 5
3013        result += [n]
3014        n += 1
3015      endwhile
3016    endif
3017    assert_equal([3, 4], result)
3018  END
3019  CheckDefAndScriptSuccess(lines)
3020
3021  # test skipped blocks at inside of function
3022  lines =<< trim END
3023    def DefTrue()
3024      var result = []
3025      var n = 0
3026      if true
3027        n = 1
3028        while n < 3
3029          result += [n]
3030          n += 1
3031        endwhile
3032      else
3033        n = 3
3034        while n < 5
3035          result += [n]
3036          n += 1
3037        endwhile
3038      endif
3039      assert_equal([1, 2], result)
3040    enddef
3041    DefTrue()
3042
3043    def DefFalse()
3044      var result = []
3045      var n = 0
3046      if false
3047        n = 1
3048        while n < 3
3049          result += [n]
3050          n += 1
3051        endwhile
3052      else
3053        n = 3
3054        while n < 5
3055          result += [n]
3056          n += 1
3057        endwhile
3058      endif
3059      assert_equal([3, 4], result)
3060    enddef
3061    DefFalse()
3062  END
3063  CheckDefAndScriptSuccess(lines)
3064enddef
3065
3066def Test_while_loop()
3067  var result = ''
3068  var cnt = 0
3069  while cnt < 555
3070    if cnt == 3
3071      break
3072    endif
3073    cnt += 1
3074    if cnt == 2
3075      continue
3076    endif
3077    result ..= cnt .. '_'
3078  endwhile
3079  assert_equal('1_3_', result)
3080
3081  var s = ''
3082  while s == 'x' # {comment}
3083  endwhile
3084enddef
3085
3086def Test_while_loop_fails()
3087  CheckDefFailure(['while xxx'], 'E1001:')
3088  CheckDefFailure(['endwhile'], 'E588:')
3089  CheckDefFailure(['continue'], 'E586:')
3090  CheckDefFailure(['if true', 'continue'], 'E586:')
3091  CheckDefFailure(['break'], 'E587:')
3092  CheckDefFailure(['if true', 'break'], 'E587:')
3093  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
3094
3095  var lines =<< trim END
3096      var s = ''
3097      while s = ''
3098      endwhile
3099  END
3100  CheckDefFailure(lines, 'E488:')
3101enddef
3102
3103def Test_interrupt_loop()
3104  var caught = false
3105  var x = 0
3106  try
3107    while 1
3108      x += 1
3109      if x == 100
3110        feedkeys("\<C-C>", 'Lt')
3111      endif
3112    endwhile
3113  catch
3114    caught = true
3115    assert_equal(100, x)
3116  endtry
3117  assert_true(caught, 'should have caught an exception')
3118  # consume the CTRL-C
3119  getchar(0)
3120enddef
3121
3122def Test_automatic_line_continuation()
3123  var mylist = [
3124      'one',
3125      'two',
3126      'three',
3127      ] # comment
3128  assert_equal(['one', 'two', 'three'], mylist)
3129
3130  var mydict = {
3131      ['one']: 1,
3132      ['two']: 2,
3133      ['three']:
3134          3,
3135      } # comment
3136  assert_equal({one: 1, two: 2, three: 3}, mydict)
3137  mydict = {
3138      one: 1,  # comment
3139      two:     # comment
3140           2,  # comment
3141      three: 3 # comment
3142      }
3143  assert_equal({one: 1, two: 2, three: 3}, mydict)
3144  mydict = {
3145      one: 1,
3146      two:
3147           2,
3148      three: 3
3149      }
3150  assert_equal({one: 1, two: 2, three: 3}, mydict)
3151
3152  assert_equal(
3153        ['one', 'two', 'three'],
3154        split('one two three')
3155        )
3156enddef
3157
3158def Test_vim9_comment()
3159  CheckScriptSuccess([
3160      'vim9script',
3161      '# something',
3162      '#something',
3163      '#{something',
3164      ])
3165
3166  split Xfile
3167  CheckScriptSuccess([
3168      'vim9script',
3169      'edit #something',
3170      ])
3171  CheckScriptSuccess([
3172      'vim9script',
3173      'edit #{something',
3174      ])
3175  close
3176
3177  CheckScriptFailure([
3178      'vim9script',
3179      ':# something',
3180      ], 'E488:')
3181  CheckScriptFailure([
3182      '# something',
3183      ], 'E488:')
3184  CheckScriptFailure([
3185      ':# something',
3186      ], 'E488:')
3187
3188  { # block start
3189  } # block end
3190  CheckDefFailure([
3191      '{# comment',
3192      ], 'E488:')
3193  CheckDefFailure([
3194      '{',
3195      '}# comment',
3196      ], 'E488:')
3197
3198  echo "yes" # comment
3199  CheckDefFailure([
3200      'echo "yes"# comment',
3201      ], 'E488:')
3202  CheckScriptSuccess([
3203      'vim9script',
3204      'echo "yes" # something',
3205      ])
3206  CheckScriptFailure([
3207      'vim9script',
3208      'echo "yes"# something',
3209      ], 'E121:')
3210  CheckScriptFailure([
3211      'vim9script',
3212      'echo# something',
3213      ], 'E1144:')
3214  CheckScriptFailure([
3215      'echo "yes" # something',
3216      ], 'E121:')
3217
3218  exe "echo" # comment
3219  CheckDefFailure([
3220      'exe "echo"# comment',
3221      ], 'E488:')
3222  CheckScriptSuccess([
3223      'vim9script',
3224      'exe "echo" # something',
3225      ])
3226  CheckScriptFailure([
3227      'vim9script',
3228      'exe "echo"# something',
3229      ], 'E121:')
3230  CheckScriptFailure([
3231      'vim9script',
3232      'exe# something',
3233      ], 'E1144:')
3234  CheckScriptFailure([
3235      'exe "echo" # something',
3236      ], 'E121:')
3237
3238  CheckDefFailure([
3239      'try# comment',
3240      '  echo "yes"',
3241      'catch',
3242      'endtry',
3243      ], 'E1144:')
3244  CheckScriptFailure([
3245      'vim9script',
3246      'try# comment',
3247      'echo "yes"',
3248      ], 'E1144:')
3249  CheckDefFailure([
3250      'try',
3251      '  throw#comment',
3252      'catch',
3253      'endtry',
3254      ], 'E1144:')
3255  CheckDefFailure([
3256      'try',
3257      '  throw "yes"#comment',
3258      'catch',
3259      'endtry',
3260      ], 'E488:')
3261  CheckDefFailure([
3262      'try',
3263      '  echo "yes"',
3264      'catch# comment',
3265      'endtry',
3266      ], 'E1144:')
3267  CheckScriptFailure([
3268      'vim9script',
3269      'try',
3270      '  echo "yes"',
3271      'catch# comment',
3272      'endtry',
3273      ], 'E1144:')
3274  CheckDefFailure([
3275      'try',
3276      '  echo "yes"',
3277      'catch /pat/# comment',
3278      'endtry',
3279      ], 'E488:')
3280  CheckDefFailure([
3281      'try',
3282      'echo "yes"',
3283      'catch',
3284      'endtry# comment',
3285      ], 'E1144:')
3286  CheckScriptFailure([
3287      'vim9script',
3288      'try',
3289      '  echo "yes"',
3290      'catch',
3291      'endtry# comment',
3292      ], 'E1144:')
3293
3294  CheckScriptSuccess([
3295      'vim9script',
3296      'hi # comment',
3297      ])
3298  CheckScriptFailure([
3299      'vim9script',
3300      'hi# comment',
3301      ], 'E1144:')
3302  CheckScriptSuccess([
3303      'vim9script',
3304      'hi Search # comment',
3305      ])
3306  CheckScriptFailure([
3307      'vim9script',
3308      'hi Search# comment',
3309      ], 'E416:')
3310  CheckScriptSuccess([
3311      'vim9script',
3312      'hi link This Search # comment',
3313      ])
3314  CheckScriptFailure([
3315      'vim9script',
3316      'hi link This That# comment',
3317      ], 'E413:')
3318  CheckScriptSuccess([
3319      'vim9script',
3320      'hi clear This # comment',
3321      'hi clear # comment',
3322      ])
3323  # not tested, because it doesn't give an error but a warning:
3324  # hi clear This# comment',
3325  CheckScriptFailure([
3326      'vim9script',
3327      'hi clear# comment',
3328      ], 'E416:')
3329
3330  CheckScriptSuccess([
3331      'vim9script',
3332      'hi Group term=bold',
3333      'match Group /todo/ # comment',
3334      ])
3335  CheckScriptFailure([
3336      'vim9script',
3337      'hi Group term=bold',
3338      'match Group /todo/# comment',
3339      ], 'E488:')
3340  CheckScriptSuccess([
3341      'vim9script',
3342      'match # comment',
3343      ])
3344  CheckScriptFailure([
3345      'vim9script',
3346      'match# comment',
3347      ], 'E1144:')
3348  CheckScriptSuccess([
3349      'vim9script',
3350      'match none # comment',
3351      ])
3352  CheckScriptFailure([
3353      'vim9script',
3354      'match none# comment',
3355      ], 'E475:')
3356
3357  CheckScriptSuccess([
3358      'vim9script',
3359      'menutrans clear # comment',
3360      ])
3361  CheckScriptFailure([
3362      'vim9script',
3363      'menutrans clear# comment text',
3364      ], 'E474:')
3365
3366  CheckScriptSuccess([
3367      'vim9script',
3368      'syntax clear # comment',
3369      ])
3370  CheckScriptFailure([
3371      'vim9script',
3372      'syntax clear# comment text',
3373      ], 'E28:')
3374  CheckScriptSuccess([
3375      'vim9script',
3376      'syntax keyword Word some',
3377      'syntax clear Word # comment',
3378      ])
3379  CheckScriptFailure([
3380      'vim9script',
3381      'syntax keyword Word some',
3382      'syntax clear Word# comment text',
3383      ], 'E28:')
3384
3385  CheckScriptSuccess([
3386      'vim9script',
3387      'syntax list # comment',
3388      ])
3389  CheckScriptFailure([
3390      'vim9script',
3391      'syntax list# comment text',
3392      ], 'E28:')
3393
3394  CheckScriptSuccess([
3395      'vim9script',
3396      'syntax match Word /pat/ oneline # comment',
3397      ])
3398  CheckScriptFailure([
3399      'vim9script',
3400      'syntax match Word /pat/ oneline# comment',
3401      ], 'E475:')
3402
3403  CheckScriptSuccess([
3404      'vim9script',
3405      'syntax keyword Word word # comm[ent',
3406      ])
3407  CheckScriptFailure([
3408      'vim9script',
3409      'syntax keyword Word word# comm[ent',
3410      ], 'E789:')
3411
3412  CheckScriptSuccess([
3413      'vim9script',
3414      'syntax match Word /pat/ # comment',
3415      ])
3416  CheckScriptFailure([
3417      'vim9script',
3418      'syntax match Word /pat/# comment',
3419      ], 'E402:')
3420
3421  CheckScriptSuccess([
3422      'vim9script',
3423      'syntax match Word /pat/ contains=Something # comment',
3424      ])
3425  CheckScriptFailure([
3426      'vim9script',
3427      'syntax match Word /pat/ contains=Something# comment',
3428      ], 'E475:')
3429  CheckScriptFailure([
3430      'vim9script',
3431      'syntax match Word /pat/ contains= # comment',
3432      ], 'E406:')
3433  CheckScriptFailure([
3434      'vim9script',
3435      'syntax match Word /pat/ contains=# comment',
3436      ], 'E475:')
3437
3438  CheckScriptSuccess([
3439      'vim9script',
3440      'syntax region Word start=/pat/ end=/pat/ # comment',
3441      ])
3442  CheckScriptFailure([
3443      'vim9script',
3444      'syntax region Word start=/pat/ end=/pat/# comment',
3445      ], 'E402:')
3446
3447  CheckScriptSuccess([
3448      'vim9script',
3449      'syntax sync # comment',
3450      ])
3451  CheckScriptFailure([
3452      'vim9script',
3453      'syntax sync# comment',
3454      ], 'E404:')
3455  CheckScriptSuccess([
3456      'vim9script',
3457      'syntax sync ccomment # comment',
3458      ])
3459  CheckScriptFailure([
3460      'vim9script',
3461      'syntax sync ccomment# comment',
3462      ], 'E404:')
3463
3464  CheckScriptSuccess([
3465      'vim9script',
3466      'syntax cluster Some contains=Word # comment',
3467      ])
3468  CheckScriptFailure([
3469      'vim9script',
3470      'syntax cluster Some contains=Word# comment',
3471      ], 'E475:')
3472
3473  CheckScriptSuccess([
3474      'vim9script',
3475      'command Echo echo # comment',
3476      'command Echo # comment',
3477      'delcommand Echo',
3478      ])
3479  CheckScriptFailure([
3480      'vim9script',
3481      'command Echo echo# comment',
3482      'Echo',
3483      ], 'E1144:')
3484  delcommand Echo
3485
3486  var curdir = getcwd()
3487  CheckScriptSuccess([
3488      'command Echo cd " comment',
3489      'Echo',
3490      'delcommand Echo',
3491      ])
3492  CheckScriptSuccess([
3493      'vim9script',
3494      'command Echo cd # comment',
3495      'Echo',
3496      'delcommand Echo',
3497      ])
3498  CheckScriptFailure([
3499      'vim9script',
3500      'command Echo cd " comment',
3501      'Echo',
3502      ], 'E344:')
3503  delcommand Echo
3504  chdir(curdir)
3505
3506  CheckScriptFailure([
3507      'vim9script',
3508      'command Echo# comment',
3509      ], 'E182:')
3510  CheckScriptFailure([
3511      'vim9script',
3512      'command Echo echo',
3513      'command Echo# comment',
3514      ], 'E182:')
3515  delcommand Echo
3516
3517  CheckScriptSuccess([
3518      'vim9script',
3519      'function # comment',
3520      ])
3521  CheckScriptFailure([
3522      'vim9script',
3523      'function " comment',
3524      ], 'E129:')
3525  CheckScriptFailure([
3526      'vim9script',
3527      'function# comment',
3528      ], 'E1144:')
3529  CheckScriptSuccess([
3530      'vim9script',
3531      'function CheckScriptSuccess # comment',
3532      ])
3533  CheckScriptFailure([
3534      'vim9script',
3535      'function CheckScriptSuccess# comment',
3536      ], 'E488:')
3537
3538  CheckScriptSuccess([
3539      'vim9script',
3540      'func g:DeleteMeA()',
3541      'endfunc',
3542      'delfunction g:DeleteMeA # comment',
3543      ])
3544  CheckScriptFailure([
3545      'vim9script',
3546      'func g:DeleteMeB()',
3547      'endfunc',
3548      'delfunction g:DeleteMeB# comment',
3549      ], 'E488:')
3550
3551  CheckScriptSuccess([
3552      'vim9script',
3553      'call execute("ls") # comment',
3554      ])
3555  CheckScriptFailure([
3556      'vim9script',
3557      'call execute("ls")# comment',
3558      ], 'E488:')
3559
3560  CheckScriptFailure([
3561      'def Test() " comment',
3562      'enddef',
3563      ], 'E488:')
3564  CheckScriptFailure([
3565      'vim9script',
3566      'def Test() " comment',
3567      'enddef',
3568      ], 'E488:')
3569
3570  CheckScriptSuccess([
3571      'func Test() " comment',
3572      'endfunc',
3573      'delfunc Test',
3574      ])
3575  CheckScriptSuccess([
3576      'vim9script',
3577      'func Test() " comment',
3578      'endfunc',
3579      ])
3580
3581  CheckScriptSuccess([
3582      'def Test() # comment',
3583      'enddef',
3584      ])
3585  CheckScriptFailure([
3586      'func Test() # comment',
3587      'endfunc',
3588      ], 'E488:')
3589
3590  var lines =<< trim END
3591      vim9script
3592      syn region Text
3593      \ start='foo'
3594      #\ comment
3595      \ end='bar'
3596      syn region Text start='foo'
3597      #\ comment
3598      \ end='bar'
3599  END
3600  CheckScriptSuccess(lines)
3601
3602  lines =<< trim END
3603      vim9script
3604      syn region Text
3605      \ start='foo'
3606      "\ comment
3607      \ end='bar'
3608  END
3609  CheckScriptFailure(lines, 'E399:')
3610enddef
3611
3612def Test_vim9_comment_gui()
3613  CheckCanRunGui
3614
3615  CheckScriptFailure([
3616      'vim9script',
3617      'gui#comment'
3618      ], 'E1144:')
3619  CheckScriptFailure([
3620      'vim9script',
3621      'gui -f#comment'
3622      ], 'E194:')
3623enddef
3624
3625def Test_vim9_comment_not_compiled()
3626  au TabEnter *.vim g:entered = 1
3627  au TabEnter *.x g:entered = 2
3628
3629  edit test.vim
3630  doautocmd TabEnter #comment
3631  assert_equal(1, g:entered)
3632
3633  doautocmd TabEnter f.x
3634  assert_equal(2, g:entered)
3635
3636  g:entered = 0
3637  doautocmd TabEnter f.x #comment
3638  assert_equal(2, g:entered)
3639
3640  assert_fails('doautocmd Syntax#comment', 'E216:')
3641
3642  au! TabEnter
3643  unlet g:entered
3644
3645  CheckScriptSuccess([
3646      'vim9script',
3647      'g:var = 123',
3648      'b:var = 456',
3649      'w:var = 777',
3650      't:var = 888',
3651      'unlet g:var w:var # something',
3652      ])
3653
3654  CheckScriptFailure([
3655      'vim9script',
3656      'let var = 123',
3657      ], 'E1126: Cannot use :let in Vim9 script')
3658
3659  CheckScriptFailure([
3660      'vim9script',
3661      'var g:var = 123',
3662      ], 'E1016: Cannot declare a global variable:')
3663
3664  CheckScriptFailure([
3665      'vim9script',
3666      'var b:var = 123',
3667      ], 'E1016: Cannot declare a buffer variable:')
3668
3669  CheckScriptFailure([
3670      'vim9script',
3671      'var w:var = 123',
3672      ], 'E1016: Cannot declare a window variable:')
3673
3674  CheckScriptFailure([
3675      'vim9script',
3676      'var t:var = 123',
3677      ], 'E1016: Cannot declare a tab variable:')
3678
3679  CheckScriptFailure([
3680      'vim9script',
3681      'var v:version = 123',
3682      ], 'E1016: Cannot declare a v: variable:')
3683
3684  CheckScriptFailure([
3685      'vim9script',
3686      'var $VARIABLE = "text"',
3687      ], 'E1016: Cannot declare an environment variable:')
3688
3689  CheckScriptFailure([
3690      'vim9script',
3691      'g:var = 123',
3692      'unlet g:var# comment1',
3693      ], 'E108:')
3694
3695  CheckScriptFailure([
3696      'let g:var = 123',
3697      'unlet g:var # something',
3698      ], 'E488:')
3699
3700  CheckScriptSuccess([
3701      'vim9script',
3702      'if 1 # comment2',
3703      '  echo "yes"',
3704      'elseif 2 #comment',
3705      '  echo "no"',
3706      'endif',
3707      ])
3708
3709  CheckScriptFailure([
3710      'vim9script',
3711      'if 1# comment3',
3712      '  echo "yes"',
3713      'endif',
3714      ], 'E488:')
3715
3716  CheckScriptFailure([
3717      'vim9script',
3718      'if 0 # comment4',
3719      '  echo "yes"',
3720      'elseif 2#comment',
3721      '  echo "no"',
3722      'endif',
3723      ], 'E488:')
3724
3725  CheckScriptSuccess([
3726      'vim9script',
3727      'var v = 1 # comment5',
3728      ])
3729
3730  CheckScriptFailure([
3731      'vim9script',
3732      'var v = 1# comment6',
3733      ], 'E488:')
3734
3735  CheckScriptSuccess([
3736      'vim9script',
3737      'new'
3738      'setline(1, ["# define pat", "last"])',
3739      ':$',
3740      'dsearch /pat/ #comment',
3741      'bwipe!',
3742      ])
3743
3744  CheckScriptFailure([
3745      'vim9script',
3746      'new'
3747      'setline(1, ["# define pat", "last"])',
3748      ':$',
3749      'dsearch /pat/#comment',
3750      'bwipe!',
3751      ], 'E488:')
3752
3753  CheckScriptFailure([
3754      'vim9script',
3755      'func! SomeFunc()',
3756      ], 'E477:')
3757enddef
3758
3759def Test_finish()
3760  var lines =<< trim END
3761    vim9script
3762    g:res = 'one'
3763    if v:false | finish | endif
3764    g:res = 'two'
3765    finish
3766    g:res = 'three'
3767  END
3768  writefile(lines, 'Xfinished')
3769  source Xfinished
3770  assert_equal('two', g:res)
3771
3772  unlet g:res
3773  delete('Xfinished')
3774enddef
3775
3776def Test_forward_declaration()
3777  var lines =<< trim END
3778    vim9script
3779    def GetValue(): string
3780      return theVal
3781    enddef
3782    var theVal = 'something'
3783    g:initVal = GetValue()
3784    theVal = 'else'
3785    g:laterVal = GetValue()
3786  END
3787  writefile(lines, 'Xforward')
3788  source Xforward
3789  assert_equal('something', g:initVal)
3790  assert_equal('else', g:laterVal)
3791
3792  unlet g:initVal
3793  unlet g:laterVal
3794  delete('Xforward')
3795enddef
3796
3797def Test_source_vim9_from_legacy()
3798  var vim9_lines =<< trim END
3799    vim9script
3800    var local = 'local'
3801    g:global = 'global'
3802    export var exported = 'exported'
3803    export def GetText(): string
3804       return 'text'
3805    enddef
3806  END
3807  writefile(vim9_lines, 'Xvim9_script.vim')
3808
3809  var legacy_lines =<< trim END
3810    source Xvim9_script.vim
3811
3812    call assert_false(exists('local'))
3813    call assert_false(exists('exported'))
3814    call assert_false(exists('s:exported'))
3815    call assert_equal('global', global)
3816    call assert_equal('global', g:global)
3817
3818    " imported variable becomes script-local
3819    import exported from './Xvim9_script.vim'
3820    call assert_equal('exported', s:exported)
3821    call assert_false(exists('exported'))
3822
3823    " imported function becomes script-local
3824    import GetText from './Xvim9_script.vim'
3825    call assert_equal('text', s:GetText())
3826    call assert_false(exists('*GetText'))
3827  END
3828  writefile(legacy_lines, 'Xlegacy_script.vim')
3829
3830  source Xlegacy_script.vim
3831  assert_equal('global', g:global)
3832  unlet g:global
3833
3834  delete('Xlegacy_script.vim')
3835  delete('Xvim9_script.vim')
3836enddef
3837
3838def Test_declare_script_in_func()
3839  var lines =<< trim END
3840      vim9script
3841      func Declare()
3842        let s:local = 123
3843      endfunc
3844      Declare()
3845      assert_equal(123, local)
3846
3847      var error: string
3848      try
3849        local = 'asdf'
3850      catch
3851        error = v:exception
3852      endtry
3853      assert_match('E1012: Type mismatch; expected number but got string', error)
3854
3855      lockvar local
3856      try
3857        local = 999
3858      catch
3859        error = v:exception
3860      endtry
3861      assert_match('E741: Value is locked: local', error)
3862  END
3863  CheckScriptSuccess(lines)
3864enddef
3865
3866
3867func Test_vim9script_not_global()
3868  " check that items defined in Vim9 script are script-local, not global
3869  let vim9lines =<< trim END
3870    vim9script
3871    var name = 'local'
3872    func TheFunc()
3873      echo 'local'
3874    endfunc
3875    def DefFunc()
3876      echo 'local'
3877    enddef
3878  END
3879  call writefile(vim9lines, 'Xvim9script.vim')
3880  source Xvim9script.vim
3881  try
3882    echo g:var
3883    assert_report('did not fail')
3884  catch /E121:/
3885    " caught
3886  endtry
3887  try
3888    call TheFunc()
3889    assert_report('did not fail')
3890  catch /E117:/
3891    " caught
3892  endtry
3893  try
3894    call DefFunc()
3895    assert_report('did not fail')
3896  catch /E117:/
3897    " caught
3898  endtry
3899
3900  call delete('Xvim9script.vim')
3901endfunc
3902
3903def Test_vim9_copen()
3904  # this was giving an error for setting w:quickfix_title
3905  copen
3906  quit
3907enddef
3908
3909" test using an auto-loaded function and variable
3910def Test_vim9_autoload()
3911  var lines =<< trim END
3912     vim9script
3913     def some#gettest(): string
3914       return 'test'
3915     enddef
3916     g:some#name = 'name'
3917     g:some#dict = {key: 'value'}
3918
3919     def some#varargs(a1: string, ...l: list<string>): string
3920       return a1 .. l[0] .. l[1]
3921     enddef
3922  END
3923
3924  mkdir('Xdir/autoload', 'p')
3925  writefile(lines, 'Xdir/autoload/some.vim')
3926  var save_rtp = &rtp
3927  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3928
3929  assert_equal('test', g:some#gettest())
3930  assert_equal('name', g:some#name)
3931  assert_equal('value', g:some#dict.key)
3932  g:some#other = 'other'
3933  assert_equal('other', g:some#other)
3934
3935  assert_equal('abc', some#varargs('a', 'b', 'c'))
3936
3937  # upper case script name works
3938  lines =<< trim END
3939     vim9script
3940     def Other#getOther(): string
3941       return 'other'
3942     enddef
3943  END
3944  writefile(lines, 'Xdir/autoload/Other.vim')
3945  assert_equal('other', g:Other#getOther())
3946
3947  delete('Xdir', 'rf')
3948  &rtp = save_rtp
3949enddef
3950
3951" test using a vim9script that is auto-loaded from an autocmd
3952def Test_vim9_aucmd_autoload()
3953  var lines =<< trim END
3954     vim9script
3955     def foo#test()
3956         echomsg getreg('"')
3957     enddef
3958  END
3959
3960  mkdir('Xdir/autoload', 'p')
3961  writefile(lines, 'Xdir/autoload/foo.vim')
3962  var save_rtp = &rtp
3963  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3964  augroup test
3965    autocmd TextYankPost * call foo#test()
3966  augroup END
3967
3968  normal Y
3969
3970  augroup test
3971    autocmd!
3972  augroup END
3973  delete('Xdir', 'rf')
3974  &rtp = save_rtp
3975enddef
3976
3977" This was causing a crash because suppress_errthrow wasn't reset.
3978def Test_vim9_autoload_error()
3979  var lines =<< trim END
3980      vim9script
3981      def crash#func()
3982          try
3983              for x in List()
3984              endfor
3985          catch
3986          endtry
3987          g:ok = true
3988      enddef
3989      fu List()
3990          invalid
3991      endfu
3992      try
3993          alsoinvalid
3994      catch /wontmatch/
3995      endtry
3996  END
3997  call mkdir('Xruntime/autoload', 'p')
3998  call writefile(lines, 'Xruntime/autoload/crash.vim')
3999
4000  # run in a separate Vim to avoid the side effects of assert_fails()
4001  lines =<< trim END
4002    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
4003    call crash#func()
4004    call writefile(['ok'], 'Xdidit')
4005    qall!
4006  END
4007  writefile(lines, 'Xscript')
4008  RunVim([], [], '-S Xscript')
4009  assert_equal(['ok'], readfile('Xdidit'))
4010
4011  delete('Xdidit')
4012  delete('Xscript')
4013  delete('Xruntime', 'rf')
4014
4015  lines =<< trim END
4016    vim9script
4017    var foo#bar = 'asdf'
4018  END
4019  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
4020enddef
4021
4022def Test_script_var_in_autocmd()
4023  # using a script variable from an autocommand, defined in a :def function in a
4024  # legacy Vim script, cannot check the variable type.
4025  var lines =<< trim END
4026    let s:counter = 1
4027    def s:Func()
4028      au! CursorHold
4029      au CursorHold * s:counter += 1
4030    enddef
4031    call s:Func()
4032    doau CursorHold
4033    call assert_equal(2, s:counter)
4034    au! CursorHold
4035  END
4036  CheckScriptSuccess(lines)
4037enddef
4038
4039def Test_error_in_autoload_script()
4040  var save_rtp = &rtp
4041  var dir = getcwd() .. '/Xruntime'
4042  &rtp = dir
4043  mkdir(dir .. '/autoload', 'p')
4044
4045  var lines =<< trim END
4046      vim9script noclear
4047      def script#autoloaded()
4048      enddef
4049      def Broken()
4050        var x: any = ''
4051        eval x != 0
4052      enddef
4053      Broken()
4054  END
4055  writefile(lines, dir .. '/autoload/script.vim')
4056
4057  lines =<< trim END
4058      vim9script
4059      def CallAutoloaded()
4060        script#autoloaded()
4061      enddef
4062
4063      function Legacy()
4064        try
4065          call s:CallAutoloaded()
4066        catch
4067          call assert_match('E1030: Using a String as a Number', v:exception)
4068        endtry
4069      endfunction
4070
4071      Legacy()
4072  END
4073  CheckScriptSuccess(lines)
4074
4075  &rtp = save_rtp
4076  delete(dir, 'rf')
4077enddef
4078
4079def Test_cmdline_win()
4080  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
4081  # the command line window.
4082  mkdir('rtp/syntax', 'p')
4083  var export_lines =<< trim END
4084    vim9script
4085    export var That = 'yes'
4086  END
4087  writefile(export_lines, 'rtp/syntax/Xexport.vim')
4088  var import_lines =<< trim END
4089    vim9script
4090    import That from './Xexport.vim'
4091  END
4092  writefile(import_lines, 'rtp/syntax/vim.vim')
4093  var save_rtp = &rtp
4094  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
4095  syntax on
4096  augroup CmdWin
4097    autocmd CmdwinEnter * g:got_there = 'yes'
4098  augroup END
4099  # this will open and also close the cmdline window
4100  feedkeys('q:', 'xt')
4101  assert_equal('yes', g:got_there)
4102
4103  augroup CmdWin
4104    au!
4105  augroup END
4106  &rtp = save_rtp
4107  delete('rtp', 'rf')
4108enddef
4109
4110def Test_invalid_sid()
4111  assert_fails('func <SNR>1234_func', 'E123:')
4112
4113  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
4114    assert_equal([], readfile('Xdidit'))
4115  endif
4116  delete('Xdidit')
4117enddef
4118
4119def Test_restoring_cpo()
4120  writefile(['vim9script', 'set nocp'], 'Xsourced')
4121  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
4122  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
4123    assert_equal(['done'], readfile('Xdone'))
4124  endif
4125  delete('Xsourced')
4126  delete('Xclose')
4127  delete('Xdone')
4128
4129  writefile(['vim9script'], 'XanotherScript')
4130  set cpo=aABceFsMny>
4131  edit XanotherScript
4132  so %
4133  assert_equal('aABceFsMny>', &cpo)
4134  :1del
4135  w
4136  so %
4137  assert_equal('aABceFsMny>', &cpo)
4138
4139  delete('XanotherScript')
4140  set cpo&vim
4141enddef
4142
4143" Use :function so we can use Check commands
4144func Test_no_redraw_when_restoring_cpo()
4145  CheckScreendump
4146  CheckFeature timers
4147
4148  let lines =<< trim END
4149    vim9script
4150    def script#func()
4151    enddef
4152  END
4153  call mkdir('Xdir/autoload', 'p')
4154  call writefile(lines, 'Xdir/autoload/script.vim')
4155
4156  let lines =<< trim END
4157      vim9script
4158      set cpo+=M
4159      exe 'set rtp^=' .. getcwd() .. '/Xdir'
4160      au CmdlineEnter : ++once timer_start(0, (_) => script#func())
4161      setline(1, 'some text')
4162  END
4163  call writefile(lines, 'XTest_redraw_cpo')
4164  let buf = RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
4165  call term_sendkeys(buf, "V:")
4166  call VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
4167
4168  " clean up
4169  call term_sendkeys(buf, "\<Esc>u")
4170  call StopVimInTerminal(buf)
4171  call delete('XTest_redraw_cpo')
4172  call delete('Xdir', 'rf')
4173endfunc
4174
4175
4176def Test_unset_any_variable()
4177  var lines =<< trim END
4178    var name: any
4179    assert_equal(0, name)
4180  END
4181  CheckDefAndScriptSuccess(lines)
4182enddef
4183
4184func Test_define_func_at_command_line()
4185  CheckRunVimInTerminal
4186
4187  " call indirectly to avoid compilation error for missing functions
4188  call Run_Test_define_func_at_command_line()
4189endfunc
4190
4191def Run_Test_define_func_at_command_line()
4192  # run in a separate Vim instance to avoid the script context
4193  var lines =<< trim END
4194    func CheckAndQuit()
4195      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
4196      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
4197    endfunc
4198  END
4199  writefile([''], 'Xdidcmd')
4200  writefile(lines, 'XcallFunc')
4201  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
4202  # define Afunc() on the command line
4203  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
4204  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
4205  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
4206
4207  call StopVimInTerminal(buf)
4208  delete('XcallFunc')
4209  delete('Xdidcmd')
4210enddef
4211
4212def Test_script_var_scope()
4213  var lines =<< trim END
4214      vim9script
4215      if true
4216        if true
4217          var one = 'one'
4218          echo one
4219        endif
4220        echo one
4221      endif
4222  END
4223  CheckScriptFailure(lines, 'E121:', 7)
4224
4225  lines =<< trim END
4226      vim9script
4227      if true
4228        if false
4229          var one = 'one'
4230          echo one
4231        else
4232          var one = 'one'
4233          echo one
4234        endif
4235        echo one
4236      endif
4237  END
4238  CheckScriptFailure(lines, 'E121:', 10)
4239
4240  lines =<< trim END
4241      vim9script
4242      while true
4243        var one = 'one'
4244        echo one
4245        break
4246      endwhile
4247      echo one
4248  END
4249  CheckScriptFailure(lines, 'E121:', 7)
4250
4251  lines =<< trim END
4252      vim9script
4253      for i in range(1)
4254        var one = 'one'
4255        echo one
4256      endfor
4257      echo one
4258  END
4259  CheckScriptFailure(lines, 'E121:', 6)
4260
4261  lines =<< trim END
4262      vim9script
4263      {
4264        var one = 'one'
4265        assert_equal('one', one)
4266      }
4267      assert_false(exists('one'))
4268      assert_false(exists('s:one'))
4269  END
4270  CheckScriptSuccess(lines)
4271
4272  lines =<< trim END
4273      vim9script
4274      {
4275        var one = 'one'
4276        echo one
4277      }
4278      echo one
4279  END
4280  CheckScriptFailure(lines, 'E121:', 6)
4281enddef
4282
4283def Test_catch_exception_in_callback()
4284  var lines =<< trim END
4285    vim9script
4286    def Callback(...l: list<any>)
4287      try
4288        var x: string
4289        var y: string
4290        # this error should be caught with CHECKLEN
4291        [x, y] = ['']
4292      catch
4293        g:caught = 'yes'
4294      endtry
4295    enddef
4296    popup_menu('popup', {callback: Callback})
4297    feedkeys("\r", 'xt')
4298  END
4299  CheckScriptSuccess(lines)
4300
4301  unlet g:caught
4302enddef
4303
4304def Test_no_unknown_error_after_error()
4305  if !has('unix') || !has('job')
4306    throw 'Skipped: not unix of missing +job feature'
4307  endif
4308  # FIXME: this check should not be needed
4309  if has('win32')
4310    throw 'Skipped: does not work on MS-Windows'
4311  endif
4312  var lines =<< trim END
4313      vim9script
4314      var source: list<number>
4315      def Out_cb(...l: list<any>)
4316          eval [][0]
4317      enddef
4318      def Exit_cb(...l: list<any>)
4319          sleep 1m
4320          source += l
4321      enddef
4322      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
4323      while job_status(myjob) == 'run'
4324        sleep 10m
4325      endwhile
4326      # wait for Exit_cb() to be called
4327      sleep 200m
4328  END
4329  writefile(lines, 'Xdef')
4330  assert_fails('so Xdef', ['E684:', 'E1012:'])
4331  delete('Xdef')
4332enddef
4333
4334def InvokeNormal()
4335  exe "norm! :m+1\r"
4336enddef
4337
4338def Test_invoke_normal_in_visual_mode()
4339  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
4340  new
4341  setline(1, ['aaa', 'bbb'])
4342  feedkeys("V\<F3>", 'xt')
4343  assert_equal(['bbb', 'aaa'], getline(1, 2))
4344  xunmap <F3>
4345enddef
4346
4347def Test_white_space_after_command()
4348  var lines =<< trim END
4349    exit_cb: Func})
4350  END
4351  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4352
4353  lines =<< trim END
4354    e#
4355  END
4356  CheckDefAndScriptFailure(lines, 'E1144:', 1)
4357enddef
4358
4359def Test_script_var_gone_when_sourced_twice()
4360  var lines =<< trim END
4361      vim9script
4362      if exists('g:guard')
4363        finish
4364      endif
4365      g:guard = 1
4366      var name = 'thename'
4367      def g:GetName(): string
4368        return name
4369      enddef
4370      def g:SetName(arg: string)
4371        name = arg
4372      enddef
4373  END
4374  writefile(lines, 'XscriptTwice.vim')
4375  so XscriptTwice.vim
4376  assert_equal('thename', g:GetName())
4377  g:SetName('newname')
4378  assert_equal('newname', g:GetName())
4379  so XscriptTwice.vim
4380  assert_fails('call g:GetName()', 'E1149:')
4381  assert_fails('call g:SetName("x")', 'E1149:')
4382
4383  delfunc g:GetName
4384  delfunc g:SetName
4385  delete('XscriptTwice.vim')
4386  unlet g:guard
4387enddef
4388
4389def Test_import_gone_when_sourced_twice()
4390  var exportlines =<< trim END
4391      vim9script
4392      if exists('g:guard')
4393        finish
4394      endif
4395      g:guard = 1
4396      export var name = 'someName'
4397  END
4398  writefile(exportlines, 'XexportScript.vim')
4399
4400  var lines =<< trim END
4401      vim9script
4402      import name from './XexportScript.vim'
4403      def g:GetName(): string
4404        return name
4405      enddef
4406  END
4407  writefile(lines, 'XscriptImport.vim')
4408  so XscriptImport.vim
4409  assert_equal('someName', g:GetName())
4410
4411  so XexportScript.vim
4412  assert_fails('call g:GetName()', 'E1149:')
4413
4414  delfunc g:GetName
4415  delete('XexportScript.vim')
4416  delete('XscriptImport.vim')
4417  unlet g:guard
4418enddef
4419
4420def Test_unsupported_commands()
4421  var lines =<< trim END
4422      ka
4423  END
4424  CheckDefFailure(lines, 'E476:')
4425  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4426
4427  lines =<< trim END
4428      :1ka
4429  END
4430  CheckDefFailure(lines, 'E476:')
4431  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4432
4433  lines =<< trim END
4434    t
4435  END
4436  CheckDefFailure(lines, 'E1100:')
4437  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4438
4439  lines =<< trim END
4440    x
4441  END
4442  CheckDefFailure(lines, 'E1100:')
4443  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4444
4445  lines =<< trim END
4446    xit
4447  END
4448  CheckDefFailure(lines, 'E1100:')
4449  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4450enddef
4451
4452def Test_mapping_line_number()
4453  var lines =<< trim END
4454      vim9script
4455      def g:FuncA()
4456          # Some comment
4457          FuncB(0)
4458      enddef
4459          # Some comment
4460      def FuncB(
4461          # Some comment
4462          n: number
4463      )
4464          exe 'nno '
4465              # Some comment
4466              .. '<F3> a'
4467              .. 'b'
4468              .. 'c'
4469      enddef
4470  END
4471  CheckScriptSuccess(lines)
4472  var res = execute('verbose nmap <F3>')
4473  assert_match('No mapping found', res)
4474
4475  g:FuncA()
4476  res = execute('verbose nmap <F3>')
4477  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
4478
4479  nunmap <F3>
4480  delfunc g:FuncA
4481enddef
4482
4483def Test_option_set()
4484  # legacy script allows for white space
4485  var lines =<< trim END
4486      set foldlevel  =11
4487      call assert_equal(11, &foldlevel)
4488  END
4489  CheckScriptSuccess(lines)
4490
4491  set foldlevel
4492  set foldlevel=12
4493  assert_equal(12, &foldlevel)
4494  set foldlevel+=2
4495  assert_equal(14, &foldlevel)
4496  set foldlevel-=3
4497  assert_equal(11, &foldlevel)
4498
4499  lines =<< trim END
4500      set foldlevel =1
4501  END
4502  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
4503
4504  lines =<< trim END
4505      set foldlevel +=1
4506  END
4507  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
4508
4509  lines =<< trim END
4510      set foldlevel ^=1
4511  END
4512  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
4513
4514  lines =<< trim END
4515      set foldlevel -=1
4516  END
4517  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
4518
4519  set foldlevel&
4520enddef
4521
4522def Test_option_modifier()
4523  # legacy script allows for white space
4524  var lines =<< trim END
4525      set hlsearch &  hlsearch  !
4526      call assert_equal(1, &hlsearch)
4527  END
4528  CheckScriptSuccess(lines)
4529
4530  set hlsearch
4531  set hlsearch!
4532  assert_equal(false, &hlsearch)
4533
4534  set hlsearch
4535  set hlsearch&
4536  assert_equal(false, &hlsearch)
4537
4538  lines =<< trim END
4539      set hlsearch &
4540  END
4541  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
4542
4543  lines =<< trim END
4544      set hlsearch   !
4545  END
4546  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
4547
4548  set hlsearch&
4549enddef
4550
4551" This must be called last, it may cause following :def functions to fail
4552def Test_xxx_echoerr_line_number()
4553  var lines =<< trim END
4554      echoerr 'some'
4555         .. ' error'
4556         .. ' continued'
4557  END
4558  CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
4559enddef
4560
4561def ProfiledWithLambda()
4562  var n = 3
4563  echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
4564enddef
4565
4566def ProfiledNested()
4567  var x = 0
4568  def Nested(): any
4569      return x
4570  enddef
4571  Nested()
4572enddef
4573
4574def ProfiledNestedProfiled()
4575  var x = 0
4576  def Nested(): any
4577      return x
4578  enddef
4579  Nested()
4580enddef
4581
4582" Execute this near the end, profiling doesn't stop until Vim exists.
4583" This only tests that it works, not the profiling output.
4584def Test_xx_profile_with_lambda()
4585  CheckFeature profile
4586
4587  profile start Xprofile.log
4588  profile func ProfiledWithLambda
4589  ProfiledWithLambda()
4590
4591  profile func ProfiledNested
4592  ProfiledNested()
4593
4594  # Also profile the nested function.  Use a different function, although the
4595  # contents is the same, to make sure it was not already compiled.
4596  profile func *
4597  ProfiledNestedProfiled()
4598
4599  profdel func *
4600  profile pause
4601enddef
4602
4603" Keep this last, it messes up highlighting.
4604def Test_substitute_cmd()
4605  new
4606  setline(1, 'something')
4607  :substitute(some(other(
4608  assert_equal('otherthing', getline(1))
4609  bwipe!
4610
4611  # also when the context is Vim9 script
4612  var lines =<< trim END
4613    vim9script
4614    new
4615    setline(1, 'something')
4616    :substitute(some(other(
4617    assert_equal('otherthing', getline(1))
4618    bwipe!
4619  END
4620  writefile(lines, 'Xvim9lines')
4621  source Xvim9lines
4622
4623  delete('Xvim9lines')
4624enddef
4625
4626" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
4627