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