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
8
9def Test_range_only()
10  new
11  setline(1, ['blah', 'Blah'])
12  :/Blah/
13  assert_equal(2, getcurpos()[1])
14  bwipe!
15
16  # without range commands use current line
17  new
18  setline(1, ['one', 'two', 'three'])
19  :2
20  print
21  assert_equal('two', Screenline(&lines))
22  :3
23  list
24  assert_equal('three$', Screenline(&lines))
25  bwipe!
26
27  # won't generate anything
28  if false
29    :123
30  endif
31enddef
32
33let g:alist = [7]
34let g:astring = 'text'
35let g:anumber = 123
36
37def Test_delfunction()
38  # Check function is defined in script namespace
39  CheckScriptSuccess([
40      'vim9script',
41      'func CheckMe()',
42      '  return 123',
43      'endfunc',
44      'assert_equal(123, s:CheckMe())',
45      ])
46
47  # Check function in script namespace cannot be deleted
48  CheckScriptFailure([
49      'vim9script',
50      'func DeleteMe1()',
51      'endfunc',
52      'delfunction DeleteMe1',
53      ], 'E1084:')
54  CheckScriptFailure([
55      'vim9script',
56      'func DeleteMe2()',
57      'endfunc',
58      'def DoThat()',
59      '  delfunction DeleteMe2',
60      'enddef',
61      'DoThat()',
62      ], 'E1084:')
63  CheckScriptFailure([
64      'vim9script',
65      'def DeleteMe3()',
66      'enddef',
67      'delfunction DeleteMe3',
68      ], 'E1084:')
69  CheckScriptFailure([
70      'vim9script',
71      'def DeleteMe4()',
72      'enddef',
73      'def DoThat()',
74      '  delfunction DeleteMe4',
75      'enddef',
76      'DoThat()',
77      ], 'E1084:')
78
79  # Check that global :def function can be replaced and deleted
80  var lines =<< trim END
81      vim9script
82      def g:Global(): string
83        return "yes"
84      enddef
85      assert_equal("yes", g:Global())
86      def! g:Global(): string
87        return "no"
88      enddef
89      assert_equal("no", g:Global())
90      delfunc g:Global
91      assert_false(exists('*g:Global'))
92  END
93  CheckScriptSuccess(lines)
94
95  # Check that global function can be replaced by a :def function and deleted
96  lines =<< trim END
97      vim9script
98      func g:Global()
99        return "yes"
100      endfunc
101      assert_equal("yes", g:Global())
102      def! g:Global(): string
103        return "no"
104      enddef
105      assert_equal("no", g:Global())
106      delfunc g:Global
107      assert_false(exists('*g:Global'))
108  END
109  CheckScriptSuccess(lines)
110
111  # Check that global :def function can be replaced by a function and deleted
112  lines =<< trim END
113      vim9script
114      def g:Global(): string
115        return "yes"
116      enddef
117      assert_equal("yes", g:Global())
118      func! g:Global()
119        return "no"
120      endfunc
121      assert_equal("no", g:Global())
122      delfunc g:Global
123      assert_false(exists('*g:Global'))
124  END
125  CheckScriptSuccess(lines)
126enddef
127
128def Test_wrong_type()
129  CheckDefFailure(['var name: list<nothing>'], 'E1010:')
130  CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
131  CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
132  CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
133
134  CheckDefFailure(['var name: dict<number'], 'E1009:')
135  CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
136
137  CheckDefFailure(['var name: ally'], 'E1010:')
138  CheckDefFailure(['var name: bram'], 'E1010:')
139  CheckDefFailure(['var name: cathy'], 'E1010:')
140  CheckDefFailure(['var name: dom'], 'E1010:')
141  CheckDefFailure(['var name: freddy'], 'E1010:')
142  CheckDefFailure(['var name: john'], 'E1010:')
143  CheckDefFailure(['var name: larry'], 'E1010:')
144  CheckDefFailure(['var name: ned'], 'E1010:')
145  CheckDefFailure(['var name: pam'], 'E1010:')
146  CheckDefFailure(['var name: sam'], 'E1010:')
147  CheckDefFailure(['var name: vim'], 'E1010:')
148
149  CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
150  CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
151enddef
152
153def Test_script_wrong_type()
154  var lines =<< trim END
155      vim9script
156      var s:dict: dict<string>
157      s:dict['a'] = ['x']
158  END
159  CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
160enddef
161
162def Test_const()
163  CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
164  CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
165  CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
166  CheckDefFailure(['final two'], 'E1125:')
167  CheckDefFailure(['final &option'], 'E996:')
168
169  var lines =<< trim END
170    final list = [1, 2, 3]
171    list[0] = 4
172    list->assert_equal([4, 2, 3])
173    const other = [5, 6, 7]
174    other->assert_equal([5, 6, 7])
175
176    var varlist = [7, 8]
177    const constlist = [1, varlist, 3]
178    varlist[0] = 77
179    # TODO: does not work yet
180    # constlist[1][1] = 88
181    var cl = constlist[1]
182    cl[1] = 88
183    constlist->assert_equal([1, [77, 88], 3])
184
185    var vardict = {five: 5, six: 6}
186    const constdict = {one: 1, two: vardict, three: 3}
187    vardict['five'] = 55
188    # TODO: does not work yet
189    # constdict['two']['six'] = 66
190    var cd = constdict['two']
191    cd['six'] = 66
192    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
193  END
194  CheckDefAndScriptSuccess(lines)
195enddef
196
197def Test_const_bang()
198  var lines =<< trim END
199      const var = 234
200      var = 99
201  END
202  CheckDefExecFailure(lines, 'E1018:', 2)
203  CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
204
205  lines =<< trim END
206      const ll = [2, 3, 4]
207      ll[0] = 99
208  END
209  CheckDefExecFailure(lines, 'E1119:', 2)
210  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
211
212  lines =<< trim END
213      const ll = [2, 3, 4]
214      ll[3] = 99
215  END
216  CheckDefExecFailure(lines, 'E1118:', 2)
217  CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
218
219  lines =<< trim END
220      const dd = {one: 1, two: 2}
221      dd["one"] = 99
222  END
223  CheckDefExecFailure(lines, 'E1121:', 2)
224  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
225
226  lines =<< trim END
227      const dd = {one: 1, two: 2}
228      dd["three"] = 99
229  END
230  CheckDefExecFailure(lines, 'E1120:')
231  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
232enddef
233
234def Test_range_no_colon()
235  CheckDefFailure(['%s/a/b/'], 'E1050:')
236  CheckDefFailure(['+ s/a/b/'], 'E1050:')
237  CheckDefFailure(['- s/a/b/'], 'E1050:')
238  CheckDefFailure(['. s/a/b/'], 'E1050:')
239enddef
240
241
242def Test_block()
243  var outer = 1
244  {
245    var inner = 2
246    assert_equal(1, outer)
247    assert_equal(2, inner)
248  }
249  assert_equal(1, outer)
250enddef
251
252def Test_block_failure()
253  CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
254  CheckDefFailure(['}'], 'E1025:')
255  CheckDefFailure(['{', 'echo 1'], 'E1026:')
256enddef
257
258def Test_block_local_vars()
259  var lines =<< trim END
260      vim9script
261      v:testing = 1
262      if true
263        var text = ['hello']
264        def SayHello(): list<string>
265          return text
266        enddef
267        def SetText(v: string)
268          text = [v]
269        enddef
270      endif
271
272      if true
273        var text = ['again']
274        def SayAgain(): list<string>
275          return text
276        enddef
277      endif
278
279      # test that the "text" variables are not cleaned up
280      test_garbagecollect_now()
281
282      defcompile
283
284      assert_equal(['hello'], SayHello())
285      assert_equal(['again'], SayAgain())
286
287      SetText('foobar')
288      assert_equal(['foobar'], SayHello())
289
290      call writefile(['ok'], 'Xdidit')
291      qall!
292  END
293
294  # need to execute this with a separate Vim instance to avoid the current
295  # context gets garbage collected.
296  writefile(lines, 'Xscript')
297  RunVim([], [], '-S Xscript')
298  assert_equal(['ok'], readfile('Xdidit'))
299
300  delete('Xscript')
301  delete('Xdidit')
302enddef
303
304def Test_block_local_vars_with_func()
305  var lines =<< trim END
306      vim9script
307      if true
308        var foo = 'foo'
309        if true
310          var bar = 'bar'
311          def Func(): list<string>
312            return [foo, bar]
313          enddef
314        endif
315      endif
316      # function is compiled here, after blocks have finished, can still access
317      # "foo" and "bar"
318      assert_equal(['foo', 'bar'], Func())
319  END
320  CheckScriptSuccess(lines)
321enddef
322
323func g:NoSuchFunc()
324  echo 'none'
325endfunc
326
327def Test_try_catch_throw()
328  var l = []
329  try # comment
330    add(l, '1')
331    throw 'wrong'
332    add(l, '2')
333  catch # comment
334    add(l, v:exception)
335  finally # comment
336    add(l, '3')
337  endtry # comment
338  assert_equal(['1', 'wrong', '3'], l)
339
340  l = []
341  try
342    try
343      add(l, '1')
344      throw 'wrong'
345      add(l, '2')
346    catch /right/
347      add(l, v:exception)
348    endtry
349  catch /wrong/
350    add(l, 'caught')
351  fina
352    add(l, 'finally')
353  endtry
354  assert_equal(['1', 'caught', 'finally'], l)
355
356  var n: number
357  try
358    n = l[3]
359  catch /E684:/
360    n = 99
361  endtry
362  assert_equal(99, n)
363
364  var done = 'no'
365  if 0
366    try | catch | endtry
367  else
368    done = 'yes'
369  endif
370  assert_equal('yes', done)
371
372  done = 'no'
373  if 1
374    done = 'yes'
375  else
376    try | catch | endtry
377    done = 'never'
378  endif
379  assert_equal('yes', done)
380
381  if 1
382  else
383    try | catch /pat/ | endtry
384    try | catch /pat/
385    endtry
386    try
387    catch /pat/ | endtry
388    try
389    catch /pat/
390    endtry
391  endif
392
393  try
394    # string slice returns a string, not a number
395    n = g:astring[3]
396  catch /E1012:/
397    n = 77
398  endtry
399  assert_equal(77, n)
400
401  try
402    n = l[g:astring]
403  catch /E1012:/
404    n = 88
405  endtry
406  assert_equal(88, n)
407
408  try
409    n = s:does_not_exist
410  catch /E121:/
411    n = 111
412  endtry
413  assert_equal(111, n)
414
415  try
416    n = g:does_not_exist
417  catch /E121:/
418    n = 121
419  endtry
420  assert_equal(121, n)
421
422  var d = {one: 1}
423  try
424    n = d[g:astring]
425  catch /E716:/
426    n = 222
427  endtry
428  assert_equal(222, n)
429
430  try
431    n = -g:astring
432  catch /E39:/
433    n = 233
434  endtry
435  assert_equal(233, n)
436
437  try
438    n = +g:astring
439  catch /E1030:/
440    n = 244
441  endtry
442  assert_equal(244, n)
443
444  try
445    n = +g:alist
446  catch /E745:/
447    n = 255
448  endtry
449  assert_equal(255, n)
450
451  var nd: dict<any>
452  try
453    nd = {[g:anumber]: 1}
454  catch /E1012:/
455    n = 266
456  endtry
457  assert_equal(266, n)
458
459  try
460    [n] = [1, 2, 3]
461  catch /E1093:/
462    n = 277
463  endtry
464  assert_equal(277, n)
465
466  try
467    &ts = g:astring
468  catch /E1012:/
469    n = 288
470  endtry
471  assert_equal(288, n)
472
473  try
474    &backspace = 'asdf'
475  catch /E474:/
476    n = 299
477  endtry
478  assert_equal(299, n)
479
480  l = [1]
481  try
482    l[3] = 3
483  catch /E684:/
484    n = 300
485  endtry
486  assert_equal(300, n)
487
488  try
489    unlet g:does_not_exist
490  catch /E108:/
491    n = 322
492  endtry
493  assert_equal(322, n)
494
495  try
496    d = {text: 1, [g:astring]: 2}
497  catch /E721:/
498    n = 333
499  endtry
500  assert_equal(333, n)
501
502  try
503    l = DeletedFunc()
504  catch /E933:/
505    n = 344
506  endtry
507  assert_equal(344, n)
508
509  try
510    echo len(v:true)
511  catch /E701:/
512    n = 355
513  endtry
514  assert_equal(355, n)
515
516  var P = function('g:NoSuchFunc')
517  delfunc g:NoSuchFunc
518  try
519    echo P()
520  catch /E117:/
521    n = 366
522  endtry
523  assert_equal(366, n)
524
525  try
526    echo g:NoSuchFunc()
527  catch /E117:/
528    n = 377
529  endtry
530  assert_equal(377, n)
531
532  try
533    echo g:alist + 4
534  catch /E745:/
535    n = 388
536  endtry
537  assert_equal(388, n)
538
539  try
540    echo 4 + g:alist
541  catch /E745:/
542    n = 399
543  endtry
544  assert_equal(399, n)
545
546  try
547    echo g:alist.member
548  catch /E715:/
549    n = 400
550  endtry
551  assert_equal(400, n)
552
553  try
554    echo d.member
555  catch /E716:/
556    n = 411
557  endtry
558  assert_equal(411, n)
559enddef
560
561def Test_throw_skipped()
562  if 0
563    throw dontgethere
564  endif
565enddef
566
567def DeletedFunc(): list<any>
568  return ['delete me']
569enddef
570defcompile
571delfunc DeletedFunc
572
573def ThrowFromDef()
574  throw "getout" # comment
575enddef
576
577func CatchInFunc()
578  try
579    call ThrowFromDef()
580  catch
581    let g:thrown_func = v:exception
582  endtry
583endfunc
584
585def CatchInDef()
586  try
587    ThrowFromDef()
588  catch
589    g:thrown_def = v:exception
590  endtry
591enddef
592
593def ReturnFinally(): string
594  try
595    return 'intry'
596  finall
597    g:in_finally = 'finally'
598  endtry
599  return 'end'
600enddef
601
602def Test_try_catch_nested()
603  CatchInFunc()
604  assert_equal('getout', g:thrown_func)
605
606  CatchInDef()
607  assert_equal('getout', g:thrown_def)
608
609  assert_equal('intry', ReturnFinally())
610  assert_equal('finally', g:in_finally)
611enddef
612
613def TryOne(): number
614  try
615    return 0
616  catch
617  endtry
618  return 0
619enddef
620
621def TryTwo(n: number): string
622  try
623    var x = {}
624  catch
625  endtry
626  return 'text'
627enddef
628
629def Test_try_catch_twice()
630  assert_equal('text', TryOne()->TryTwo())
631enddef
632
633def Test_try_catch_match()
634  var seq = 'a'
635  try
636    throw 'something'
637  catch /nothing/
638    seq ..= 'x'
639  catch /some/
640    seq ..= 'b'
641  catch /asdf/
642    seq ..= 'x'
643  catch ?a\?sdf?
644    seq ..= 'y'
645  finally
646    seq ..= 'c'
647  endtry
648  assert_equal('abc', seq)
649enddef
650
651def Test_try_catch_fails()
652  CheckDefFailure(['catch'], 'E603:')
653  CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
654  CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
655  CheckDefFailure(['finally'], 'E606:')
656  CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
657  CheckDefFailure(['endtry'], 'E602:')
658  CheckDefFailure(['while 1', 'endtry'], 'E170:')
659  CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
660  CheckDefFailure(['if 1', 'endtry'], 'E171:')
661  CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
662
663  CheckDefFailure(['throw'], 'E1143:')
664  CheckDefFailure(['throw xxx'], 'E1001:')
665enddef
666
667def Test_throw_vimscript()
668  # only checks line continuation
669  var lines =<< trim END
670      vim9script
671      try
672        throw 'one'
673              .. 'two'
674      catch
675        assert_equal('onetwo', v:exception)
676      endtry
677  END
678  CheckScriptSuccess(lines)
679
680  lines =<< trim END
681    vim9script
682    @r = ''
683    def Func()
684      throw @r
685    enddef
686    var result = ''
687    try
688      Func()
689    catch /E1129:/
690      result = 'caught'
691    endtry
692    assert_equal('caught', result)
693  END
694  CheckScriptSuccess(lines)
695enddef
696
697def Test_error_in_nested_function()
698  # an error in a nested :function aborts executin in the calling :def function
699  var lines =<< trim END
700      vim9script
701      def Func()
702        Error()
703        g:test_var = 1
704      enddef
705      func Error() abort
706        eval [][0]
707      endfunc
708      Func()
709  END
710  g:test_var = 0
711  CheckScriptFailure(lines, 'E684:')
712  assert_equal(0, g:test_var)
713enddef
714
715def Test_cexpr_vimscript()
716  # only checks line continuation
717  set errorformat=File\ %f\ line\ %l
718  var lines =<< trim END
719      vim9script
720      cexpr 'File'
721                .. ' someFile' ..
722                   ' line 19'
723      assert_equal(19, getqflist()[0].lnum)
724  END
725  CheckScriptSuccess(lines)
726  set errorformat&
727enddef
728
729def Test_statusline_syntax()
730  # legacy syntax is used for 'statusline'
731  var lines =<< trim END
732      vim9script
733      func g:Status()
734        return '%{"x" is# "x"}'
735      endfunc
736      set laststatus=2 statusline=%!Status()
737      redrawstatus
738      set laststatus statusline=
739  END
740  CheckScriptSuccess(lines)
741enddef
742
743def Test_list_vimscript()
744  # checks line continuation and comments
745  var lines =<< trim END
746      vim9script
747      var mylist = [
748            'one',
749            # comment
750            'two', # empty line follows
751
752            'three',
753            ]
754      assert_equal(['one', 'two', 'three'], mylist)
755  END
756  CheckScriptSuccess(lines)
757
758  # check all lines from heredoc are kept
759  lines =<< trim END
760      # comment 1
761      two
762      # comment 3
763
764      five
765      # comment 6
766  END
767  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
768enddef
769
770if has('channel')
771  let someJob = test_null_job()
772
773  def FuncWithError()
774    echomsg g:someJob
775  enddef
776
777  func Test_convert_emsg_to_exception()
778    try
779      call FuncWithError()
780    catch
781      call assert_match('Vim:E908:', v:exception)
782    endtry
783  endfunc
784endif
785
786let s:export_script_lines =<< trim END
787  vim9script
788  var name: string = 'bob'
789  def Concat(arg: string): string
790    return name .. arg
791  enddef
792  g:result = Concat('bie')
793  g:localname = name
794
795  export const CONST = 1234
796  export var exported = 9876
797  export var exp_name = 'John'
798  export def Exported(): string
799    return 'Exported'
800  enddef
801END
802
803def Undo_export_script_lines()
804  unlet g:result
805  unlet g:localname
806enddef
807
808def Test_vim9_import_export()
809  var import_script_lines =<< trim END
810    vim9script
811    import {exported, Exported} from './Xexport.vim'
812    g:imported = exported
813    exported += 3
814    g:imported_added = exported
815    g:imported_func = Exported()
816
817    def GetExported(): string
818      var local_dict = {ref: Exported}
819      return local_dict.ref()
820    enddef
821    g:funcref_result = GetExported()
822
823    import {exp_name} from './Xexport.vim'
824    g:imported_name = exp_name
825    exp_name ..= ' Doe'
826    g:imported_name_appended = exp_name
827    g:imported_later = exported
828  END
829
830  writefile(import_script_lines, 'Ximport.vim')
831  writefile(s:export_script_lines, 'Xexport.vim')
832
833  source Ximport.vim
834
835  assert_equal('bobbie', g:result)
836  assert_equal('bob', g:localname)
837  assert_equal(9876, g:imported)
838  assert_equal(9879, g:imported_added)
839  assert_equal(9879, g:imported_later)
840  assert_equal('Exported', g:imported_func)
841  assert_equal('Exported', g:funcref_result)
842  assert_equal('John', g:imported_name)
843  assert_equal('John Doe', g:imported_name_appended)
844  assert_false(exists('g:name'))
845
846  Undo_export_script_lines()
847  unlet g:imported
848  unlet g:imported_added
849  unlet g:imported_later
850  unlet g:imported_func
851  unlet g:imported_name g:imported_name_appended
852  delete('Ximport.vim')
853
854  # similar, with line breaks
855  var import_line_break_script_lines =<< trim END
856    vim9script
857    import {
858        exported,
859        Exported,
860        }
861        from
862        './Xexport.vim'
863    g:imported = exported
864    exported += 5
865    g:imported_added = exported
866    g:imported_func = Exported()
867  END
868  writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
869  source Ximport_lbr.vim
870
871  assert_equal(9876, g:imported)
872  assert_equal(9881, g:imported_added)
873  assert_equal('Exported', g:imported_func)
874
875  # exported script not sourced again
876  assert_false(exists('g:result'))
877  unlet g:imported
878  unlet g:imported_added
879  unlet g:imported_func
880  delete('Ximport_lbr.vim')
881
882  # import inside :def function
883  var import_in_def_lines =<< trim END
884    vim9script
885    def ImportInDef()
886      import exported from './Xexport.vim'
887      g:imported = exported
888      exported += 7
889      g:imported_added = exported
890    enddef
891    ImportInDef()
892  END
893  writefile(import_in_def_lines, 'Ximport2.vim')
894  source Ximport2.vim
895  # TODO: this should be 9879
896  assert_equal(9876, g:imported)
897  assert_equal(9883, g:imported_added)
898  unlet g:imported
899  unlet g:imported_added
900  delete('Ximport2.vim')
901
902  var import_star_as_lines =<< trim END
903    vim9script
904    import * as Export from './Xexport.vim'
905    def UseExport()
906      g:imported = Export.exported
907    enddef
908    UseExport()
909  END
910  writefile(import_star_as_lines, 'Ximport.vim')
911  source Ximport.vim
912  assert_equal(9883, g:imported)
913
914  var import_star_as_lines_no_dot =<< trim END
915    vim9script
916    import * as Export from './Xexport.vim'
917    def Func()
918      var dummy = 1
919      var imported = Export + dummy
920    enddef
921    defcompile
922  END
923  writefile(import_star_as_lines_no_dot, 'Ximport.vim')
924  assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func')
925
926  var import_star_as_lines_dot_space =<< trim END
927    vim9script
928    import * as Export from './Xexport.vim'
929    def Func()
930      var imported = Export . exported
931    enddef
932    defcompile
933  END
934  writefile(import_star_as_lines_dot_space, 'Ximport.vim')
935  assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
936
937  var import_star_as_duplicated =<< trim END
938    vim9script
939    import * as Export from './Xexport.vim'
940    var some = 'other'
941    import * as Export from './Xexport.vim'
942    defcompile
943  END
944  writefile(import_star_as_duplicated, 'Ximport.vim')
945  assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
946
947  var import_star_as_lines_missing_name =<< trim END
948    vim9script
949    import * as Export from './Xexport.vim'
950    def Func()
951      var imported = Export.
952    enddef
953    defcompile
954  END
955  writefile(import_star_as_lines_missing_name, 'Ximport.vim')
956  assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func')
957
958  var import_star_as_lbr_lines =<< trim END
959    vim9script
960    import *
961        as Export
962        from
963        './Xexport.vim'
964    def UseExport()
965      g:imported = Export.exported
966    enddef
967    UseExport()
968  END
969  writefile(import_star_as_lbr_lines, 'Ximport.vim')
970  source Ximport.vim
971  assert_equal(9883, g:imported)
972
973  var import_star_lines =<< trim END
974    vim9script
975    import * from './Xexport.vim'
976  END
977  writefile(import_star_lines, 'Ximport.vim')
978  assert_fails('source Ximport.vim', 'E1045:', '', 2, 'Ximport.vim')
979
980  # try to import something that exists but is not exported
981  var import_not_exported_lines =<< trim END
982    vim9script
983    import name from './Xexport.vim'
984  END
985  writefile(import_not_exported_lines, 'Ximport.vim')
986  assert_fails('source Ximport.vim', 'E1049:', '', 2, 'Ximport.vim')
987
988  # try to import something that is already defined
989  var import_already_defined =<< trim END
990    vim9script
991    var exported = 'something'
992    import exported from './Xexport.vim'
993  END
994  writefile(import_already_defined, 'Ximport.vim')
995  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
996
997  # try to import something that is already defined
998  import_already_defined =<< trim END
999    vim9script
1000    var exported = 'something'
1001    import * as exported from './Xexport.vim'
1002  END
1003  writefile(import_already_defined, 'Ximport.vim')
1004  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
1005
1006  # try to import something that is already defined
1007  import_already_defined =<< trim END
1008    vim9script
1009    var exported = 'something'
1010    import {exported} from './Xexport.vim'
1011  END
1012  writefile(import_already_defined, 'Ximport.vim')
1013  assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
1014
1015  # try changing an imported const
1016  var import_assign_to_const =<< trim END
1017    vim9script
1018    import CONST from './Xexport.vim'
1019    def Assign()
1020      CONST = 987
1021    enddef
1022    defcompile
1023  END
1024  writefile(import_assign_to_const, 'Ximport.vim')
1025  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
1026
1027  # import a very long name, requires making a copy
1028  var import_long_name_lines =<< trim END
1029    vim9script
1030    import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim'
1031  END
1032  writefile(import_long_name_lines, 'Ximport.vim')
1033  assert_fails('source Ximport.vim', 'E1048:', '', 2, 'Ximport.vim')
1034
1035  var import_no_from_lines =<< trim END
1036    vim9script
1037    import name './Xexport.vim'
1038  END
1039  writefile(import_no_from_lines, 'Ximport.vim')
1040  assert_fails('source Ximport.vim', 'E1070:', '', 2, 'Ximport.vim')
1041
1042  var import_invalid_string_lines =<< trim END
1043    vim9script
1044    import name from Xexport.vim
1045  END
1046  writefile(import_invalid_string_lines, 'Ximport.vim')
1047  assert_fails('source Ximport.vim', 'E1071:', '', 2, 'Ximport.vim')
1048
1049  var import_wrong_name_lines =<< trim END
1050    vim9script
1051    import name from './XnoExport.vim'
1052  END
1053  writefile(import_wrong_name_lines, 'Ximport.vim')
1054  assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
1055
1056  var import_missing_comma_lines =<< trim END
1057    vim9script
1058    import {exported name} from './Xexport.vim'
1059  END
1060  writefile(import_missing_comma_lines, 'Ximport3.vim')
1061  assert_fails('source Ximport3.vim', 'E1046:', '', 2, 'Ximport3.vim')
1062
1063  delete('Ximport.vim')
1064  delete('Ximport3.vim')
1065  delete('Xexport.vim')
1066
1067  # Check that in a Vim9 script 'cpo' is set to the Vim default.
1068  set cpo&vi
1069  var cpo_before = &cpo
1070  var lines =<< trim END
1071    vim9script
1072    g:cpo_in_vim9script = &cpo
1073  END
1074  writefile(lines, 'Xvim9_script')
1075  source Xvim9_script
1076  assert_equal(cpo_before, &cpo)
1077  set cpo&vim
1078  assert_equal(&cpo, g:cpo_in_vim9script)
1079  delete('Xvim9_script')
1080enddef
1081
1082func g:Trigger()
1083  source Ximport.vim
1084  return "echo 'yes'\<CR>"
1085endfunc
1086
1087def Test_import_export_expr_map()
1088  # check that :import and :export work when buffer is locked
1089  var export_lines =<< trim END
1090    vim9script
1091    export def That(): string
1092      return 'yes'
1093    enddef
1094  END
1095  writefile(export_lines, 'Xexport_that.vim')
1096
1097  var import_lines =<< trim END
1098    vim9script
1099    import That from './Xexport_that.vim'
1100    assert_equal('yes', That())
1101  END
1102  writefile(import_lines, 'Ximport.vim')
1103
1104  nnoremap <expr> trigger g:Trigger()
1105  feedkeys('trigger', "xt")
1106
1107  delete('Xexport_that.vim')
1108  delete('Ximport.vim')
1109  nunmap trigger
1110enddef
1111
1112def Test_import_in_filetype()
1113  # check that :import works when the buffer is locked
1114  mkdir('ftplugin', 'p')
1115  var export_lines =<< trim END
1116    vim9script
1117    export var That = 'yes'
1118  END
1119  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1120
1121  var import_lines =<< trim END
1122    vim9script
1123    import That from './Xexport_ft.vim'
1124    assert_equal('yes', That)
1125    g:did_load_mytpe = 1
1126  END
1127  writefile(import_lines, 'ftplugin/qf.vim')
1128
1129  var save_rtp = &rtp
1130  &rtp = getcwd() .. ',' .. &rtp
1131
1132  filetype plugin on
1133  copen
1134  assert_equal(1, g:did_load_mytpe)
1135
1136  quit!
1137  delete('Xexport_ft.vim')
1138  delete('ftplugin', 'rf')
1139  &rtp = save_rtp
1140enddef
1141
1142def Test_use_import_in_mapping()
1143  var lines =<< trim END
1144      vim9script
1145      export def Funcx()
1146        g:result = 42
1147      enddef
1148  END
1149  writefile(lines, 'XsomeExport.vim')
1150  lines =<< trim END
1151      vim9script
1152      import Funcx from './XsomeExport.vim'
1153      nnoremap <F3> :call <sid>Funcx()<cr>
1154  END
1155  writefile(lines, 'Xmapscript.vim')
1156
1157  source Xmapscript.vim
1158  feedkeys("\<F3>", "xt")
1159  assert_equal(42, g:result)
1160
1161  unlet g:result
1162  delete('XsomeExport.vim')
1163  delete('Xmapscript.vim')
1164  nunmap <F3>
1165enddef
1166
1167def Test_vim9script_fails()
1168  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1169  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1170  CheckScriptFailure(['export var some = 123'], 'E1042:')
1171  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1172  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1173  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1174
1175  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1176  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1177
1178  assert_fails('vim9script', 'E1038:')
1179  assert_fails('export something', 'E1043:')
1180enddef
1181
1182func Test_import_fails_without_script()
1183  CheckRunVimInTerminal
1184
1185  " call indirectly to avoid compilation error for missing functions
1186  call Run_Test_import_fails_on_command_line()
1187endfunc
1188
1189def Run_Test_import_fails_on_command_line()
1190  var export =<< trim END
1191    vim9script
1192    export def Foo(): number
1193        return 0
1194    enddef
1195  END
1196  writefile(export, 'XexportCmd.vim')
1197
1198  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1199                rows: 6, wait_for_ruler: 0})
1200  WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
1201
1202  delete('XexportCmd.vim')
1203  StopVimInTerminal(buf)
1204enddef
1205
1206def Test_vim9script_reload_noclear()
1207  var lines =<< trim END
1208    vim9script
1209    export var exported = 'thexport'
1210  END
1211  writefile(lines, 'XExportReload')
1212  lines =<< trim END
1213    vim9script noclear
1214    g:loadCount += 1
1215    var s:reloaded = 'init'
1216    import exported from './XExportReload'
1217
1218    def Again(): string
1219      return 'again'
1220    enddef
1221
1222    if exists('s:loaded') | finish | endif
1223    var s:loaded = true
1224
1225    var s:notReloaded = 'yes'
1226    s:reloaded = 'first'
1227    def g:Values(): list<string>
1228      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
1229    enddef
1230
1231    def Once(): string
1232      return 'once'
1233    enddef
1234  END
1235  writefile(lines, 'XReloaded')
1236  g:loadCount = 0
1237  source XReloaded
1238  assert_equal(1, g:loadCount)
1239  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
1240  source XReloaded
1241  assert_equal(2, g:loadCount)
1242  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1243  source XReloaded
1244  assert_equal(3, g:loadCount)
1245  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1246
1247  delete('XReloaded')
1248  delete('XExportReload')
1249  delfunc g:Values
1250  unlet g:loadCount
1251enddef
1252
1253def Test_vim9script_reload_import()
1254  var lines =<< trim END
1255    vim9script
1256    const var = ''
1257    var valone = 1234
1258    def MyFunc(arg: string)
1259       valone = 5678
1260    enddef
1261  END
1262  var morelines =<< trim END
1263    var valtwo = 222
1264    export def GetValtwo(): number
1265      return valtwo
1266    enddef
1267  END
1268  writefile(lines + morelines, 'Xreload.vim')
1269  source Xreload.vim
1270  source Xreload.vim
1271  source Xreload.vim
1272
1273  var testlines =<< trim END
1274    vim9script
1275    def TheFunc()
1276      import GetValtwo from './Xreload.vim'
1277      assert_equal(222, GetValtwo())
1278    enddef
1279    TheFunc()
1280  END
1281  writefile(testlines, 'Ximport.vim')
1282  source Ximport.vim
1283
1284  # Test that when not using "morelines" GetValtwo() and valtwo are still
1285  # defined, because import doesn't reload a script.
1286  writefile(lines, 'Xreload.vim')
1287  source Ximport.vim
1288
1289  # cannot declare a var twice
1290  lines =<< trim END
1291    vim9script
1292    var valone = 1234
1293    var valone = 5678
1294  END
1295  writefile(lines, 'Xreload.vim')
1296  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1297
1298  delete('Xreload.vim')
1299  delete('Ximport.vim')
1300enddef
1301
1302" if a script is reloaded with a script-local variable that changed its type, a
1303" compiled function using that variable must fail.
1304def Test_script_reload_change_type()
1305  var lines =<< trim END
1306    vim9script noclear
1307    var str = 'string'
1308    def g:GetStr(): string
1309      return str .. 'xxx'
1310    enddef
1311  END
1312  writefile(lines, 'Xreload.vim')
1313  source Xreload.vim
1314  echo g:GetStr()
1315
1316  lines =<< trim END
1317    vim9script noclear
1318    var str = 1234
1319  END
1320  writefile(lines, 'Xreload.vim')
1321  source Xreload.vim
1322  assert_fails('echo g:GetStr()', 'E1150:')
1323
1324  delfunc g:GetStr
1325  delete('Xreload.vim')
1326enddef
1327
1328def s:RetSome(): string
1329  return 'some'
1330enddef
1331
1332" Not exported function that is referenced needs to be accessed by the
1333" script-local name.
1334def Test_vim9script_funcref()
1335  var sortlines =<< trim END
1336      vim9script
1337      def Compare(i1: number, i2: number): number
1338        return i2 - i1
1339      enddef
1340
1341      export def FastSort(): list<number>
1342        return range(5)->sort(Compare)
1343      enddef
1344  END
1345  writefile(sortlines, 'Xsort.vim')
1346
1347  var lines =<< trim END
1348    vim9script
1349    import FastSort from './Xsort.vim'
1350    def Test()
1351      g:result = FastSort()
1352    enddef
1353    Test()
1354  END
1355  writefile(lines, 'Xscript.vim')
1356
1357  source Xscript.vim
1358  assert_equal([4, 3, 2, 1, 0], g:result)
1359
1360  unlet g:result
1361  delete('Xsort.vim')
1362  delete('Xscript.vim')
1363
1364  var Funcref = function('s:RetSome')
1365  assert_equal('some', Funcref())
1366enddef
1367
1368" Check that when searching for "FilterFunc" it finds the import in the
1369" script where FastFilter() is called from, both as a string and as a direct
1370" function reference.
1371def Test_vim9script_funcref_other_script()
1372  var filterLines =<< trim END
1373    vim9script
1374    export def FilterFunc(idx: number, val: number): bool
1375      return idx % 2 == 1
1376    enddef
1377    export def FastFilter(): list<number>
1378      return range(10)->filter('FilterFunc')
1379    enddef
1380    export def FastFilterDirect(): list<number>
1381      return range(10)->filter(FilterFunc)
1382    enddef
1383  END
1384  writefile(filterLines, 'Xfilter.vim')
1385
1386  var lines =<< trim END
1387    vim9script
1388    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1389    def Test()
1390      var x: list<number> = FastFilter()
1391    enddef
1392    Test()
1393    def TestDirect()
1394      var x: list<number> = FastFilterDirect()
1395    enddef
1396    TestDirect()
1397  END
1398  CheckScriptSuccess(lines)
1399  delete('Xfilter.vim')
1400enddef
1401
1402def Test_vim9script_reload_delfunc()
1403  var first_lines =<< trim END
1404    vim9script
1405    def FuncYes(): string
1406      return 'yes'
1407    enddef
1408  END
1409  var withno_lines =<< trim END
1410    def FuncNo(): string
1411      return 'no'
1412    enddef
1413    def g:DoCheck(no_exists: bool)
1414      assert_equal('yes', FuncYes())
1415      assert_equal('no', FuncNo())
1416    enddef
1417  END
1418  var nono_lines =<< trim END
1419    def g:DoCheck(no_exists: bool)
1420      assert_equal('yes', FuncYes())
1421      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
1422    enddef
1423  END
1424
1425  # FuncNo() is defined
1426  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1427  source Xreloaded.vim
1428  g:DoCheck(true)
1429
1430  # FuncNo() is not redefined
1431  writefile(first_lines + nono_lines, 'Xreloaded.vim')
1432  source Xreloaded.vim
1433  g:DoCheck(false)
1434
1435  # FuncNo() is back
1436  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1437  source Xreloaded.vim
1438  g:DoCheck(false)
1439
1440  delete('Xreloaded.vim')
1441enddef
1442
1443def Test_vim9script_reload_delvar()
1444  # write the script with a script-local variable
1445  var lines =<< trim END
1446    vim9script
1447    var name = 'string'
1448  END
1449  writefile(lines, 'XreloadVar.vim')
1450  source XreloadVar.vim
1451
1452  # now write the script using the same variable locally - works
1453  lines =<< trim END
1454    vim9script
1455    def Func()
1456      var name = 'string'
1457    enddef
1458  END
1459  writefile(lines, 'XreloadVar.vim')
1460  source XreloadVar.vim
1461
1462  delete('XreloadVar.vim')
1463enddef
1464
1465def Test_import_absolute()
1466  var import_lines = [
1467        'vim9script',
1468        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
1469        'def UseExported()',
1470        '  g:imported_abs = exported',
1471        '  exported = 8888',
1472        '  g:imported_after = exported',
1473        'enddef',
1474        'UseExported()',
1475        'g:import_disassembled = execute("disass UseExported")',
1476        ]
1477  writefile(import_lines, 'Ximport_abs.vim')
1478  writefile(s:export_script_lines, 'Xexport_abs.vim')
1479
1480  source Ximport_abs.vim
1481
1482  assert_equal(9876, g:imported_abs)
1483  assert_equal(8888, g:imported_after)
1484  assert_match('<SNR>\d\+_UseExported\_s*' ..
1485          'g:imported_abs = exported\_s*' ..
1486          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1487          '1 STOREG g:imported_abs\_s*' ..
1488          'exported = 8888\_s*' ..
1489          '2 PUSHNR 8888\_s*' ..
1490          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
1491          'g:imported_after = exported\_s*' ..
1492          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1493          '5 STOREG g:imported_after',
1494        g:import_disassembled)
1495
1496  Undo_export_script_lines()
1497  unlet g:imported_abs
1498  unlet g:import_disassembled
1499
1500  delete('Ximport_abs.vim')
1501  delete('Xexport_abs.vim')
1502enddef
1503
1504def Test_import_rtp()
1505  var import_lines = [
1506        'vim9script',
1507        'import exported from "Xexport_rtp.vim"',
1508        'g:imported_rtp = exported',
1509        ]
1510  writefile(import_lines, 'Ximport_rtp.vim')
1511  mkdir('import')
1512  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
1513
1514  var save_rtp = &rtp
1515  &rtp = getcwd()
1516  source Ximport_rtp.vim
1517  &rtp = save_rtp
1518
1519  assert_equal(9876, g:imported_rtp)
1520
1521  Undo_export_script_lines()
1522  unlet g:imported_rtp
1523  delete('Ximport_rtp.vim')
1524  delete('import', 'rf')
1525enddef
1526
1527def Test_import_compile_error()
1528  var export_lines = [
1529        'vim9script',
1530        'export def ExpFunc(): string',
1531        '  return notDefined',
1532        'enddef',
1533        ]
1534  writefile(export_lines, 'Xexported.vim')
1535
1536  var import_lines = [
1537        'vim9script',
1538        'import ExpFunc from "./Xexported.vim"',
1539        'def ImpFunc()',
1540        '  echo ExpFunc()',
1541        'enddef',
1542        'defcompile',
1543        ]
1544  writefile(import_lines, 'Ximport.vim')
1545
1546  try
1547    source Ximport.vim
1548  catch /E1001/
1549    # Error should be fore the Xexported.vim file.
1550    assert_match('E1001: Variable not found: notDefined', v:exception)
1551    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
1552  endtry
1553
1554  delete('Xexported.vim')
1555  delete('Ximport.vim')
1556enddef
1557
1558def Test_func_redefine_error()
1559  var lines = [
1560        'vim9script',
1561        'def Func()',
1562        '  eval [][0]',
1563        'enddef',
1564        'Func()',
1565        ]
1566  writefile(lines, 'Xtestscript.vim')
1567
1568  for count in range(3)
1569    try
1570      source Xtestscript.vim
1571    catch /E684/
1572      # function name should contain <SNR> every time
1573      assert_match('E684: list index out of range', v:exception)
1574      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
1575    endtry
1576  endfor
1577
1578  delete('Xtestscript.vim')
1579enddef
1580
1581def Test_func_overrules_import_fails()
1582  var export_lines =<< trim END
1583      vim9script
1584      export def Func()
1585        echo 'imported'
1586      enddef
1587  END
1588  writefile(export_lines, 'XexportedFunc.vim')
1589
1590  var lines =<< trim END
1591    vim9script
1592    import Func from './XexportedFunc.vim'
1593    def Func()
1594      echo 'local to function'
1595    enddef
1596  END
1597  CheckScriptFailure(lines, 'E1073:')
1598
1599  lines =<< trim END
1600    vim9script
1601    import Func from './XexportedFunc.vim'
1602    def Outer()
1603      def Func()
1604        echo 'local to function'
1605      enddef
1606    enddef
1607    defcompile
1608  END
1609  CheckScriptFailure(lines, 'E1073:')
1610
1611  delete('XexportedFunc.vim')
1612enddef
1613
1614def Test_func_redefine_fails()
1615  var lines =<< trim END
1616    vim9script
1617    def Func()
1618      echo 'one'
1619    enddef
1620    def Func()
1621      echo 'two'
1622    enddef
1623  END
1624  CheckScriptFailure(lines, 'E1073:')
1625
1626  lines =<< trim END
1627    vim9script
1628    def Foo(): string
1629      return 'foo'
1630      enddef
1631    def Func()
1632      var  Foo = {-> 'lambda'}
1633    enddef
1634    defcompile
1635  END
1636  CheckScriptFailure(lines, 'E1073:')
1637enddef
1638
1639def Test_fixed_size_list()
1640  # will be allocated as one piece of memory, check that changes work
1641  var l = [1, 2, 3, 4]
1642  l->remove(0)
1643  l->add(5)
1644  l->insert(99, 1)
1645  assert_equal([2, 99, 3, 4, 5], l)
1646enddef
1647
1648def Test_no_insert_xit()
1649  CheckDefExecFailure(['a = 1'], 'E1100:')
1650  CheckDefExecFailure(['c = 1'], 'E1100:')
1651  CheckDefExecFailure(['i = 1'], 'E1100:')
1652  CheckDefExecFailure(['t = 1'], 'E1100:')
1653  CheckDefExecFailure(['x = 1'], 'E1100:')
1654
1655  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
1656  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
1657  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
1658  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
1659  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
1660  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
1661  CheckScriptFailure(['vim9script', 't'], 'E1100:')
1662  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
1663  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
1664enddef
1665
1666def IfElse(what: number): string
1667  var res = ''
1668  if what == 1
1669    res = "one"
1670  elseif what == 2
1671    res = "two"
1672  else
1673    res = "three"
1674  endif
1675  return res
1676enddef
1677
1678def Test_if_elseif_else()
1679  assert_equal('one', IfElse(1))
1680  assert_equal('two', IfElse(2))
1681  assert_equal('three', IfElse(3))
1682enddef
1683
1684def Test_if_elseif_else_fails()
1685  CheckDefFailure(['elseif true'], 'E582:')
1686  CheckDefFailure(['else'], 'E581:')
1687  CheckDefFailure(['endif'], 'E580:')
1688  CheckDefFailure(['if true', 'elseif xxx'], 'E1001:')
1689  CheckDefFailure(['if true', 'echo 1'], 'E171:')
1690enddef
1691
1692let g:bool_true = v:true
1693let g:bool_false = v:false
1694
1695def Test_if_const_expr()
1696  var res = false
1697  if true ? true : false
1698    res = true
1699  endif
1700  assert_equal(true, res)
1701
1702  g:glob = 2
1703  if false
1704    execute('g:glob = 3')
1705  endif
1706  assert_equal(2, g:glob)
1707  if true
1708    execute('g:glob = 3')
1709  endif
1710  assert_equal(3, g:glob)
1711
1712  res = false
1713  if g:bool_true ? true : false
1714    res = true
1715  endif
1716  assert_equal(true, res)
1717
1718  res = false
1719  if true ? g:bool_true : false
1720    res = true
1721  endif
1722  assert_equal(true, res)
1723
1724  res = false
1725  if true ? true : g:bool_false
1726    res = true
1727  endif
1728  assert_equal(true, res)
1729
1730  res = false
1731  if true ? false : true
1732    res = true
1733  endif
1734  assert_equal(false, res)
1735
1736  res = false
1737  if false ? false : true
1738    res = true
1739  endif
1740  assert_equal(true, res)
1741
1742  res = false
1743  if false ? true : false
1744    res = true
1745  endif
1746  assert_equal(false, res)
1747
1748  res = false
1749  if has('xyz') ? true : false
1750    res = true
1751  endif
1752  assert_equal(false, res)
1753
1754  res = false
1755  if true && true
1756    res = true
1757  endif
1758  assert_equal(true, res)
1759
1760  res = false
1761  if true && false
1762    res = true
1763  endif
1764  assert_equal(false, res)
1765
1766  res = false
1767  if g:bool_true && false
1768    res = true
1769  endif
1770  assert_equal(false, res)
1771
1772  res = false
1773  if true && g:bool_false
1774    res = true
1775  endif
1776  assert_equal(false, res)
1777
1778  res = false
1779  if false && false
1780    res = true
1781  endif
1782  assert_equal(false, res)
1783
1784  res = false
1785  if true || false
1786    res = true
1787  endif
1788  assert_equal(true, res)
1789
1790  res = false
1791  if g:bool_true || false
1792    res = true
1793  endif
1794  assert_equal(true, res)
1795
1796  res = false
1797  if true || g:bool_false
1798    res = true
1799  endif
1800  assert_equal(true, res)
1801
1802  res = false
1803  if false || false
1804    res = true
1805  endif
1806  assert_equal(false, res)
1807
1808  # with constant "false" expression may be invalid so long as the syntax is OK
1809  if false | eval 0 | endif
1810  if false | eval burp + 234 | endif
1811  if false | echo burp 234 'asd' | endif
1812  if false
1813    burp
1814  endif
1815enddef
1816
1817def Test_if_const_expr_fails()
1818  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
1819  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
1820  CheckDefFailure(["if has('aaa'"], 'E110:')
1821  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
1822enddef
1823
1824def RunNested(i: number): number
1825  var x: number = 0
1826  if i % 2
1827    if 1
1828      # comment
1829    else
1830      # comment
1831    endif
1832    x += 1
1833  else
1834    x += 1000
1835  endif
1836  return x
1837enddef
1838
1839def Test_nested_if()
1840  assert_equal(1, RunNested(1))
1841  assert_equal(1000, RunNested(2))
1842enddef
1843
1844def Test_execute_cmd()
1845  # missing argument is ignored
1846  execute
1847  execute # comment
1848
1849  new
1850  setline(1, 'default')
1851  execute 'setline(1, "execute-string")'
1852  assert_equal('execute-string', getline(1))
1853
1854  execute "setline(1, 'execute-string')"
1855  assert_equal('execute-string', getline(1))
1856
1857  var cmd1 = 'setline(1,'
1858  var cmd2 = '"execute-var")'
1859  execute cmd1 cmd2 # comment
1860  assert_equal('execute-var', getline(1))
1861
1862  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
1863  assert_equal('execute-var-string', getline(1))
1864
1865  var cmd_first = 'call '
1866  var cmd_last = 'setline(1, "execute-var-var")'
1867  execute cmd_first .. cmd_last
1868  assert_equal('execute-var-var', getline(1))
1869  bwipe!
1870
1871  var n = true
1872  execute 'echomsg' (n ? '"true"' : '"no"')
1873  assert_match('^true$', Screenline(&lines))
1874
1875  echomsg [1, 2, 3] {a: 1, b: 2}
1876  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
1877
1878  CheckDefFailure(['execute xxx'], 'E1001:', 1)
1879  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
1880  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
1881enddef
1882
1883def Test_execute_cmd_vimscript()
1884  # only checks line continuation
1885  var lines =<< trim END
1886      vim9script
1887      execute 'g:someVar'
1888                .. ' = ' ..
1889                   '28'
1890      assert_equal(28, g:someVar)
1891      unlet g:someVar
1892  END
1893  CheckScriptSuccess(lines)
1894enddef
1895
1896def Test_echo_cmd()
1897  echo 'some' # comment
1898  echon 'thing'
1899  assert_match('^something$', Screenline(&lines))
1900
1901  echo "some" # comment
1902  echon "thing"
1903  assert_match('^something$', Screenline(&lines))
1904
1905  var str1 = 'some'
1906  var str2 = 'more'
1907  echo str1 str2
1908  assert_match('^some more$', Screenline(&lines))
1909
1910  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
1911enddef
1912
1913def Test_echomsg_cmd()
1914  echomsg 'some' 'more' # comment
1915  assert_match('^some more$', Screenline(&lines))
1916  echo 'clear'
1917  :1messages
1918  assert_match('^some more$', Screenline(&lines))
1919
1920  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
1921enddef
1922
1923def Test_echomsg_cmd_vimscript()
1924  # only checks line continuation
1925  var lines =<< trim END
1926      vim9script
1927      echomsg 'here'
1928                .. ' is ' ..
1929                   'a message'
1930      assert_match('^here is a message$', Screenline(&lines))
1931  END
1932  CheckScriptSuccess(lines)
1933enddef
1934
1935def Test_echoerr_cmd()
1936  try
1937    echoerr 'something' 'wrong' # comment
1938  catch
1939    assert_match('something wrong', v:exception)
1940  endtry
1941enddef
1942
1943def Test_echoerr_cmd_vimscript()
1944  # only checks line continuation
1945  var lines =<< trim END
1946      vim9script
1947      try
1948        echoerr 'this'
1949                .. ' is ' ..
1950                   'wrong'
1951      catch
1952        assert_match('this is wrong', v:exception)
1953      endtry
1954  END
1955  CheckScriptSuccess(lines)
1956enddef
1957
1958def Test_for_outside_of_function()
1959  var lines =<< trim END
1960    vim9script
1961    new
1962    for var in range(0, 3)
1963      append(line('$'), var)
1964    endfor
1965    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
1966    bwipe!
1967  END
1968  writefile(lines, 'Xvim9for.vim')
1969  source Xvim9for.vim
1970  delete('Xvim9for.vim')
1971enddef
1972
1973def Test_for_loop()
1974  var result = ''
1975  for cnt in range(7)
1976    if cnt == 4
1977      break
1978    endif
1979    if cnt == 2
1980      continue
1981    endif
1982    result ..= cnt .. '_'
1983  endfor
1984  assert_equal('0_1_3_', result)
1985
1986  var concat = ''
1987  for str in eval('["one", "two"]')
1988    concat ..= str
1989  endfor
1990  assert_equal('onetwo', concat)
1991
1992  var total = 0
1993  for nr in
1994      [1, 2, 3]
1995    total += nr
1996  endfor
1997  assert_equal(6, total)
1998
1999  total = 0
2000  for nr
2001    in [1, 2, 3]
2002    total += nr
2003  endfor
2004  assert_equal(6, total)
2005
2006  total = 0
2007  for nr
2008    in
2009    [1, 2, 3]
2010    total += nr
2011  endfor
2012  assert_equal(6, total)
2013enddef
2014
2015def Test_for_loop_fails()
2016  CheckDefFailure(['for '], 'E1097:')
2017  CheckDefFailure(['for x'], 'E1097:')
2018  CheckDefFailure(['for x in'], 'E1097:')
2019  CheckDefFailure(['for # in range(5)'], 'E690:')
2020  CheckDefFailure(['for i In range(5)'], 'E690:')
2021  CheckDefFailure(['var x = 5', 'for x in range(5)'], 'E1017:')
2022  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2023  delfunc! g:Func
2024  CheckDefFailure(['for i in "text"'], 'E1012:')
2025  CheckDefFailure(['for i in xxx'], 'E1001:')
2026  CheckDefFailure(['endfor'], 'E588:')
2027  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2028enddef
2029
2030def Test_for_loop_script_var()
2031  # cannot use s:var in a :def function
2032  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2033
2034  # can use s:var in Vim9 script, with or without s:
2035  var lines =<< trim END
2036    vim9script
2037    var total = 0
2038    for s:var in [1, 2, 3]
2039      total += s:var
2040    endfor
2041    assert_equal(6, total)
2042
2043    total = 0
2044    for var in [1, 2, 3]
2045      total += var
2046    endfor
2047    assert_equal(6, total)
2048  END
2049enddef
2050
2051def Test_for_loop_unpack()
2052  var lines =<< trim END
2053      var result = []
2054      for [v1, v2] in [[1, 2], [3, 4]]
2055        result->add(v1)
2056        result->add(v2)
2057      endfor
2058      assert_equal([1, 2, 3, 4], result)
2059
2060      result = []
2061      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2062        result->add(v1)
2063        result->add(v2)
2064        result->add(v3)
2065      endfor
2066      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2067
2068      result = []
2069      for [&ts, &sw] in [[1, 2], [3, 4]]
2070        result->add(&ts)
2071        result->add(&sw)
2072      endfor
2073      assert_equal([1, 2, 3, 4], result)
2074
2075      var slist: list<string>
2076      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2077        slist->add($LOOPVAR)
2078        slist->add(@r)
2079        slist->add(v:errmsg)
2080      endfor
2081      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2082
2083      slist = []
2084      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2085        slist->add(g:globalvar)
2086        slist->add(b:bufvar)
2087        slist->add(w:winvar)
2088        slist->add(t:tabvar)
2089      endfor
2090      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2091      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2092  END
2093  CheckDefAndScriptSuccess(lines)
2094
2095  lines =<< trim END
2096      for [v1, v2] in [[1, 2, 3], [3, 4]]
2097        echo v1 v2
2098      endfor
2099  END
2100  CheckDefExecFailure(lines, 'E710:', 1)
2101
2102  lines =<< trim END
2103      for [v1, v2] in [[1], [3, 4]]
2104        echo v1 v2
2105      endfor
2106  END
2107  CheckDefExecFailure(lines, 'E711:', 1)
2108
2109  lines =<< trim END
2110      for [v1, v1] in [[1, 2], [3, 4]]
2111        echo v1
2112      endfor
2113  END
2114  CheckDefExecFailure(lines, 'E1017:', 1)
2115enddef
2116
2117def Test_while_loop()
2118  var result = ''
2119  var cnt = 0
2120  while cnt < 555
2121    if cnt == 3
2122      break
2123    endif
2124    cnt += 1
2125    if cnt == 2
2126      continue
2127    endif
2128    result ..= cnt .. '_'
2129  endwhile
2130  assert_equal('1_3_', result)
2131enddef
2132
2133def Test_while_loop_fails()
2134  CheckDefFailure(['while xxx'], 'E1001:')
2135  CheckDefFailure(['endwhile'], 'E588:')
2136  CheckDefFailure(['continue'], 'E586:')
2137  CheckDefFailure(['if true', 'continue'], 'E586:')
2138  CheckDefFailure(['break'], 'E587:')
2139  CheckDefFailure(['if true', 'break'], 'E587:')
2140  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
2141enddef
2142
2143def Test_interrupt_loop()
2144  var caught = false
2145  var x = 0
2146  try
2147    while 1
2148      x += 1
2149      if x == 100
2150        feedkeys("\<C-C>", 'Lt')
2151      endif
2152    endwhile
2153  catch
2154    caught = true
2155    assert_equal(100, x)
2156  endtry
2157  assert_true(caught, 'should have caught an exception')
2158  # consume the CTRL-C
2159  getchar(0)
2160enddef
2161
2162def Test_automatic_line_continuation()
2163  var mylist = [
2164      'one',
2165      'two',
2166      'three',
2167      ] # comment
2168  assert_equal(['one', 'two', 'three'], mylist)
2169
2170  var mydict = {
2171      ['one']: 1,
2172      ['two']: 2,
2173      ['three']:
2174          3,
2175      } # comment
2176  assert_equal({one: 1, two: 2, three: 3}, mydict)
2177  mydict = {
2178      one: 1,  # comment
2179      two:     # comment
2180           2,  # comment
2181      three: 3 # comment
2182      }
2183  assert_equal({one: 1, two: 2, three: 3}, mydict)
2184  mydict = {
2185      one: 1,
2186      two:
2187           2,
2188      three: 3
2189      }
2190  assert_equal({one: 1, two: 2, three: 3}, mydict)
2191
2192  assert_equal(
2193        ['one', 'two', 'three'],
2194        split('one two three')
2195        )
2196enddef
2197
2198def Test_vim9_comment()
2199  CheckScriptSuccess([
2200      'vim9script',
2201      '# something',
2202      '#something',
2203      '#{something',
2204      ])
2205
2206  split Xfile
2207  CheckScriptSuccess([
2208      'vim9script',
2209      'edit #something',
2210      ])
2211  CheckScriptSuccess([
2212      'vim9script',
2213      'edit #{something',
2214      ])
2215  close
2216
2217  CheckScriptFailure([
2218      'vim9script',
2219      ':# something',
2220      ], 'E488:')
2221  CheckScriptFailure([
2222      '# something',
2223      ], 'E488:')
2224  CheckScriptFailure([
2225      ':# something',
2226      ], 'E488:')
2227
2228  { # block start
2229  } # block end
2230  CheckDefFailure([
2231      '{# comment',
2232      ], 'E488:')
2233  CheckDefFailure([
2234      '{',
2235      '}# comment',
2236      ], 'E488:')
2237
2238  echo "yes" # comment
2239  CheckDefFailure([
2240      'echo "yes"# comment',
2241      ], 'E488:')
2242  CheckScriptSuccess([
2243      'vim9script',
2244      'echo "yes" # something',
2245      ])
2246  CheckScriptFailure([
2247      'vim9script',
2248      'echo "yes"# something',
2249      ], 'E121:')
2250  CheckScriptFailure([
2251      'vim9script',
2252      'echo# something',
2253      ], 'E1144:')
2254  CheckScriptFailure([
2255      'echo "yes" # something',
2256      ], 'E121:')
2257
2258  exe "echo" # comment
2259  CheckDefFailure([
2260      'exe "echo"# comment',
2261      ], 'E488:')
2262  CheckScriptSuccess([
2263      'vim9script',
2264      'exe "echo" # something',
2265      ])
2266  CheckScriptFailure([
2267      'vim9script',
2268      'exe "echo"# something',
2269      ], 'E121:')
2270  CheckScriptFailure([
2271      'vim9script',
2272      'exe# something',
2273      ], 'E1144:')
2274  CheckScriptFailure([
2275      'exe "echo" # something',
2276      ], 'E121:')
2277
2278  CheckDefFailure([
2279      'try# comment',
2280      '  echo "yes"',
2281      'catch',
2282      'endtry',
2283      ], 'E1144:')
2284  CheckScriptFailure([
2285      'vim9script',
2286      'try# comment',
2287      'echo "yes"',
2288      ], 'E1144:')
2289  CheckDefFailure([
2290      'try',
2291      '  throw#comment',
2292      'catch',
2293      'endtry',
2294      ], 'E1144:')
2295  CheckDefFailure([
2296      'try',
2297      '  throw "yes"#comment',
2298      'catch',
2299      'endtry',
2300      ], 'E488:')
2301  CheckDefFailure([
2302      'try',
2303      '  echo "yes"',
2304      'catch# comment',
2305      'endtry',
2306      ], 'E1144:')
2307  CheckScriptFailure([
2308      'vim9script',
2309      'try',
2310      '  echo "yes"',
2311      'catch# comment',
2312      'endtry',
2313      ], 'E1144:')
2314  CheckDefFailure([
2315      'try',
2316      '  echo "yes"',
2317      'catch /pat/# comment',
2318      'endtry',
2319      ], 'E488:')
2320  CheckDefFailure([
2321      'try',
2322      'echo "yes"',
2323      'catch',
2324      'endtry# comment',
2325      ], 'E1144:')
2326  CheckScriptFailure([
2327      'vim9script',
2328      'try',
2329      '  echo "yes"',
2330      'catch',
2331      'endtry# comment',
2332      ], 'E1144:')
2333
2334  CheckScriptSuccess([
2335      'vim9script',
2336      'hi # comment',
2337      ])
2338  CheckScriptFailure([
2339      'vim9script',
2340      'hi# comment',
2341      ], 'E1144:')
2342  CheckScriptSuccess([
2343      'vim9script',
2344      'hi Search # comment',
2345      ])
2346  CheckScriptFailure([
2347      'vim9script',
2348      'hi Search# comment',
2349      ], 'E416:')
2350  CheckScriptSuccess([
2351      'vim9script',
2352      'hi link This Search # comment',
2353      ])
2354  CheckScriptFailure([
2355      'vim9script',
2356      'hi link This That# comment',
2357      ], 'E413:')
2358  CheckScriptSuccess([
2359      'vim9script',
2360      'hi clear This # comment',
2361      'hi clear # comment',
2362      ])
2363  # not tested, because it doesn't give an error but a warning:
2364  # hi clear This# comment',
2365  CheckScriptFailure([
2366      'vim9script',
2367      'hi clear# comment',
2368      ], 'E416:')
2369
2370  CheckScriptSuccess([
2371      'vim9script',
2372      'hi Group term=bold',
2373      'match Group /todo/ # comment',
2374      ])
2375  CheckScriptFailure([
2376      'vim9script',
2377      'hi Group term=bold',
2378      'match Group /todo/# comment',
2379      ], 'E488:')
2380  CheckScriptSuccess([
2381      'vim9script',
2382      'match # comment',
2383      ])
2384  CheckScriptFailure([
2385      'vim9script',
2386      'match# comment',
2387      ], 'E1144:')
2388  CheckScriptSuccess([
2389      'vim9script',
2390      'match none # comment',
2391      ])
2392  CheckScriptFailure([
2393      'vim9script',
2394      'match none# comment',
2395      ], 'E475:')
2396
2397  CheckScriptSuccess([
2398      'vim9script',
2399      'menutrans clear # comment',
2400      ])
2401  CheckScriptFailure([
2402      'vim9script',
2403      'menutrans clear# comment text',
2404      ], 'E474:')
2405
2406  CheckScriptSuccess([
2407      'vim9script',
2408      'syntax clear # comment',
2409      ])
2410  CheckScriptFailure([
2411      'vim9script',
2412      'syntax clear# comment text',
2413      ], 'E28:')
2414  CheckScriptSuccess([
2415      'vim9script',
2416      'syntax keyword Word some',
2417      'syntax clear Word # comment',
2418      ])
2419  CheckScriptFailure([
2420      'vim9script',
2421      'syntax keyword Word some',
2422      'syntax clear Word# comment text',
2423      ], 'E28:')
2424
2425  CheckScriptSuccess([
2426      'vim9script',
2427      'syntax list # comment',
2428      ])
2429  CheckScriptFailure([
2430      'vim9script',
2431      'syntax list# comment text',
2432      ], 'E28:')
2433
2434  CheckScriptSuccess([
2435      'vim9script',
2436      'syntax match Word /pat/ oneline # comment',
2437      ])
2438  CheckScriptFailure([
2439      'vim9script',
2440      'syntax match Word /pat/ oneline# comment',
2441      ], 'E475:')
2442
2443  CheckScriptSuccess([
2444      'vim9script',
2445      'syntax keyword Word word # comm[ent',
2446      ])
2447  CheckScriptFailure([
2448      'vim9script',
2449      'syntax keyword Word word# comm[ent',
2450      ], 'E789:')
2451
2452  CheckScriptSuccess([
2453      'vim9script',
2454      'syntax match Word /pat/ # comment',
2455      ])
2456  CheckScriptFailure([
2457      'vim9script',
2458      'syntax match Word /pat/# comment',
2459      ], 'E402:')
2460
2461  CheckScriptSuccess([
2462      'vim9script',
2463      'syntax match Word /pat/ contains=Something # comment',
2464      ])
2465  CheckScriptFailure([
2466      'vim9script',
2467      'syntax match Word /pat/ contains=Something# comment',
2468      ], 'E475:')
2469  CheckScriptFailure([
2470      'vim9script',
2471      'syntax match Word /pat/ contains= # comment',
2472      ], 'E406:')
2473  CheckScriptFailure([
2474      'vim9script',
2475      'syntax match Word /pat/ contains=# comment',
2476      ], 'E475:')
2477
2478  CheckScriptSuccess([
2479      'vim9script',
2480      'syntax region Word start=/pat/ end=/pat/ # comment',
2481      ])
2482  CheckScriptFailure([
2483      'vim9script',
2484      'syntax region Word start=/pat/ end=/pat/# comment',
2485      ], 'E402:')
2486
2487  CheckScriptSuccess([
2488      'vim9script',
2489      'syntax sync # comment',
2490      ])
2491  CheckScriptFailure([
2492      'vim9script',
2493      'syntax sync# comment',
2494      ], 'E404:')
2495  CheckScriptSuccess([
2496      'vim9script',
2497      'syntax sync ccomment # comment',
2498      ])
2499  CheckScriptFailure([
2500      'vim9script',
2501      'syntax sync ccomment# comment',
2502      ], 'E404:')
2503
2504  CheckScriptSuccess([
2505      'vim9script',
2506      'syntax cluster Some contains=Word # comment',
2507      ])
2508  CheckScriptFailure([
2509      'vim9script',
2510      'syntax cluster Some contains=Word# comment',
2511      ], 'E475:')
2512
2513  CheckScriptSuccess([
2514      'vim9script',
2515      'command Echo echo # comment',
2516      'command Echo # comment',
2517      'delcommand Echo',
2518      ])
2519  CheckScriptFailure([
2520      'vim9script',
2521      'command Echo echo# comment',
2522      'Echo',
2523      ], 'E1144:')
2524  delcommand Echo
2525
2526  var curdir = getcwd()
2527  CheckScriptSuccess([
2528      'command Echo cd " comment',
2529      'Echo',
2530      'delcommand Echo',
2531      ])
2532  CheckScriptSuccess([
2533      'vim9script',
2534      'command Echo cd # comment',
2535      'Echo',
2536      'delcommand Echo',
2537      ])
2538  CheckScriptFailure([
2539      'vim9script',
2540      'command Echo cd " comment',
2541      'Echo',
2542      ], 'E344:')
2543  delcommand Echo
2544  chdir(curdir)
2545
2546  CheckScriptFailure([
2547      'vim9script',
2548      'command Echo# comment',
2549      ], 'E182:')
2550  CheckScriptFailure([
2551      'vim9script',
2552      'command Echo echo',
2553      'command Echo# comment',
2554      ], 'E182:')
2555  delcommand Echo
2556
2557  CheckScriptSuccess([
2558      'vim9script',
2559      'function # comment',
2560      ])
2561  CheckScriptFailure([
2562      'vim9script',
2563      'function " comment',
2564      ], 'E129:')
2565  CheckScriptFailure([
2566      'vim9script',
2567      'function# comment',
2568      ], 'E1144:')
2569  CheckScriptSuccess([
2570      'vim9script',
2571      'function CheckScriptSuccess # comment',
2572      ])
2573  CheckScriptFailure([
2574      'vim9script',
2575      'function CheckScriptSuccess# comment',
2576      ], 'E488:')
2577
2578  CheckScriptSuccess([
2579      'vim9script',
2580      'func g:DeleteMeA()',
2581      'endfunc',
2582      'delfunction g:DeleteMeA # comment',
2583      ])
2584  CheckScriptFailure([
2585      'vim9script',
2586      'func g:DeleteMeB()',
2587      'endfunc',
2588      'delfunction g:DeleteMeB# comment',
2589      ], 'E488:')
2590
2591  CheckScriptSuccess([
2592      'vim9script',
2593      'call execute("ls") # comment',
2594      ])
2595  CheckScriptFailure([
2596      'vim9script',
2597      'call execute("ls")# comment',
2598      ], 'E488:')
2599
2600  CheckScriptFailure([
2601      'def Test() " comment',
2602      'enddef',
2603      ], 'E488:')
2604  CheckScriptFailure([
2605      'vim9script',
2606      'def Test() " comment',
2607      'enddef',
2608      ], 'E488:')
2609
2610  CheckScriptSuccess([
2611      'func Test() " comment',
2612      'endfunc',
2613      'delfunc Test',
2614      ])
2615  CheckScriptSuccess([
2616      'vim9script',
2617      'func Test() " comment',
2618      'endfunc',
2619      ])
2620
2621  CheckScriptSuccess([
2622      'def Test() # comment',
2623      'enddef',
2624      ])
2625  CheckScriptFailure([
2626      'func Test() # comment',
2627      'endfunc',
2628      ], 'E488:')
2629enddef
2630
2631def Test_vim9_comment_gui()
2632  CheckCanRunGui
2633
2634  CheckScriptFailure([
2635      'vim9script',
2636      'gui#comment'
2637      ], 'E1144:')
2638  CheckScriptFailure([
2639      'vim9script',
2640      'gui -f#comment'
2641      ], 'E499:')
2642enddef
2643
2644def Test_vim9_comment_not_compiled()
2645  au TabEnter *.vim g:entered = 1
2646  au TabEnter *.x g:entered = 2
2647
2648  edit test.vim
2649  doautocmd TabEnter #comment
2650  assert_equal(1, g:entered)
2651
2652  doautocmd TabEnter f.x
2653  assert_equal(2, g:entered)
2654
2655  g:entered = 0
2656  doautocmd TabEnter f.x #comment
2657  assert_equal(2, g:entered)
2658
2659  assert_fails('doautocmd Syntax#comment', 'E216:')
2660
2661  au! TabEnter
2662  unlet g:entered
2663
2664  CheckScriptSuccess([
2665      'vim9script',
2666      'g:var = 123',
2667      'b:var = 456',
2668      'w:var = 777',
2669      't:var = 888',
2670      'unlet g:var w:var # something',
2671      ])
2672
2673  CheckScriptFailure([
2674      'vim9script',
2675      'let var = 123',
2676      ], 'E1126: Cannot use :let in Vim9 script')
2677
2678  CheckScriptFailure([
2679      'vim9script',
2680      'var g:var = 123',
2681      ], 'E1016: Cannot declare a global variable:')
2682
2683  CheckScriptFailure([
2684      'vim9script',
2685      'var b:var = 123',
2686      ], 'E1016: Cannot declare a buffer variable:')
2687
2688  CheckScriptFailure([
2689      'vim9script',
2690      'var w:var = 123',
2691      ], 'E1016: Cannot declare a window variable:')
2692
2693  CheckScriptFailure([
2694      'vim9script',
2695      'var t:var = 123',
2696      ], 'E1016: Cannot declare a tab variable:')
2697
2698  CheckScriptFailure([
2699      'vim9script',
2700      'var v:version = 123',
2701      ], 'E1016: Cannot declare a v: variable:')
2702
2703  CheckScriptFailure([
2704      'vim9script',
2705      'var $VARIABLE = "text"',
2706      ], 'E1016: Cannot declare an environment variable:')
2707
2708  CheckScriptFailure([
2709      'vim9script',
2710      'g:var = 123',
2711      'unlet g:var# comment1',
2712      ], 'E108:')
2713
2714  CheckScriptFailure([
2715      'let g:var = 123',
2716      'unlet g:var # something',
2717      ], 'E488:')
2718
2719  CheckScriptSuccess([
2720      'vim9script',
2721      'if 1 # comment2',
2722      '  echo "yes"',
2723      'elseif 2 #comment',
2724      '  echo "no"',
2725      'endif',
2726      ])
2727
2728  CheckScriptFailure([
2729      'vim9script',
2730      'if 1# comment3',
2731      '  echo "yes"',
2732      'endif',
2733      ], 'E15:')
2734
2735  CheckScriptFailure([
2736      'vim9script',
2737      'if 0 # comment4',
2738      '  echo "yes"',
2739      'elseif 2#comment',
2740      '  echo "no"',
2741      'endif',
2742      ], 'E15:')
2743
2744  CheckScriptSuccess([
2745      'vim9script',
2746      'var v = 1 # comment5',
2747      ])
2748
2749  CheckScriptFailure([
2750      'vim9script',
2751      'var v = 1# comment6',
2752      ], 'E15:')
2753
2754  CheckScriptSuccess([
2755      'vim9script',
2756      'new'
2757      'setline(1, ["# define pat", "last"])',
2758      ':$',
2759      'dsearch /pat/ #comment',
2760      'bwipe!',
2761      ])
2762
2763  CheckScriptFailure([
2764      'vim9script',
2765      'new'
2766      'setline(1, ["# define pat", "last"])',
2767      ':$',
2768      'dsearch /pat/#comment',
2769      'bwipe!',
2770      ], 'E488:')
2771
2772  CheckScriptFailure([
2773      'vim9script',
2774      'func! SomeFunc()',
2775      ], 'E477:')
2776enddef
2777
2778def Test_finish()
2779  var lines =<< trim END
2780    vim9script
2781    g:res = 'one'
2782    if v:false | finish | endif
2783    g:res = 'two'
2784    finish
2785    g:res = 'three'
2786  END
2787  writefile(lines, 'Xfinished')
2788  source Xfinished
2789  assert_equal('two', g:res)
2790
2791  unlet g:res
2792  delete('Xfinished')
2793enddef
2794
2795def Test_forward_declaration()
2796  var lines =<< trim END
2797    vim9script
2798    def GetValue(): string
2799      return theVal
2800    enddef
2801    var theVal = 'something'
2802    g:initVal = GetValue()
2803    theVal = 'else'
2804    g:laterVal = GetValue()
2805  END
2806  writefile(lines, 'Xforward')
2807  source Xforward
2808  assert_equal('something', g:initVal)
2809  assert_equal('else', g:laterVal)
2810
2811  unlet g:initVal
2812  unlet g:laterVal
2813  delete('Xforward')
2814enddef
2815
2816def Test_source_vim9_from_legacy()
2817  var vim9_lines =<< trim END
2818    vim9script
2819    var local = 'local'
2820    g:global = 'global'
2821    export var exported = 'exported'
2822    export def GetText(): string
2823       return 'text'
2824    enddef
2825  END
2826  writefile(vim9_lines, 'Xvim9_script.vim')
2827
2828  var legacy_lines =<< trim END
2829    source Xvim9_script.vim
2830
2831    call assert_false(exists('local'))
2832    call assert_false(exists('exported'))
2833    call assert_false(exists('s:exported'))
2834    call assert_equal('global', global)
2835    call assert_equal('global', g:global)
2836
2837    " imported variable becomes script-local
2838    import exported from './Xvim9_script.vim'
2839    call assert_equal('exported', s:exported)
2840    call assert_false(exists('exported'))
2841
2842    " imported function becomes script-local
2843    import GetText from './Xvim9_script.vim'
2844    call assert_equal('text', s:GetText())
2845    call assert_false(exists('*GetText'))
2846  END
2847  writefile(legacy_lines, 'Xlegacy_script.vim')
2848
2849  source Xlegacy_script.vim
2850  assert_equal('global', g:global)
2851  unlet g:global
2852
2853  delete('Xlegacy_script.vim')
2854  delete('Xvim9_script.vim')
2855enddef
2856
2857func Test_vim9script_not_global()
2858  " check that items defined in Vim9 script are script-local, not global
2859  let vim9lines =<< trim END
2860    vim9script
2861    var name = 'local'
2862    func TheFunc()
2863      echo 'local'
2864    endfunc
2865    def DefFunc()
2866      echo 'local'
2867    enddef
2868  END
2869  call writefile(vim9lines, 'Xvim9script.vim')
2870  source Xvim9script.vim
2871  try
2872    echo g:var
2873    assert_report('did not fail')
2874  catch /E121:/
2875    " caught
2876  endtry
2877  try
2878    call TheFunc()
2879    assert_report('did not fail')
2880  catch /E117:/
2881    " caught
2882  endtry
2883  try
2884    call DefFunc()
2885    assert_report('did not fail')
2886  catch /E117:/
2887    " caught
2888  endtry
2889
2890  call delete('Xvim9script.vim')
2891endfunc
2892
2893def Test_vim9_copen()
2894  # this was giving an error for setting w:quickfix_title
2895  copen
2896  quit
2897enddef
2898
2899" test using an auto-loaded function and variable
2900def Test_vim9_autoload()
2901  var lines =<< trim END
2902     vim9script
2903     def some#gettest(): string
2904       return 'test'
2905     enddef
2906     g:some#name = 'name'
2907  END
2908
2909  mkdir('Xdir/autoload', 'p')
2910  writefile(lines, 'Xdir/autoload/some.vim')
2911  var save_rtp = &rtp
2912  exe 'set rtp^=' .. getcwd() .. '/Xdir'
2913
2914  assert_equal('test', g:some#gettest())
2915  assert_equal('name', g:some#name)
2916  g:some#other = 'other'
2917  assert_equal('other', g:some#other)
2918
2919  # upper case script name works
2920  lines =<< trim END
2921     vim9script
2922     def Other#getOther(): string
2923       return 'other'
2924     enddef
2925  END
2926  writefile(lines, 'Xdir/autoload/Other.vim')
2927  assert_equal('other', g:Other#getOther())
2928
2929  delete('Xdir', 'rf')
2930  &rtp = save_rtp
2931enddef
2932
2933" test using a vim9script that is auto-loaded from an autocmd
2934def Test_vim9_aucmd_autoload()
2935  var lines =<< trim END
2936     vim9script
2937     def foo#test()
2938         echomsg getreg('"')
2939     enddef
2940  END
2941
2942  mkdir('Xdir/autoload', 'p')
2943  writefile(lines, 'Xdir/autoload/foo.vim')
2944  var save_rtp = &rtp
2945  exe 'set rtp^=' .. getcwd() .. '/Xdir'
2946  augroup test
2947    autocmd TextYankPost * call foo#test()
2948  augroup END
2949
2950  normal Y
2951
2952  augroup test
2953    autocmd!
2954  augroup END
2955  delete('Xdir', 'rf')
2956  &rtp = save_rtp
2957enddef
2958
2959" This was causing a crash because suppress_errthrow wasn't reset.
2960def Test_vim9_autoload_error()
2961  var lines =<< trim END
2962      vim9script
2963      def crash#func()
2964          try
2965              for x in List()
2966              endfor
2967          catch
2968          endtry
2969          g:ok = true
2970      enddef
2971      fu List()
2972          invalid
2973      endfu
2974      try
2975          alsoinvalid
2976      catch /wontmatch/
2977      endtry
2978  END
2979  call mkdir('Xruntime/autoload', 'p')
2980  call writefile(lines, 'Xruntime/autoload/crash.vim')
2981
2982  # run in a separate Vim to avoid the side effects of assert_fails()
2983  lines =<< trim END
2984    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
2985    call crash#func()
2986    call writefile(['ok'], 'Xdidit')
2987    qall!
2988  END
2989  writefile(lines, 'Xscript')
2990  RunVim([], [], '-S Xscript')
2991  assert_equal(['ok'], readfile('Xdidit'))
2992
2993  delete('Xdidit')
2994  delete('Xscript')
2995  delete('Xruntime', 'rf')
2996
2997  lines =<< trim END
2998    vim9script
2999    var foo#bar = 'asdf'
3000  END
3001  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
3002enddef
3003
3004def Test_script_var_in_autocmd()
3005  # using a script variable from an autocommand, defined in a :def function in a
3006  # legacy Vim script, cannot check the variable type.
3007  var lines =<< trim END
3008    let s:counter = 1
3009    def s:Func()
3010      au! CursorHold
3011      au CursorHold * s:counter += 1
3012    enddef
3013    call s:Func()
3014    doau CursorHold
3015    call assert_equal(2, s:counter)
3016    au! CursorHold
3017  END
3018  CheckScriptSuccess(lines)
3019enddef
3020
3021def Test_cmdline_win()
3022  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
3023  # the command line window.
3024  mkdir('rtp/syntax', 'p')
3025  var export_lines =<< trim END
3026    vim9script
3027    export var That = 'yes'
3028  END
3029  writefile(export_lines, 'rtp/syntax/Xexport.vim')
3030  var import_lines =<< trim END
3031    vim9script
3032    import That from './Xexport.vim'
3033  END
3034  writefile(import_lines, 'rtp/syntax/vim.vim')
3035  var save_rtp = &rtp
3036  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
3037  syntax on
3038  augroup CmdWin
3039    autocmd CmdwinEnter * g:got_there = 'yes'
3040  augroup END
3041  # this will open and also close the cmdline window
3042  feedkeys('q:', 'xt')
3043  assert_equal('yes', g:got_there)
3044
3045  augroup CmdWin
3046    au!
3047  augroup END
3048  &rtp = save_rtp
3049  delete('rtp', 'rf')
3050enddef
3051
3052def Test_invalid_sid()
3053  assert_fails('func <SNR>1234_func', 'E123:')
3054
3055  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
3056    assert_equal([], readfile('Xdidit'))
3057  endif
3058  delete('Xdidit')
3059enddef
3060
3061def Test_restoring_cpo()
3062  writefile(['vim9script', 'set nocp'], 'Xsourced')
3063  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
3064  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
3065    assert_equal(['done'], readfile('Xdone'))
3066  endif
3067  delete('Xsourced')
3068  delete('Xclose')
3069  delete('Xdone')
3070enddef
3071
3072
3073def Test_unset_any_variable()
3074  var lines =<< trim END
3075    var name: any
3076    assert_equal(0, name)
3077  END
3078  CheckDefAndScriptSuccess(lines)
3079enddef
3080
3081func Test_define_func_at_command_line()
3082  CheckRunVimInTerminal
3083
3084  " call indirectly to avoid compilation error for missing functions
3085  call Run_Test_define_func_at_command_line()
3086endfunc
3087
3088def Run_Test_define_func_at_command_line()
3089  # run in a separate Vim instance to avoid the script context
3090  var lines =<< trim END
3091    func CheckAndQuit()
3092      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
3093      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
3094    endfunc
3095  END
3096  writefile([''], 'Xdidcmd')
3097  writefile(lines, 'XcallFunc')
3098  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
3099  # define Afunc() on the command line
3100  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
3101  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
3102  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
3103
3104  call StopVimInTerminal(buf)
3105  delete('XcallFunc')
3106  delete('Xdidcmd')
3107enddef
3108
3109def Test_script_var_scope()
3110  var lines =<< trim END
3111      vim9script
3112      if true
3113        if true
3114          var one = 'one'
3115          echo one
3116        endif
3117        echo one
3118      endif
3119  END
3120  CheckScriptFailure(lines, 'E121:', 7)
3121
3122  lines =<< trim END
3123      vim9script
3124      if true
3125        if false
3126          var one = 'one'
3127          echo one
3128        else
3129          var one = 'one'
3130          echo one
3131        endif
3132        echo one
3133      endif
3134  END
3135  CheckScriptFailure(lines, 'E121:', 10)
3136
3137  lines =<< trim END
3138      vim9script
3139      while true
3140        var one = 'one'
3141        echo one
3142        break
3143      endwhile
3144      echo one
3145  END
3146  CheckScriptFailure(lines, 'E121:', 7)
3147
3148  lines =<< trim END
3149      vim9script
3150      for i in range(1)
3151        var one = 'one'
3152        echo one
3153      endfor
3154      echo one
3155  END
3156  CheckScriptFailure(lines, 'E121:', 6)
3157
3158  lines =<< trim END
3159      vim9script
3160      {
3161        var one = 'one'
3162        assert_equal('one', one)
3163      }
3164      assert_false(exists('one'))
3165      assert_false(exists('s:one'))
3166  END
3167  CheckScriptSuccess(lines)
3168
3169  lines =<< trim END
3170      vim9script
3171      {
3172        var one = 'one'
3173        echo one
3174      }
3175      echo one
3176  END
3177  CheckScriptFailure(lines, 'E121:', 6)
3178enddef
3179
3180def Test_catch_exception_in_callback()
3181  var lines =<< trim END
3182    vim9script
3183    def Callback(...l: any)
3184      try
3185        var x: string
3186        var y: string
3187        # this error should be caught with CHECKLEN
3188        [x, y] = ['']
3189      catch
3190        g:caught = 'yes'
3191      endtry
3192    enddef
3193    popup_menu('popup', {callback: Callback})
3194    feedkeys("\r", 'xt')
3195  END
3196  CheckScriptSuccess(lines)
3197
3198  unlet g:caught
3199enddef
3200
3201def Test_no_unknown_error_after_error()
3202  if !has('unix') || !has('job')
3203    throw 'Skipped: not unix of missing +job feature'
3204  endif
3205  var lines =<< trim END
3206      vim9script
3207      var source: list<number>
3208      def Out_cb(...l: any)
3209          eval [][0]
3210      enddef
3211      def Exit_cb(...l: any)
3212          sleep 1m
3213          source += l
3214      enddef
3215      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
3216      while job_status(myjob) == 'run'
3217        sleep 10m
3218      endwhile
3219      sleep 10m
3220  END
3221  writefile(lines, 'Xdef')
3222  assert_fails('so Xdef', ['E684:', 'E1012:'])
3223  delete('Xdef')
3224enddef
3225
3226def InvokeNormal()
3227  exe "norm! :m+1\r"
3228enddef
3229
3230def Test_invoke_normal_in_visual_mode()
3231  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
3232  new
3233  setline(1, ['aaa', 'bbb'])
3234  feedkeys("V\<F3>", 'xt')
3235  assert_equal(['bbb', 'aaa'], getline(1, 2))
3236  xunmap <F3>
3237enddef
3238
3239def Test_white_space_after_command()
3240  var lines =<< trim END
3241    exit_cb: Func})
3242  END
3243  CheckDefAndScriptFailure(lines, 'E1144:', 1)
3244
3245  lines =<< trim END
3246    e#
3247  END
3248  CheckDefAndScriptFailure(lines, 'E1144:', 1)
3249enddef
3250
3251def Test_script_var_gone_when_sourced_twice()
3252  var lines =<< trim END
3253      vim9script
3254      if exists('g:guard')
3255        finish
3256      endif
3257      g:guard = 1
3258      var name = 'thename'
3259      def g:GetName(): string
3260        return name
3261      enddef
3262      def g:SetName(arg: string)
3263        name = arg
3264      enddef
3265  END
3266  writefile(lines, 'XscriptTwice.vim')
3267  so XscriptTwice.vim
3268  assert_equal('thename', g:GetName())
3269  g:SetName('newname')
3270  assert_equal('newname', g:GetName())
3271  so XscriptTwice.vim
3272  assert_fails('call g:GetName()', 'E1149:')
3273  assert_fails('call g:SetName("x")', 'E1149:')
3274
3275  delfunc g:GetName
3276  delfunc g:SetName
3277  delete('XscriptTwice.vim')
3278  unlet g:guard
3279enddef
3280
3281def Test_import_gone_when_sourced_twice()
3282  var exportlines =<< trim END
3283      vim9script
3284      if exists('g:guard')
3285        finish
3286      endif
3287      g:guard = 1
3288      export var name = 'someName'
3289  END
3290  writefile(exportlines, 'XexportScript.vim')
3291
3292  var lines =<< trim END
3293      vim9script
3294      import name from './XexportScript.vim'
3295      def g:GetName(): string
3296        return name
3297      enddef
3298  END
3299  writefile(lines, 'XscriptImport.vim')
3300  so XscriptImport.vim
3301  assert_equal('someName', g:GetName())
3302
3303  so XexportScript.vim
3304  assert_fails('call g:GetName()', 'E1149:')
3305
3306  delfunc g:GetName
3307  delete('XexportScript.vim')
3308  delete('XscriptImport.vim')
3309  unlet g:guard
3310enddef
3311
3312" Keep this last, it messes up highlighting.
3313def Test_substitute_cmd()
3314  new
3315  setline(1, 'something')
3316  :substitute(some(other(
3317  assert_equal('otherthing', getline(1))
3318  bwipe!
3319
3320  # also when the context is Vim9 script
3321  var lines =<< trim END
3322    vim9script
3323    new
3324    setline(1, 'something')
3325    :substitute(some(other(
3326    assert_equal('otherthing', getline(1))
3327    bwipe!
3328  END
3329  writefile(lines, 'Xvim9lines')
3330  source Xvim9lines
3331
3332  delete('Xvim9lines')
3333enddef
3334
3335" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
3336