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