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