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 screendump.vim 8 9func Test_def_basic() 10 def SomeFunc(): string 11 return 'yes' 12 enddef 13 call SomeFunc()->assert_equal('yes') 14endfunc 15 16func Test_compiling_error() 17 " use a terminal to see the whole error message 18 CheckRunVimInTerminal 19 20 call TestCompilingError() 21 call TestCompilingErrorInTry() 22endfunc 23 24def TestCompilingError() 25 var lines =<< trim END 26 vim9script 27 def Fails() 28 echo nothing 29 enddef 30 defcompile 31 END 32 writefile(lines, 'XTest_compile_error') 33 var buf = RunVimInTerminal('-S XTest_compile_error', 34 {rows: 10, wait_for_ruler: 0}) 35 WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', 36 Term_getlines(buf, range(1, 9)))) 37 38 # clean up 39 StopVimInTerminal(buf) 40 delete('XTest_compile_error') 41enddef 42 43def TestCompilingErrorInTry() 44 var dir = 'Xdir/autoload' 45 mkdir(dir, 'p') 46 47 var lines =<< trim END 48 vim9script 49 def script#OnlyCompiled() 50 g:runtime = 'yes' 51 invalid 52 enddef 53 END 54 writefile(lines, dir .. '/script.vim') 55 56 lines =<< trim END 57 vim9script 58 todo 59 try 60 script#OnlyCompiled() 61 catch /nothing/ 62 endtry 63 END 64 lines[1] = 'set rtp=' .. getcwd() .. '/Xdir' 65 writefile(lines, 'XTest_compile_error') 66 67 var buf = RunVimInTerminal('-S XTest_compile_error', {rows: 10, wait_for_ruler: 0}) 68 WaitForAssert(() => assert_match('Error detected while compiling command line.*function script#OnlyCompiled.*Invalid command: invalid', 69 Term_getlines(buf, range(1, 9)))) 70 71 # clean up 72 StopVimInTerminal(buf) 73 delete('XTest_compile_error') 74 delete('Xdir', 'rf') 75enddef 76 77def Test_compile_error_in_called_function() 78 var lines =<< trim END 79 vim9script 80 var n: number 81 def Foo() 82 &hls = n 83 enddef 84 def Bar() 85 Foo() 86 enddef 87 silent! Foo() 88 Bar() 89 END 90 CheckScriptFailureList(lines, ['E1012:', 'E1191:']) 91enddef 92 93def Test_wrong_function_name() 94 var lines =<< trim END 95 vim9script 96 func _Foo() 97 echo 'foo' 98 endfunc 99 END 100 CheckScriptFailure(lines, 'E128:') 101 102 lines =<< trim END 103 vim9script 104 def _Foo() 105 echo 'foo' 106 enddef 107 END 108 CheckScriptFailure(lines, 'E128:') 109enddef 110 111def Test_autoload_name_mismatch() 112 var dir = 'Xdir/autoload' 113 mkdir(dir, 'p') 114 115 var lines =<< trim END 116 vim9script 117 def scriptX#Function() 118 # comment 119 g:runtime = 'yes' 120 enddef 121 END 122 writefile(lines, dir .. '/script.vim') 123 124 var save_rtp = &rtp 125 exe 'set rtp=' .. getcwd() .. '/Xdir' 126 lines =<< trim END 127 call script#Function() 128 END 129 CheckScriptFailure(lines, 'E746:', 2) 130 131 &rtp = save_rtp 132 delete(dir, 'rf') 133enddef 134 135def Test_autoload_names() 136 var dir = 'Xdir/autoload' 137 mkdir(dir, 'p') 138 139 var lines =<< trim END 140 func foobar#function() 141 return 'yes' 142 endfunc 143 let foobar#var = 'no' 144 END 145 writefile(lines, dir .. '/foobar.vim') 146 147 var save_rtp = &rtp 148 exe 'set rtp=' .. getcwd() .. '/Xdir' 149 150 lines =<< trim END 151 assert_equal('yes', foobar#function()) 152 var Function = foobar#function 153 assert_equal('yes', Function()) 154 155 assert_equal('no', foobar#var) 156 END 157 CheckDefAndScriptSuccess(lines) 158 159 &rtp = save_rtp 160 delete(dir, 'rf') 161enddef 162 163def CallRecursive(n: number): number 164 return CallRecursive(n + 1) 165enddef 166 167def CallMapRecursive(l: list<number>): number 168 return map(l, (_, v) => CallMapRecursive([v]))[0] 169enddef 170 171def Test_funcdepth_error() 172 set maxfuncdepth=10 173 174 var caught = false 175 try 176 CallRecursive(1) 177 catch /E132:/ 178 caught = true 179 endtry 180 assert_true(caught) 181 182 caught = false 183 try 184 CallMapRecursive([1]) 185 catch /E132:/ 186 caught = true 187 endtry 188 assert_true(caught) 189 190 set maxfuncdepth& 191enddef 192 193def Test_endfunc_enddef() 194 var lines =<< trim END 195 def Test() 196 echo 'test' 197 endfunc 198 enddef 199 END 200 CheckScriptFailure(lines, 'E1151:', 3) 201 202 lines =<< trim END 203 def Test() 204 func Nested() 205 echo 'test' 206 enddef 207 enddef 208 END 209 CheckScriptFailure(lines, 'E1152:', 4) 210 211 lines =<< trim END 212 def Ok() 213 echo 'hello' 214 enddef | echo 'there' 215 def Bad() 216 echo 'hello' 217 enddef there 218 END 219 CheckScriptFailure(lines, 'E1173: Text found after enddef: there', 6) 220enddef 221 222def Test_missing_endfunc_enddef() 223 var lines =<< trim END 224 vim9script 225 def Test() 226 echo 'test' 227 endef 228 END 229 CheckScriptFailure(lines, 'E1057:', 2) 230 231 lines =<< trim END 232 vim9script 233 func Some() 234 echo 'test' 235 enfffunc 236 END 237 CheckScriptFailure(lines, 'E126:', 2) 238enddef 239 240def Test_white_space_before_paren() 241 var lines =<< trim END 242 vim9script 243 def Test () 244 echo 'test' 245 enddef 246 END 247 CheckScriptFailure(lines, 'E1068:', 2) 248 249 lines =<< trim END 250 vim9script 251 func Test () 252 echo 'test' 253 endfunc 254 END 255 CheckScriptFailure(lines, 'E1068:', 2) 256 257 lines =<< trim END 258 def Test () 259 echo 'test' 260 enddef 261 END 262 CheckScriptFailure(lines, 'E1068:', 1) 263 264 lines =<< trim END 265 func Test () 266 echo 'test' 267 endfunc 268 END 269 CheckScriptSuccess(lines) 270enddef 271 272def Test_enddef_dict_key() 273 var d = { 274 enddef: 'x', 275 endfunc: 'y', 276 } 277 assert_equal({enddef: 'x', endfunc: 'y'}, d) 278enddef 279 280def ReturnString(): string 281 return 'string' 282enddef 283 284def ReturnNumber(): number 285 return 123 286enddef 287 288let g:notNumber = 'string' 289 290def ReturnGlobal(): number 291 return g:notNumber 292enddef 293 294def Test_return_something() 295 ReturnString()->assert_equal('string') 296 ReturnNumber()->assert_equal(123) 297 assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal') 298enddef 299 300def Test_check_argument_type() 301 var lines =<< trim END 302 vim9script 303 def Val(a: number, b: number): number 304 return 0 305 enddef 306 def Func() 307 var x: any = true 308 Val(0, x) 309 enddef 310 disass Func 311 Func() 312 END 313 CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2) 314enddef 315 316def Test_missing_return() 317 CheckDefFailure(['def Missing(): number', 318 ' if g:cond', 319 ' echo "no return"', 320 ' else', 321 ' return 0', 322 ' endif' 323 'enddef'], 'E1027:') 324 CheckDefFailure(['def Missing(): number', 325 ' if g:cond', 326 ' return 1', 327 ' else', 328 ' echo "no return"', 329 ' endif' 330 'enddef'], 'E1027:') 331 CheckDefFailure(['def Missing(): number', 332 ' if g:cond', 333 ' return 1', 334 ' else', 335 ' return 2', 336 ' endif' 337 ' return 3' 338 'enddef'], 'E1095:') 339enddef 340 341def Test_return_bool() 342 var lines =<< trim END 343 vim9script 344 def MenuFilter(id: number, key: string): bool 345 return popup_filter_menu(id, key) 346 enddef 347 def YesnoFilter(id: number, key: string): bool 348 return popup_filter_yesno(id, key) 349 enddef 350 defcompile 351 END 352 CheckScriptSuccess(lines) 353enddef 354 355let s:nothing = 0 356def ReturnNothing() 357 s:nothing = 1 358 if true 359 return 360 endif 361 s:nothing = 2 362enddef 363 364def Test_return_nothing() 365 ReturnNothing() 366 s:nothing->assert_equal(1) 367enddef 368 369def Test_return_invalid() 370 var lines =<< trim END 371 vim9script 372 def Func(): invalid 373 return xxx 374 enddef 375 defcompile 376 END 377 CheckScriptFailure(lines, 'E1010:', 2) 378 379 lines =<< trim END 380 vim9script 381 def Test(Fun: func(number): number): list<number> 382 return map([1, 2, 3], (_, i) => Fun(i)) 383 enddef 384 defcompile 385 def Inc(nr: number): nr 386 return nr + 2 387 enddef 388 echo Test(Inc) 389 END 390 # doing this twice was leaking memory 391 CheckScriptFailure(lines, 'E1010:') 392 CheckScriptFailure(lines, 'E1010:') 393enddef 394 395func Increment() 396 let g:counter += 1 397endfunc 398 399def Test_call_ufunc_count() 400 g:counter = 1 401 Increment() 402 Increment() 403 Increment() 404 # works with and without :call 405 g:counter->assert_equal(4) 406 eval g:counter->assert_equal(4) 407 unlet g:counter 408enddef 409 410def MyVarargs(arg: string, ...rest: list<string>): string 411 var res = arg 412 for s in rest 413 res ..= ',' .. s 414 endfor 415 return res 416enddef 417 418def Test_call_varargs() 419 MyVarargs('one')->assert_equal('one') 420 MyVarargs('one', 'two')->assert_equal('one,two') 421 MyVarargs('one', 'two', 'three')->assert_equal('one,two,three') 422enddef 423 424def MyDefaultArgs(name = 'string'): string 425 return name 426enddef 427 428def MyDefaultSecond(name: string, second: bool = true): string 429 return second ? name : 'none' 430enddef 431 432 433def Test_call_default_args() 434 MyDefaultArgs()->assert_equal('string') 435 MyDefaultArgs(v:none)->assert_equal('string') 436 MyDefaultArgs('one')->assert_equal('one') 437 assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 4, 'Test_call_default_args') 438 439 MyDefaultSecond('test')->assert_equal('test') 440 MyDefaultSecond('test', true)->assert_equal('test') 441 MyDefaultSecond('test', false)->assert_equal('none') 442 443 var lines =<< trim END 444 def MyDefaultThird(name: string, aa = 'aa', bb = 'bb'): string 445 return name .. aa .. bb 446 enddef 447 448 MyDefaultThird('->')->assert_equal('->aabb') 449 MyDefaultThird('->', v:none)->assert_equal('->aabb') 450 MyDefaultThird('->', 'xx')->assert_equal('->xxbb') 451 MyDefaultThird('->', v:none, v:none)->assert_equal('->aabb') 452 MyDefaultThird('->', 'xx', v:none)->assert_equal('->xxbb') 453 MyDefaultThird('->', v:none, 'yy')->assert_equal('->aayy') 454 MyDefaultThird('->', 'xx', 'yy')->assert_equal('->xxyy') 455 456 def DefArg(mandatory: any, optional = mandatory): string 457 return mandatory .. optional 458 enddef 459 DefArg(1234)->assert_equal('12341234') 460 DefArg("ok")->assert_equal('okok') 461 END 462 CheckDefAndScriptSuccess(lines) 463 464 CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:') 465 delfunc g:Func 466 CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string') 467 delfunc g:Func 468 CheckDefFailure(['def Func(x: number = )', 'enddef'], 'E15:') 469 470 lines =<< trim END 471 vim9script 472 def Func(a = b == 0 ? 1 : 2, b = 0) 473 enddef 474 defcompile 475 END 476 CheckScriptFailure(lines, 'E1001: Variable not found: b') 477enddef 478 479def FuncWithComment( # comment 480 a: number, #comment 481 b: bool, # comment 482 c: string) #comment 483 assert_equal(4, a) 484 assert_equal(true, b) 485 assert_equal('yes', c) 486enddef 487 488def Test_func_with_comments() 489 FuncWithComment(4, true, 'yes') 490 491 var lines =<< trim END 492 def Func(# comment 493 arg: string) 494 enddef 495 END 496 CheckScriptFailure(lines, 'E125:', 1) 497 498 lines =<< trim END 499 def Func( 500 arg: string# comment 501 ) 502 enddef 503 END 504 CheckScriptFailure(lines, 'E475:', 2) 505 506 lines =<< trim END 507 def Func( 508 arg: string 509 )# comment 510 enddef 511 END 512 CheckScriptFailure(lines, 'E488:', 3) 513enddef 514 515def Test_nested_function() 516 def Nested(arg: string): string 517 return 'nested ' .. arg 518 enddef 519 Nested('function')->assert_equal('nested function') 520 521 CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') 522 CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') 523 524 CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') 525 CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:') 526 CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:') 527 528 var lines =<< trim END 529 def Outer() 530 def Inner() 531 # comment 532 enddef 533 def Inner() 534 enddef 535 enddef 536 END 537 CheckDefFailure(lines, 'E1073:') 538 539 lines =<< trim END 540 def Outer() 541 def Inner() 542 # comment 543 enddef 544 def! Inner() 545 enddef 546 enddef 547 END 548 CheckDefFailure(lines, 'E1117:') 549 550 # nested function inside conditional 551 lines =<< trim END 552 vim9script 553 var thecount = 0 554 if true 555 def Test(): number 556 def TheFunc(): number 557 thecount += 1 558 return thecount 559 enddef 560 return TheFunc() 561 enddef 562 endif 563 defcompile 564 assert_equal(1, Test()) 565 assert_equal(2, Test()) 566 END 567 CheckScriptSuccess(lines) 568 569 # also works when "thecount" is inside the "if" block 570 lines =<< trim END 571 vim9script 572 if true 573 var thecount = 0 574 def Test(): number 575 def TheFunc(): number 576 thecount += 1 577 return thecount 578 enddef 579 return TheFunc() 580 enddef 581 endif 582 defcompile 583 assert_equal(1, Test()) 584 assert_equal(2, Test()) 585 END 586 CheckScriptSuccess(lines) 587enddef 588 589def Test_not_nested_function() 590 echo printf('%d', 591 function('len')('xxx')) 592enddef 593 594func Test_call_default_args_from_func() 595 call MyDefaultArgs()->assert_equal('string') 596 call MyDefaultArgs('one')->assert_equal('one') 597 call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func') 598endfunc 599 600def Test_nested_global_function() 601 var lines =<< trim END 602 vim9script 603 def Outer() 604 def g:Inner(): string 605 return 'inner' 606 enddef 607 enddef 608 defcompile 609 Outer() 610 g:Inner()->assert_equal('inner') 611 delfunc g:Inner 612 Outer() 613 g:Inner()->assert_equal('inner') 614 delfunc g:Inner 615 Outer() 616 g:Inner()->assert_equal('inner') 617 delfunc g:Inner 618 END 619 CheckScriptSuccess(lines) 620 621 lines =<< trim END 622 vim9script 623 def Outer() 624 def g:Inner(): string 625 return 'inner' 626 enddef 627 enddef 628 defcompile 629 Outer() 630 Outer() 631 END 632 CheckScriptFailure(lines, "E122:") 633 delfunc g:Inner 634 635 lines =<< trim END 636 vim9script 637 def Outer() 638 def g:Inner() 639 echo map([1, 2, 3], (_, v) => v + 1) 640 enddef 641 g:Inner() 642 enddef 643 Outer() 644 END 645 CheckScriptSuccess(lines) 646 delfunc g:Inner 647 648 lines =<< trim END 649 vim9script 650 def Func() 651 echo 'script' 652 enddef 653 def Outer() 654 def Func() 655 echo 'inner' 656 enddef 657 enddef 658 defcompile 659 END 660 CheckScriptFailure(lines, "E1073:") 661enddef 662 663def DefListAll() 664 def 665enddef 666 667def DefListOne() 668 def DefListOne 669enddef 670 671def DefListMatches() 672 def /DefList 673enddef 674 675def Test_nested_def_list() 676 var funcs = split(execute('call DefListAll()'), "\n") 677 assert_true(len(funcs) > 10) 678 assert_true(funcs->index('def DefListAll()') >= 0) 679 680 funcs = split(execute('call DefListOne()'), "\n") 681 assert_equal([' def DefListOne()', '1 def DefListOne', ' enddef'], funcs) 682 683 funcs = split(execute('call DefListMatches()'), "\n") 684 assert_true(len(funcs) >= 3) 685 assert_true(funcs->index('def DefListAll()') >= 0) 686 assert_true(funcs->index('def DefListOne()') >= 0) 687 assert_true(funcs->index('def DefListMatches()') >= 0) 688 689 var lines =<< trim END 690 vim9script 691 def Func() 692 def +Func+ 693 enddef 694 defcompile 695 END 696 CheckScriptFailure(lines, 'E476:', 1) 697enddef 698 699def Test_global_local_function() 700 var lines =<< trim END 701 vim9script 702 def g:Func(): string 703 return 'global' 704 enddef 705 def Func(): string 706 return 'local' 707 enddef 708 g:Func()->assert_equal('global') 709 Func()->assert_equal('local') 710 delfunc g:Func 711 END 712 CheckScriptSuccess(lines) 713 714 lines =<< trim END 715 vim9script 716 def g:Funcy() 717 echo 'funcy' 718 enddef 719 s:Funcy() 720 END 721 CheckScriptFailure(lines, 'E117:') 722enddef 723 724def Test_local_function_shadows_global() 725 var lines =<< trim END 726 vim9script 727 def g:Gfunc(): string 728 return 'global' 729 enddef 730 def AnotherFunc(): number 731 var Gfunc = function('len') 732 return Gfunc('testing') 733 enddef 734 g:Gfunc()->assert_equal('global') 735 AnotherFunc()->assert_equal(7) 736 delfunc g:Gfunc 737 END 738 CheckScriptSuccess(lines) 739 740 lines =<< trim END 741 vim9script 742 def g:Func(): string 743 return 'global' 744 enddef 745 def AnotherFunc() 746 g:Func = function('len') 747 enddef 748 AnotherFunc() 749 END 750 CheckScriptFailure(lines, 'E705:') 751 delfunc g:Func 752 753 # global function is found without g: prefix 754 lines =<< trim END 755 vim9script 756 def g:Func(): string 757 return 'global' 758 enddef 759 def AnotherFunc(): string 760 return Func() 761 enddef 762 assert_equal('global', AnotherFunc()) 763 delfunc g:Func 764 END 765 CheckScriptSuccess(lines) 766 767 lines =<< trim END 768 vim9script 769 def g:Func(): string 770 return 'global' 771 enddef 772 assert_equal('global', Func()) 773 delfunc g:Func 774 END 775 CheckScriptSuccess(lines) 776enddef 777 778func TakesOneArg(arg) 779 echo a:arg 780endfunc 781 782def Test_call_wrong_args() 783 CheckDefFailure(['TakesOneArg()'], 'E119:') 784 CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') 785 CheckDefFailure(['bufnr(xxx)'], 'E1001:') 786 CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:') 787 788 var lines =<< trim END 789 vim9script 790 def Func(s: string) 791 echo s 792 enddef 793 Func([]) 794 END 795 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5) 796 797 lines =<< trim END 798 vim9script 799 var name = 'piet' 800 def FuncOne(name: string) 801 echo nr 802 enddef 803 END 804 CheckScriptFailure(lines, 'E1168:') 805 806 lines =<< trim END 807 vim9script 808 def FuncOne(nr: number) 809 echo nr 810 enddef 811 def FuncTwo() 812 FuncOne() 813 enddef 814 defcompile 815 END 816 writefile(lines, 'Xscript') 817 var didCatch = false 818 try 819 source Xscript 820 catch 821 assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception) 822 assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint) 823 didCatch = true 824 endtry 825 assert_true(didCatch) 826 827 lines =<< trim END 828 vim9script 829 def FuncOne(nr: number) 830 echo nr 831 enddef 832 def FuncTwo() 833 FuncOne(1, 2) 834 enddef 835 defcompile 836 END 837 writefile(lines, 'Xscript') 838 didCatch = false 839 try 840 source Xscript 841 catch 842 assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception) 843 assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint) 844 didCatch = true 845 endtry 846 assert_true(didCatch) 847 848 delete('Xscript') 849enddef 850 851def Test_call_funcref_wrong_args() 852 var head =<< trim END 853 vim9script 854 def Func3(a1: string, a2: number, a3: list<number>) 855 echo a1 .. a2 .. a3[0] 856 enddef 857 def Testme() 858 var funcMap: dict<func> = {func: Func3} 859 END 860 var tail =<< trim END 861 enddef 862 Testme() 863 END 864 CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail) 865 866 CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:') 867 CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:') 868 869 var lines =<< trim END 870 vim9script 871 var Ref: func(number): any 872 Ref = (j) => !j 873 echo Ref(false) 874 END 875 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4) 876 877 lines =<< trim END 878 vim9script 879 var Ref: func(number): any 880 Ref = (j) => !j 881 call Ref(false) 882 END 883 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4) 884enddef 885 886def Test_call_lambda_args() 887 var lines =<< trim END 888 var Callback = (..._) => 'anything' 889 assert_equal('anything', Callback()) 890 assert_equal('anything', Callback(1)) 891 assert_equal('anything', Callback('a', 2)) 892 893 assert_equal('xyz', ((a: string): string => a)('xyz')) 894 END 895 CheckDefAndScriptSuccess(lines) 896 897 CheckDefFailure(['echo ((i) => 0)()'], 898 'E119: Not enough arguments for function: ((i) => 0)()') 899 900 lines =<< trim END 901 var Ref = (x: number, y: number) => x + y 902 echo Ref(1, 'x') 903 END 904 CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string') 905 906 lines =<< trim END 907 var Ref: func(job, string, number) 908 Ref = (x, y) => 0 909 END 910 CheckDefAndScriptFailure(lines, 'E1012:') 911 912 lines =<< trim END 913 var Ref: func(job, string) 914 Ref = (x, y, z) => 0 915 END 916 CheckDefAndScriptFailure(lines, 'E1012:') 917 918 lines =<< trim END 919 var one = 1 920 var l = [1, 2, 3] 921 echo map(l, (one) => one) 922 END 923 CheckDefFailure(lines, 'E1167:') 924 CheckScriptFailure(['vim9script'] + lines, 'E1168:') 925 926 lines =<< trim END 927 var Ref: func(any, ?any): bool 928 Ref = (_, y = 1) => false 929 END 930 CheckDefAndScriptFailure(lines, 'E1172:') 931 932 lines =<< trim END 933 var a = 0 934 var b = (a == 0 ? 1 : 2) 935 assert_equal(1, b) 936 var txt = 'a' 937 b = (txt =~ 'x' ? 1 : 2) 938 assert_equal(2, b) 939 END 940 CheckDefAndScriptSuccess(lines) 941 942 lines =<< trim END 943 def ShadowLocal() 944 var one = 1 945 var l = [1, 2, 3] 946 echo map(l, (one) => one) 947 enddef 948 END 949 CheckDefFailure(lines, 'E1167:') 950 951 lines =<< trim END 952 def Shadowarg(one: number) 953 var l = [1, 2, 3] 954 echo map(l, (one) => one) 955 enddef 956 END 957 CheckDefFailure(lines, 'E1167:') 958 959 lines =<< trim END 960 echo ((a) => a)('aa', 'bb') 961 END 962 CheckDefAndScriptFailure(lines, 'E118:', 1) 963 964 lines =<< trim END 965 echo 'aa'->((a) => a)('bb') 966 END 967 CheckDefFailure(lines, 'E118: Too many arguments for function: ->((a) => a)(''bb'')', 1) 968 CheckScriptFailure(['vim9script'] + lines, 'E118: Too many arguments for function: <lambda>', 2) 969enddef 970 971def FilterWithCond(x: string, Cond: func(string): bool): bool 972 return Cond(x) 973enddef 974 975def Test_lambda_return_type() 976 var lines =<< trim END 977 var Ref = (): => 123 978 END 979 CheckDefAndScriptFailure(lines, 'E1157:', 1) 980 981 # no space before the return type 982 lines =<< trim END 983 var Ref = (x):number => x + 1 984 END 985 CheckDefAndScriptFailure(lines, 'E1069:', 1) 986 987 # this works 988 for x in ['foo', 'boo'] 989 echo FilterWithCond(x, (v) => v =~ '^b') 990 endfor 991 992 # this fails 993 lines =<< trim END 994 echo FilterWithCond('foo', (v) => v .. '^b') 995 END 996 CheckDefAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected func(string): bool but got func(any): string', 1) 997 998 lines =<< trim END 999 var Lambda1 = (x) => { 1000 return x 1001 } 1002 assert_equal('asdf', Lambda1('asdf')) 1003 var Lambda2 = (x): string => { 1004 return x 1005 } 1006 assert_equal('foo', Lambda2('foo')) 1007 END 1008 CheckDefAndScriptSuccess(lines) 1009 1010 lines =<< trim END 1011 var Lambda = (x): string => { 1012 return x 1013 } 1014 echo Lambda(['foo']) 1015 END 1016 CheckDefExecAndScriptFailure(lines, 'E1012:') 1017enddef 1018 1019def Test_lambda_uses_assigned_var() 1020 CheckDefSuccess([ 1021 'var x: any = "aaa"' 1022 'x = filter(["bbb"], (_, v) => v =~ x)']) 1023enddef 1024 1025def Test_pass_legacy_lambda_to_def_func() 1026 var lines =<< trim END 1027 vim9script 1028 func Foo() 1029 eval s:Bar({x -> 0}) 1030 endfunc 1031 def Bar(y: any) 1032 enddef 1033 Foo() 1034 END 1035 CheckScriptSuccess(lines) 1036 1037 lines =<< trim END 1038 vim9script 1039 def g:TestFunc(f: func) 1040 enddef 1041 legacy call g:TestFunc({-> 0}) 1042 delfunc g:TestFunc 1043 1044 def g:TestFunc(f: func(number)) 1045 enddef 1046 legacy call g:TestFunc({nr -> 0}) 1047 delfunc g:TestFunc 1048 END 1049 CheckScriptSuccess(lines) 1050enddef 1051 1052" Default arg and varargs 1053def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string 1054 var res = one .. ',' .. two 1055 for s in rest 1056 res ..= ',' .. s 1057 endfor 1058 return res 1059enddef 1060 1061def Test_call_def_varargs() 1062 assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs') 1063 MyDefVarargs('one')->assert_equal('one,foo') 1064 MyDefVarargs('one', 'two')->assert_equal('one,two') 1065 MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three') 1066 CheckDefFailure(['MyDefVarargs("one", 22)'], 1067 'E1013: Argument 2: type mismatch, expected string but got number') 1068 CheckDefFailure(['MyDefVarargs("one", "two", 123)'], 1069 'E1013: Argument 3: type mismatch, expected string but got number') 1070 1071 var lines =<< trim END 1072 vim9script 1073 def Func(...l: list<string>) 1074 echo l 1075 enddef 1076 Func('a', 'b', 'c') 1077 END 1078 CheckScriptSuccess(lines) 1079 1080 lines =<< trim END 1081 vim9script 1082 def Func(...l: list<string>) 1083 echo l 1084 enddef 1085 Func() 1086 END 1087 CheckScriptSuccess(lines) 1088 1089 lines =<< trim END 1090 vim9script 1091 def Func(...l: list<any>) 1092 echo l 1093 enddef 1094 Func(0) 1095 END 1096 CheckScriptSuccess(lines) 1097 1098 lines =<< trim END 1099 vim9script 1100 def Func(...l: any) 1101 echo l 1102 enddef 1103 Func(0) 1104 END 1105 CheckScriptFailure(lines, 'E1180:', 2) 1106 1107 lines =<< trim END 1108 vim9script 1109 def Func(..._l: list<string>) 1110 echo _l 1111 enddef 1112 Func('a', 'b', 'c') 1113 END 1114 CheckScriptSuccess(lines) 1115 1116 lines =<< trim END 1117 vim9script 1118 def Func(...l: list<string>) 1119 echo l 1120 enddef 1121 Func(1, 2, 3) 1122 END 1123 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch') 1124 1125 lines =<< trim END 1126 vim9script 1127 def Func(...l: list<string>) 1128 echo l 1129 enddef 1130 Func('a', 9) 1131 END 1132 CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch') 1133 1134 lines =<< trim END 1135 vim9script 1136 def Func(...l: list<string>) 1137 echo l 1138 enddef 1139 Func(1, 'a') 1140 END 1141 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch') 1142 1143 lines =<< trim END 1144 vim9script 1145 def Func( # some comment 1146 ...l = [] 1147 ) 1148 echo l 1149 enddef 1150 END 1151 CheckScriptFailure(lines, 'E1160:') 1152 1153 lines =<< trim END 1154 vim9script 1155 def DoIt() 1156 g:Later('') 1157 enddef 1158 defcompile 1159 def g:Later(...l: list<number>) 1160 enddef 1161 DoIt() 1162 END 1163 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got string') 1164enddef 1165 1166let s:value = '' 1167 1168def FuncOneDefArg(opt = 'text') 1169 s:value = opt 1170enddef 1171 1172def FuncTwoDefArg(nr = 123, opt = 'text'): string 1173 return nr .. opt 1174enddef 1175 1176def FuncVarargs(...arg: list<string>): string 1177 return join(arg, ',') 1178enddef 1179 1180def Test_func_type_varargs() 1181 var RefDefArg: func(?string) 1182 RefDefArg = FuncOneDefArg 1183 RefDefArg() 1184 s:value->assert_equal('text') 1185 RefDefArg('some') 1186 s:value->assert_equal('some') 1187 1188 var RefDef2Arg: func(?number, ?string): string 1189 RefDef2Arg = FuncTwoDefArg 1190 RefDef2Arg()->assert_equal('123text') 1191 RefDef2Arg(99)->assert_equal('99text') 1192 RefDef2Arg(77, 'some')->assert_equal('77some') 1193 1194 CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:') 1195 CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:') 1196 1197 var RefVarargs: func(...list<string>): string 1198 RefVarargs = FuncVarargs 1199 RefVarargs()->assert_equal('') 1200 RefVarargs('one')->assert_equal('one') 1201 RefVarargs('one', 'two')->assert_equal('one,two') 1202 1203 CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:') 1204 CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:') 1205enddef 1206 1207" Only varargs 1208def MyVarargsOnly(...args: list<string>): string 1209 return join(args, ',') 1210enddef 1211 1212def Test_call_varargs_only() 1213 MyVarargsOnly()->assert_equal('') 1214 MyVarargsOnly('one')->assert_equal('one') 1215 MyVarargsOnly('one', 'two')->assert_equal('one,two') 1216 CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number') 1217 CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number') 1218enddef 1219 1220def Test_using_var_as_arg() 1221 writefile(['def Func(x: number)', 'var x = 234', 'enddef', 'defcompile'], 'Xdef') 1222 assert_fails('so Xdef', 'E1006:', '', 1, 'Func') 1223 delete('Xdef') 1224enddef 1225 1226def DictArg(arg: dict<string>) 1227 arg['key'] = 'value' 1228enddef 1229 1230def ListArg(arg: list<string>) 1231 arg[0] = 'value' 1232enddef 1233 1234def Test_assign_to_argument() 1235 # works for dict and list 1236 var d: dict<string> = {} 1237 DictArg(d) 1238 d['key']->assert_equal('value') 1239 var l: list<string> = [] 1240 ListArg(l) 1241 l[0]->assert_equal('value') 1242 1243 CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:') 1244 delfunc! g:Func 1245enddef 1246 1247" These argument names are reserved in legacy functions. 1248def WithReservedNames(firstline: string, lastline: string): string 1249 return firstline .. lastline 1250enddef 1251 1252def Test_argument_names() 1253 assert_equal('OK', WithReservedNames('O', 'K')) 1254enddef 1255 1256def Test_call_func_defined_later() 1257 g:DefinedLater('one')->assert_equal('one') 1258 assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later') 1259enddef 1260 1261func DefinedLater(arg) 1262 return a:arg 1263endfunc 1264 1265def Test_call_funcref() 1266 g:SomeFunc('abc')->assert_equal(3) 1267 assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call 1268 assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref') 1269 1270 var lines =<< trim END 1271 vim9script 1272 def RetNumber(): number 1273 return 123 1274 enddef 1275 var Funcref: func: number = function('RetNumber') 1276 Funcref()->assert_equal(123) 1277 END 1278 CheckScriptSuccess(lines) 1279 1280 lines =<< trim END 1281 vim9script 1282 def RetNumber(): number 1283 return 123 1284 enddef 1285 def Bar(F: func: number): number 1286 return F() 1287 enddef 1288 var Funcref = function('RetNumber') 1289 Bar(Funcref)->assert_equal(123) 1290 END 1291 CheckScriptSuccess(lines) 1292 1293 lines =<< trim END 1294 vim9script 1295 def UseNumber(nr: number) 1296 echo nr 1297 enddef 1298 var Funcref: func(number) = function('UseNumber') 1299 Funcref(123) 1300 END 1301 CheckScriptSuccess(lines) 1302 1303 lines =<< trim END 1304 vim9script 1305 def UseNumber(nr: number) 1306 echo nr 1307 enddef 1308 var Funcref: func(string) = function('UseNumber') 1309 END 1310 CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)') 1311 1312 lines =<< trim END 1313 vim9script 1314 def EchoNr(nr = 34) 1315 g:echo = nr 1316 enddef 1317 var Funcref: func(?number) = function('EchoNr') 1318 Funcref() 1319 g:echo->assert_equal(34) 1320 Funcref(123) 1321 g:echo->assert_equal(123) 1322 END 1323 CheckScriptSuccess(lines) 1324 1325 lines =<< trim END 1326 vim9script 1327 def EchoList(...l: list<number>) 1328 g:echo = l 1329 enddef 1330 var Funcref: func(...list<number>) = function('EchoList') 1331 Funcref() 1332 g:echo->assert_equal([]) 1333 Funcref(1, 2, 3) 1334 g:echo->assert_equal([1, 2, 3]) 1335 END 1336 CheckScriptSuccess(lines) 1337 1338 lines =<< trim END 1339 vim9script 1340 def OptAndVar(nr: number, opt = 12, ...l: list<number>): number 1341 g:optarg = opt 1342 g:listarg = l 1343 return nr 1344 enddef 1345 var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar') 1346 Funcref(10)->assert_equal(10) 1347 g:optarg->assert_equal(12) 1348 g:listarg->assert_equal([]) 1349 1350 Funcref(11, 22)->assert_equal(11) 1351 g:optarg->assert_equal(22) 1352 g:listarg->assert_equal([]) 1353 1354 Funcref(17, 18, 1, 2, 3)->assert_equal(17) 1355 g:optarg->assert_equal(18) 1356 g:listarg->assert_equal([1, 2, 3]) 1357 END 1358 CheckScriptSuccess(lines) 1359enddef 1360 1361let SomeFunc = function('len') 1362let NotAFunc = 'text' 1363 1364def CombineFuncrefTypes() 1365 # same arguments, different return type 1366 var Ref1: func(bool): string 1367 var Ref2: func(bool): number 1368 var Ref3: func(bool): any 1369 Ref3 = g:cond ? Ref1 : Ref2 1370 1371 # different number of arguments 1372 var Refa1: func(bool): number 1373 var Refa2: func(bool, number): number 1374 var Refa3: func: number 1375 Refa3 = g:cond ? Refa1 : Refa2 1376 1377 # different argument types 1378 var Refb1: func(bool, string): number 1379 var Refb2: func(string, number): number 1380 var Refb3: func(any, any): number 1381 Refb3 = g:cond ? Refb1 : Refb2 1382enddef 1383 1384def FuncWithForwardCall() 1385 return g:DefinedEvenLater("yes") 1386enddef 1387 1388def DefinedEvenLater(arg: string): string 1389 return arg 1390enddef 1391 1392def Test_error_in_nested_function() 1393 # Error in called function requires unwinding the call stack. 1394 assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall') 1395enddef 1396 1397def Test_return_type_wrong() 1398 CheckScriptFailure([ 1399 'def Func(): number', 1400 'return "a"', 1401 'enddef', 1402 'defcompile'], 'expected number but got string') 1403 delfunc! g:Func 1404 CheckScriptFailure([ 1405 'def Func(): string', 1406 'return 1', 1407 'enddef', 1408 'defcompile'], 'expected string but got number') 1409 delfunc! g:Func 1410 CheckScriptFailure([ 1411 'def Func(): void', 1412 'return "a"', 1413 'enddef', 1414 'defcompile'], 1415 'E1096: Returning a value in a function without a return type') 1416 delfunc! g:Func 1417 CheckScriptFailure([ 1418 'def Func()', 1419 'return "a"', 1420 'enddef', 1421 'defcompile'], 1422 'E1096: Returning a value in a function without a return type') 1423 delfunc! g:Func 1424 1425 CheckScriptFailure([ 1426 'def Func(): number', 1427 'return', 1428 'enddef', 1429 'defcompile'], 'E1003:') 1430 delfunc! g:Func 1431 1432 CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') 1433 delfunc! g:Func 1434 CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') 1435 delfunc! g:Func 1436 CheckScriptFailure(['def Func()', 'return 1'], 'E1057:') 1437 delfunc! g:Func 1438 1439 CheckScriptFailure([ 1440 'vim9script', 1441 'def FuncB()', 1442 ' return 123', 1443 'enddef', 1444 'def FuncA()', 1445 ' FuncB()', 1446 'enddef', 1447 'defcompile'], 'E1096:') 1448enddef 1449 1450def Test_arg_type_wrong() 1451 CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') 1452 CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...') 1453 CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:') 1454 CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:') 1455 CheckScriptFailure(['def Func6(...x:list<number>)', 'echo "a"', 'enddef'], 'E1069:') 1456 CheckScriptFailure(['def Func7(...x: int)', 'echo "a"', 'enddef'], 'E1010:') 1457enddef 1458 1459def Test_white_space_before_comma() 1460 var lines =<< trim END 1461 vim9script 1462 def Func(a: number , b: number) 1463 enddef 1464 END 1465 CheckScriptFailure(lines, 'E1068:') 1466 call assert_fails('vim9cmd echo stridx("a" .. "b" , "a")', 'E1068:') 1467enddef 1468 1469def Test_white_space_after_comma() 1470 var lines =<< trim END 1471 vim9script 1472 def Func(a: number,b: number) 1473 enddef 1474 END 1475 CheckScriptFailure(lines, 'E1069:') 1476 1477 # OK in legacy function 1478 lines =<< trim END 1479 vim9script 1480 func Func(a,b) 1481 endfunc 1482 END 1483 CheckScriptSuccess(lines) 1484enddef 1485 1486def Test_vim9script_call() 1487 var lines =<< trim END 1488 vim9script 1489 var name = '' 1490 def MyFunc(arg: string) 1491 name = arg 1492 enddef 1493 MyFunc('foobar') 1494 name->assert_equal('foobar') 1495 1496 var str = 'barfoo' 1497 str->MyFunc() 1498 name->assert_equal('barfoo') 1499 1500 g:value = 'value' 1501 g:value->MyFunc() 1502 name->assert_equal('value') 1503 1504 var listvar = [] 1505 def ListFunc(arg: list<number>) 1506 listvar = arg 1507 enddef 1508 [1, 2, 3]->ListFunc() 1509 listvar->assert_equal([1, 2, 3]) 1510 1511 var dictvar = {} 1512 def DictFunc(arg: dict<number>) 1513 dictvar = arg 1514 enddef 1515 {a: 1, b: 2}->DictFunc() 1516 dictvar->assert_equal({a: 1, b: 2}) 1517 def CompiledDict() 1518 {a: 3, b: 4}->DictFunc() 1519 enddef 1520 CompiledDict() 1521 dictvar->assert_equal({a: 3, b: 4}) 1522 1523 {a: 3, b: 4}->DictFunc() 1524 dictvar->assert_equal({a: 3, b: 4}) 1525 1526 ('text')->MyFunc() 1527 name->assert_equal('text') 1528 ("some")->MyFunc() 1529 name->assert_equal('some') 1530 1531 # line starting with single quote is not a mark 1532 # line starting with double quote can be a method call 1533 'asdfasdf'->MyFunc() 1534 name->assert_equal('asdfasdf') 1535 "xyz"->MyFunc() 1536 name->assert_equal('xyz') 1537 1538 def UseString() 1539 'xyork'->MyFunc() 1540 enddef 1541 UseString() 1542 name->assert_equal('xyork') 1543 1544 def UseString2() 1545 "knife"->MyFunc() 1546 enddef 1547 UseString2() 1548 name->assert_equal('knife') 1549 1550 # prepending a colon makes it a mark 1551 new 1552 setline(1, ['aaa', 'bbb', 'ccc']) 1553 normal! 3Gmt1G 1554 :'t 1555 getcurpos()[1]->assert_equal(3) 1556 bwipe! 1557 1558 MyFunc( 1559 'continued' 1560 ) 1561 assert_equal('continued', 1562 name 1563 ) 1564 1565 call MyFunc( 1566 'more' 1567 .. 1568 'lines' 1569 ) 1570 assert_equal( 1571 'morelines', 1572 name) 1573 END 1574 writefile(lines, 'Xcall.vim') 1575 source Xcall.vim 1576 delete('Xcall.vim') 1577enddef 1578 1579def Test_vim9script_call_fail_decl() 1580 var lines =<< trim END 1581 vim9script 1582 var name = '' 1583 def MyFunc(arg: string) 1584 var name = 123 1585 enddef 1586 defcompile 1587 END 1588 CheckScriptFailure(lines, 'E1054:') 1589enddef 1590 1591def Test_vim9script_call_fail_type() 1592 var lines =<< trim END 1593 vim9script 1594 def MyFunc(arg: string) 1595 echo arg 1596 enddef 1597 MyFunc(1234) 1598 END 1599 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') 1600enddef 1601 1602def Test_vim9script_call_fail_const() 1603 var lines =<< trim END 1604 vim9script 1605 const var = '' 1606 def MyFunc(arg: string) 1607 var = 'asdf' 1608 enddef 1609 defcompile 1610 END 1611 writefile(lines, 'Xcall_const.vim') 1612 assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') 1613 delete('Xcall_const.vim') 1614 1615 lines =<< trim END 1616 const g:Aconst = 77 1617 def Change() 1618 # comment 1619 g:Aconst = 99 1620 enddef 1621 call Change() 1622 unlet g:Aconst 1623 END 1624 CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) 1625enddef 1626 1627" Test that inside :function a Python function can be defined, :def is not 1628" recognized. 1629func Test_function_python() 1630 CheckFeature python3 1631 let py = 'python3' 1632 execute py "<< EOF" 1633def do_something(): 1634 return 1 1635EOF 1636endfunc 1637 1638def Test_delfunc() 1639 var lines =<< trim END 1640 vim9script 1641 def g:GoneSoon() 1642 echo 'hello' 1643 enddef 1644 1645 def CallGoneSoon() 1646 GoneSoon() 1647 enddef 1648 defcompile 1649 1650 delfunc g:GoneSoon 1651 CallGoneSoon() 1652 END 1653 writefile(lines, 'XToDelFunc') 1654 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1655 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1656 1657 delete('XToDelFunc') 1658enddef 1659 1660def Test_redef_failure() 1661 writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') 1662 so Xdef 1663 writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') 1664 so Xdef 1665 writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef') 1666 assert_fails('so Xdef', 'E1027:', '', 1, 'Func0') 1667 writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') 1668 so Xdef 1669 delete('Xdef') 1670 1671 assert_fails('g:Func0()', 'E1091:') 1672 g:Func1()->assert_equal('Func1') 1673 g:Func2()->assert_equal('Func2') 1674 1675 delfunc! Func0 1676 delfunc! Func1 1677 delfunc! Func2 1678enddef 1679 1680def Test_vim9script_func() 1681 var lines =<< trim END 1682 vim9script 1683 func Func(arg) 1684 echo a:arg 1685 endfunc 1686 Func('text') 1687 END 1688 writefile(lines, 'XVim9Func') 1689 so XVim9Func 1690 1691 delete('XVim9Func') 1692enddef 1693 1694let s:funcResult = 0 1695 1696def FuncNoArgNoRet() 1697 s:funcResult = 11 1698enddef 1699 1700def FuncNoArgRetNumber(): number 1701 s:funcResult = 22 1702 return 1234 1703enddef 1704 1705def FuncNoArgRetString(): string 1706 s:funcResult = 45 1707 return 'text' 1708enddef 1709 1710def FuncOneArgNoRet(arg: number) 1711 s:funcResult = arg 1712enddef 1713 1714def FuncOneArgRetNumber(arg: number): number 1715 s:funcResult = arg 1716 return arg 1717enddef 1718 1719def FuncTwoArgNoRet(one: bool, two: number) 1720 s:funcResult = two 1721enddef 1722 1723def FuncOneArgRetString(arg: string): string 1724 return arg 1725enddef 1726 1727def FuncOneArgRetAny(arg: any): any 1728 return arg 1729enddef 1730 1731def Test_func_type() 1732 var Ref1: func() 1733 s:funcResult = 0 1734 Ref1 = FuncNoArgNoRet 1735 Ref1() 1736 s:funcResult->assert_equal(11) 1737 1738 var Ref2: func 1739 s:funcResult = 0 1740 Ref2 = FuncNoArgNoRet 1741 Ref2() 1742 s:funcResult->assert_equal(11) 1743 1744 s:funcResult = 0 1745 Ref2 = FuncOneArgNoRet 1746 Ref2(12) 1747 s:funcResult->assert_equal(12) 1748 1749 s:funcResult = 0 1750 Ref2 = FuncNoArgRetNumber 1751 Ref2()->assert_equal(1234) 1752 s:funcResult->assert_equal(22) 1753 1754 s:funcResult = 0 1755 Ref2 = FuncOneArgRetNumber 1756 Ref2(13)->assert_equal(13) 1757 s:funcResult->assert_equal(13) 1758enddef 1759 1760def Test_repeat_return_type() 1761 var res = 0 1762 for n in repeat([1], 3) 1763 res += n 1764 endfor 1765 res->assert_equal(3) 1766 1767 res = 0 1768 for n in add([1, 2], 3) 1769 res += n 1770 endfor 1771 res->assert_equal(6) 1772enddef 1773 1774def Test_argv_return_type() 1775 next fileone filetwo 1776 var res = '' 1777 for name in argv() 1778 res ..= name 1779 endfor 1780 res->assert_equal('fileonefiletwo') 1781enddef 1782 1783def Test_func_type_part() 1784 var RefVoid: func: void 1785 RefVoid = FuncNoArgNoRet 1786 RefVoid = FuncOneArgNoRet 1787 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number') 1788 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string') 1789 1790 var RefAny: func(): any 1791 RefAny = FuncNoArgRetNumber 1792 RefAny = FuncNoArgRetString 1793 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()') 1794 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)') 1795 1796 var RefAnyNoArgs: func: any = RefAny 1797 1798 var RefNr: func: number 1799 RefNr = FuncNoArgRetNumber 1800 RefNr = FuncOneArgRetNumber 1801 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()') 1802 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string') 1803 1804 var RefStr: func: string 1805 RefStr = FuncNoArgRetString 1806 RefStr = FuncOneArgRetString 1807 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()') 1808 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number') 1809enddef 1810 1811def Test_func_type_fails() 1812 CheckDefFailure(['var ref1: func()'], 'E704:') 1813 1814 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number') 1815 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)') 1816 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number') 1817 CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)') 1818 CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)') 1819 CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)') 1820 1821 CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:') 1822 CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:') 1823 CheckDefFailure(['var RefWrong: func(bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool)'], 'E1005:') 1824 CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:') 1825enddef 1826 1827def Test_func_return_type() 1828 var nr: number 1829 nr = FuncNoArgRetNumber() 1830 nr->assert_equal(1234) 1831 1832 nr = FuncOneArgRetAny(122) 1833 nr->assert_equal(122) 1834 1835 var str: string 1836 str = FuncOneArgRetAny('yes') 1837 str->assert_equal('yes') 1838 1839 CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number') 1840enddef 1841 1842def Test_func_common_type() 1843 def FuncOne(n: number): number 1844 return n 1845 enddef 1846 def FuncTwo(s: string): number 1847 return len(s) 1848 enddef 1849 def FuncThree(n: number, s: string): number 1850 return n + len(s) 1851 enddef 1852 var list = [FuncOne, FuncTwo, FuncThree] 1853 assert_equal(8, list[0](8)) 1854 assert_equal(4, list[1]('word')) 1855 assert_equal(7, list[2](3, 'word')) 1856enddef 1857 1858def MultiLine( 1859 arg1: string, 1860 arg2 = 1234, 1861 ...rest: list<string> 1862 ): string 1863 return arg1 .. arg2 .. join(rest, '-') 1864enddef 1865 1866def MultiLineComment( 1867 arg1: string, # comment 1868 arg2 = 1234, # comment 1869 ...rest: list<string> # comment 1870 ): string # comment 1871 return arg1 .. arg2 .. join(rest, '-') 1872enddef 1873 1874def Test_multiline() 1875 MultiLine('text')->assert_equal('text1234') 1876 MultiLine('text', 777)->assert_equal('text777') 1877 MultiLine('text', 777, 'one')->assert_equal('text777one') 1878 MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1879enddef 1880 1881func Test_multiline_not_vim9() 1882 call MultiLine('text')->assert_equal('text1234') 1883 call MultiLine('text', 777)->assert_equal('text777') 1884 call MultiLine('text', 777, 'one')->assert_equal('text777one') 1885 call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1886endfunc 1887 1888 1889" When using CheckScriptFailure() for the below test, E1010 is generated instead 1890" of E1056. 1891func Test_E1056_1059() 1892 let caught_1056 = 0 1893 try 1894 def F(): 1895 return 1 1896 enddef 1897 catch /E1056:/ 1898 let caught_1056 = 1 1899 endtry 1900 eval caught_1056->assert_equal(1) 1901 1902 let caught_1059 = 0 1903 try 1904 def F5(items : list) 1905 echo 'a' 1906 enddef 1907 catch /E1059:/ 1908 let caught_1059 = 1 1909 endtry 1910 eval caught_1059->assert_equal(1) 1911endfunc 1912 1913func DelMe() 1914 echo 'DelMe' 1915endfunc 1916 1917def Test_error_reporting() 1918 # comment lines at the start of the function 1919 var lines =<< trim END 1920 " comment 1921 def Func() 1922 # comment 1923 # comment 1924 invalid 1925 enddef 1926 defcompile 1927 END 1928 writefile(lines, 'Xdef') 1929 try 1930 source Xdef 1931 assert_report('should have failed') 1932 catch /E476:/ 1933 v:exception->assert_match('Invalid command: invalid') 1934 v:throwpoint->assert_match(', line 3$') 1935 endtry 1936 delfunc! g:Func 1937 1938 # comment lines after the start of the function 1939 lines =<< trim END 1940 " comment 1941 def Func() 1942 var x = 1234 1943 # comment 1944 # comment 1945 invalid 1946 enddef 1947 defcompile 1948 END 1949 writefile(lines, 'Xdef') 1950 try 1951 source Xdef 1952 assert_report('should have failed') 1953 catch /E476:/ 1954 v:exception->assert_match('Invalid command: invalid') 1955 v:throwpoint->assert_match(', line 4$') 1956 endtry 1957 delfunc! g:Func 1958 1959 lines =<< trim END 1960 vim9script 1961 def Func() 1962 var db = {foo: 1, bar: 2} 1963 # comment 1964 var x = db.asdf 1965 enddef 1966 defcompile 1967 Func() 1968 END 1969 writefile(lines, 'Xdef') 1970 try 1971 source Xdef 1972 assert_report('should have failed') 1973 catch /E716:/ 1974 v:throwpoint->assert_match('_Func, line 3$') 1975 endtry 1976 delfunc! g:Func 1977 1978 delete('Xdef') 1979enddef 1980 1981def Test_deleted_function() 1982 CheckDefExecFailure([ 1983 'var RefMe: func = function("g:DelMe")', 1984 'delfunc g:DelMe', 1985 'echo RefMe()'], 'E117:') 1986enddef 1987 1988def Test_unknown_function() 1989 CheckDefExecFailure([ 1990 'var Ref: func = function("NotExist")', 1991 'delfunc g:NotExist'], 'E700:') 1992enddef 1993 1994def RefFunc(Ref: func(any): any): string 1995 return Ref('more') 1996enddef 1997 1998def Test_closure_simple() 1999 var local = 'some ' 2000 RefFunc((s) => local .. s)->assert_equal('some more') 2001enddef 2002 2003def MakeRef() 2004 var local = 'some ' 2005 g:Ref = (s) => local .. s 2006enddef 2007 2008def Test_closure_ref_after_return() 2009 MakeRef() 2010 g:Ref('thing')->assert_equal('some thing') 2011 unlet g:Ref 2012enddef 2013 2014def MakeTwoRefs() 2015 var local = ['some'] 2016 g:Extend = (s) => local->add(s) 2017 g:Read = () => local 2018enddef 2019 2020def Test_closure_two_refs() 2021 MakeTwoRefs() 2022 join(g:Read(), ' ')->assert_equal('some') 2023 g:Extend('more') 2024 join(g:Read(), ' ')->assert_equal('some more') 2025 g:Extend('even') 2026 join(g:Read(), ' ')->assert_equal('some more even') 2027 2028 unlet g:Extend 2029 unlet g:Read 2030enddef 2031 2032def ReadRef(Ref: func(): list<string>): string 2033 return join(Ref(), ' ') 2034enddef 2035 2036def ExtendRef(Ref: func(string): list<string>, add: string) 2037 Ref(add) 2038enddef 2039 2040def Test_closure_two_indirect_refs() 2041 MakeTwoRefs() 2042 ReadRef(g:Read)->assert_equal('some') 2043 ExtendRef(g:Extend, 'more') 2044 ReadRef(g:Read)->assert_equal('some more') 2045 ExtendRef(g:Extend, 'even') 2046 ReadRef(g:Read)->assert_equal('some more even') 2047 2048 unlet g:Extend 2049 unlet g:Read 2050enddef 2051 2052def MakeArgRefs(theArg: string) 2053 var local = 'loc_val' 2054 g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s 2055enddef 2056 2057def MakeArgRefsVarargs(theArg: string, ...rest: list<string>) 2058 var local = 'the_loc' 2059 g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest) 2060enddef 2061 2062def Test_closure_using_argument() 2063 MakeArgRefs('arg_val') 2064 g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val') 2065 2066 MakeArgRefsVarargs('arg_val', 'one', 'two') 2067 g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two') 2068 2069 unlet g:UseArg 2070 unlet g:UseVararg 2071 2072 var lines =<< trim END 2073 vim9script 2074 def Test(Fun: func(number): number): list<number> 2075 return map([1, 2, 3], (_, i) => Fun(i)) 2076 enddef 2077 def Inc(nr: number): number 2078 return nr + 2 2079 enddef 2080 assert_equal([3, 4, 5], Test(Inc)) 2081 END 2082 CheckScriptSuccess(lines) 2083enddef 2084 2085def MakeGetAndAppendRefs() 2086 var local = 'a' 2087 2088 def Append(arg: string) 2089 local ..= arg 2090 enddef 2091 g:Append = Append 2092 2093 def Get(): string 2094 return local 2095 enddef 2096 g:Get = Get 2097enddef 2098 2099def Test_closure_append_get() 2100 MakeGetAndAppendRefs() 2101 g:Get()->assert_equal('a') 2102 g:Append('-b') 2103 g:Get()->assert_equal('a-b') 2104 g:Append('-c') 2105 g:Get()->assert_equal('a-b-c') 2106 2107 unlet g:Append 2108 unlet g:Get 2109enddef 2110 2111def Test_nested_closure() 2112 var local = 'text' 2113 def Closure(arg: string): string 2114 return local .. arg 2115 enddef 2116 Closure('!!!')->assert_equal('text!!!') 2117enddef 2118 2119func GetResult(Ref) 2120 return a:Ref('some') 2121endfunc 2122 2123def Test_call_closure_not_compiled() 2124 var text = 'text' 2125 g:Ref = (s) => s .. text 2126 GetResult(g:Ref)->assert_equal('sometext') 2127enddef 2128 2129def Test_double_closure_fails() 2130 var lines =<< trim END 2131 vim9script 2132 def Func() 2133 var name = 0 2134 for i in range(2) 2135 timer_start(0, () => name) 2136 endfor 2137 enddef 2138 Func() 2139 END 2140 CheckScriptSuccess(lines) 2141enddef 2142 2143def Test_nested_closure_used() 2144 var lines =<< trim END 2145 vim9script 2146 def Func() 2147 var x = 'hello' 2148 var Closure = () => x 2149 g:Myclosure = () => Closure() 2150 enddef 2151 Func() 2152 assert_equal('hello', g:Myclosure()) 2153 END 2154 CheckScriptSuccess(lines) 2155enddef 2156 2157def Test_nested_closure_fails() 2158 var lines =<< trim END 2159 vim9script 2160 def FuncA() 2161 FuncB(0) 2162 enddef 2163 def FuncB(n: number): list<string> 2164 return map([0], (_, v) => n) 2165 enddef 2166 FuncA() 2167 END 2168 CheckScriptFailure(lines, 'E1012:') 2169enddef 2170 2171def Test_global_closure() 2172 var lines =<< trim END 2173 vim9script 2174 def ReverseEveryNLines(n: number, line1: number, line2: number) 2175 var mods = 'sil keepj keepp lockm ' 2176 var range = ':' .. line1 .. ',' .. line2 2177 def g:Offset(): number 2178 var offset = (line('.') - line1 + 1) % n 2179 return offset != 0 ? offset : n 2180 enddef 2181 exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()' 2182 enddef 2183 2184 new 2185 repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1) 2186 ReverseEveryNLines(3, 1, 9) 2187 END 2188 CheckScriptSuccess(lines) 2189 var expected = repeat(['ccc', 'bbb', 'aaa'], 3) 2190 assert_equal(expected, getline(1, 9)) 2191 bwipe! 2192enddef 2193 2194def Test_global_closure_called_directly() 2195 var lines =<< trim END 2196 vim9script 2197 def Outer() 2198 var x = 1 2199 def g:Inner() 2200 var y = x 2201 x += 1 2202 assert_equal(1, y) 2203 enddef 2204 g:Inner() 2205 assert_equal(2, x) 2206 enddef 2207 Outer() 2208 END 2209 CheckScriptSuccess(lines) 2210 delfunc g:Inner 2211enddef 2212 2213def Test_failure_in_called_function() 2214 # this was using the frame index as the return value 2215 var lines =<< trim END 2216 vim9script 2217 au TerminalWinOpen * eval [][0] 2218 def PopupTerm(a: any) 2219 # make sure typvals on stack are string 2220 ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join() 2221 FireEvent() 2222 enddef 2223 def FireEvent() 2224 do TerminalWinOpen 2225 enddef 2226 # use try/catch to make eval fail 2227 try 2228 call PopupTerm(0) 2229 catch 2230 endtry 2231 au! TerminalWinOpen 2232 END 2233 CheckScriptSuccess(lines) 2234enddef 2235 2236def Test_nested_lambda() 2237 var lines =<< trim END 2238 vim9script 2239 def Func() 2240 var x = 4 2241 var Lambda1 = () => 7 2242 var Lambda2 = () => [Lambda1(), x] 2243 var res = Lambda2() 2244 assert_equal([7, 4], res) 2245 enddef 2246 Func() 2247 END 2248 CheckScriptSuccess(lines) 2249enddef 2250 2251def Test_double_nested_lambda() 2252 var lines =<< trim END 2253 vim9script 2254 def F(head: string): func(string): func(string): string 2255 return (sep: string): func(string): string => ((tail: string): string => { 2256 return head .. sep .. tail 2257 }) 2258 enddef 2259 assert_equal('hello-there', F('hello')('-')('there')) 2260 END 2261 CheckScriptSuccess(lines) 2262enddef 2263 2264def Test_nested_inline_lambda() 2265 var lines =<< trim END 2266 vim9script 2267 def F(text: string): func(string): func(string): string 2268 return (arg: string): func(string): string => ((sep: string): string => { 2269 return sep .. arg .. text 2270 }) 2271 enddef 2272 assert_equal('--there++', F('++')('there')('--')) 2273 END 2274 CheckScriptSuccess(lines) 2275 2276 lines =<< trim END 2277 vim9script 2278 echo range(4)->mapnew((_, v) => { 2279 return range(v) ->mapnew((_, s) => { 2280 return string(s) 2281 }) 2282 }) 2283 END 2284 CheckScriptSuccess(lines) 2285 2286 lines =<< trim END 2287 vim9script 2288 2289 def s:func() 2290 range(10) 2291 ->mapnew((_, _) => ({ 2292 key: range(10)->mapnew((_, _) => { 2293 return ' ' 2294 }), 2295 })) 2296 enddef 2297 2298 defcomp 2299 END 2300 CheckScriptSuccess(lines) 2301enddef 2302 2303def Shadowed(): list<number> 2304 var FuncList: list<func: number> = [() => 42] 2305 return FuncList->mapnew((_, Shadowed) => Shadowed()) 2306enddef 2307 2308def Test_lambda_arg_shadows_func() 2309 assert_equal([42], Shadowed()) 2310enddef 2311 2312def Line_continuation_in_def(dir: string = ''): string 2313 var path: string = empty(dir) 2314 \ ? 'empty' 2315 \ : 'full' 2316 return path 2317enddef 2318 2319def Test_line_continuation_in_def() 2320 Line_continuation_in_def('.')->assert_equal('full') 2321enddef 2322 2323def Test_script_var_in_lambda() 2324 var lines =<< trim END 2325 vim9script 2326 var script = 'test' 2327 assert_equal(['test'], map(['one'], (_, _) => script)) 2328 END 2329 CheckScriptSuccess(lines) 2330enddef 2331 2332def Line_continuation_in_lambda(): list<string> 2333 var x = range(97, 100) 2334 ->mapnew((_, v) => nr2char(v) 2335 ->toupper()) 2336 ->reverse() 2337 return x 2338enddef 2339 2340def Test_line_continuation_in_lambda() 2341 Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A']) 2342 2343 var lines =<< trim END 2344 vim9script 2345 var res = [{n: 1, m: 2, s: 'xxx'}] 2346 ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s', 2347 v.n, 2348 v.m, 2349 substitute(v.s, '.*', 'yyy', '') 2350 )) 2351 assert_equal(['1:2:yyy'], res) 2352 END 2353 CheckScriptSuccess(lines) 2354enddef 2355 2356def Test_list_lambda() 2357 timer_start(1000, (_) => 0) 2358 var body = execute(timer_info()[0].callback 2359 ->string() 2360 ->substitute("('", ' ', '') 2361 ->substitute("')", '', '') 2362 ->substitute('function\zs', ' ', '')) 2363 assert_match('def <lambda>\d\+(_: any): number\n1 return 0\n enddef', body) 2364enddef 2365 2366def Test_lambda_block_variable() 2367 var lines =<< trim END 2368 vim9script 2369 var flist: list<func> 2370 for i in range(10) 2371 var inloop = i 2372 flist[i] = () => inloop 2373 endfor 2374 END 2375 CheckScriptSuccess(lines) 2376 2377 lines =<< trim END 2378 vim9script 2379 if true 2380 var outloop = 5 2381 var flist: list<func> 2382 for i in range(10) 2383 flist[i] = () => outloop 2384 endfor 2385 endif 2386 END 2387 CheckScriptSuccess(lines) 2388 2389 lines =<< trim END 2390 vim9script 2391 if true 2392 var outloop = 5 2393 endif 2394 var flist: list<func> 2395 for i in range(10) 2396 flist[i] = () => outloop 2397 endfor 2398 END 2399 CheckScriptFailure(lines, 'E1001: Variable not found: outloop', 1) 2400 2401 lines =<< trim END 2402 vim9script 2403 for i in range(10) 2404 var Ref = () => 0 2405 endfor 2406 assert_equal(0, ((i) => 0)(0)) 2407 END 2408 CheckScriptSuccess(lines) 2409enddef 2410 2411def Test_legacy_lambda() 2412 legacy echo {x -> 'hello ' .. x}('foo') 2413 2414 var lines =<< trim END 2415 echo {x -> 'hello ' .. x}('foo') 2416 END 2417 CheckDefAndScriptFailure(lines, 'E720:') 2418 2419 lines =<< trim END 2420 vim9script 2421 def Func() 2422 echo (() => 'no error')() 2423 enddef 2424 legacy call s:Func() 2425 END 2426 CheckScriptSuccess(lines) 2427enddef 2428 2429def Test_legacy() 2430 var lines =<< trim END 2431 vim9script 2432 func g:LegacyFunction() 2433 let g:legacyvar = 1 2434 endfunc 2435 def Testit() 2436 legacy call g:LegacyFunction() 2437 enddef 2438 Testit() 2439 assert_equal(1, g:legacyvar) 2440 unlet g:legacyvar 2441 delfunc g:LegacyFunction 2442 END 2443 CheckScriptSuccess(lines) 2444enddef 2445 2446def Test_legacy_errors() 2447 for cmd in ['if', 'elseif', 'else', 'endif', 2448 'for', 'endfor', 'continue', 'break', 2449 'while', 'endwhile', 2450 'try', 'catch', 'finally', 'endtry'] 2451 CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:') 2452 endfor 2453enddef 2454 2455def DoFilterThis(a: string): list<string> 2456 # closure nested inside another closure using argument 2457 var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0) 2458 return ['x', 'y', 'a', 'x2', 'c']->Filter() 2459enddef 2460 2461def Test_nested_closure_using_argument() 2462 assert_equal(['x', 'x2'], DoFilterThis('x')) 2463enddef 2464 2465def Test_triple_nested_closure() 2466 var what = 'x' 2467 var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0 2468 var Filter = (l) => filter(l, (_, v) => Match(v, what)) 2469 assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter()) 2470enddef 2471 2472func Test_silent_echo() 2473 CheckScreendump 2474 2475 let lines =<< trim END 2476 vim9script 2477 def EchoNothing() 2478 silent echo '' 2479 enddef 2480 defcompile 2481 END 2482 call writefile(lines, 'XTest_silent_echo') 2483 2484 " Check that the balloon shows up after a mouse move 2485 let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6}) 2486 call term_sendkeys(buf, ":abc") 2487 call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {}) 2488 2489 " clean up 2490 call StopVimInTerminal(buf) 2491 call delete('XTest_silent_echo') 2492endfunc 2493 2494def SilentlyError() 2495 execute('silent! invalid') 2496 g:did_it = 'yes' 2497enddef 2498 2499func UserError() 2500 silent! invalid 2501endfunc 2502 2503def SilentlyUserError() 2504 UserError() 2505 g:did_it = 'yes' 2506enddef 2507 2508" This can't be a :def function, because the assert would not be reached. 2509func Test_ignore_silent_error() 2510 let g:did_it = 'no' 2511 call SilentlyError() 2512 call assert_equal('yes', g:did_it) 2513 2514 let g:did_it = 'no' 2515 call SilentlyUserError() 2516 call assert_equal('yes', g:did_it) 2517 2518 unlet g:did_it 2519endfunc 2520 2521def Test_ignore_silent_error_in_filter() 2522 var lines =<< trim END 2523 vim9script 2524 def Filter(winid: number, key: string): bool 2525 if key == 'o' 2526 silent! eval [][0] 2527 return true 2528 endif 2529 return popup_filter_menu(winid, key) 2530 enddef 2531 2532 popup_create('popup', {filter: Filter}) 2533 feedkeys("o\r", 'xnt') 2534 END 2535 CheckScriptSuccess(lines) 2536enddef 2537 2538def Fibonacci(n: number): number 2539 if n < 2 2540 return n 2541 else 2542 return Fibonacci(n - 1) + Fibonacci(n - 2) 2543 endif 2544enddef 2545 2546def Test_recursive_call() 2547 Fibonacci(20)->assert_equal(6765) 2548enddef 2549 2550def TreeWalk(dir: string): list<any> 2551 return readdir(dir)->mapnew((_, val) => 2552 fnamemodify(dir .. '/' .. val, ':p')->isdirectory() 2553 ? {[val]: TreeWalk(dir .. '/' .. val)} 2554 : val 2555 ) 2556enddef 2557 2558def Test_closure_in_map() 2559 mkdir('XclosureDir/tdir', 'p') 2560 writefile(['111'], 'XclosureDir/file1') 2561 writefile(['222'], 'XclosureDir/file2') 2562 writefile(['333'], 'XclosureDir/tdir/file3') 2563 2564 TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}]) 2565 2566 delete('XclosureDir', 'rf') 2567enddef 2568 2569def Test_invalid_function_name() 2570 var lines =<< trim END 2571 vim9script 2572 def s: list<string> 2573 END 2574 CheckScriptFailure(lines, 'E129:') 2575 2576 lines =<< trim END 2577 vim9script 2578 def g: list<string> 2579 END 2580 CheckScriptFailure(lines, 'E129:') 2581 2582 lines =<< trim END 2583 vim9script 2584 def <SID>: list<string> 2585 END 2586 CheckScriptFailure(lines, 'E884:') 2587 2588 lines =<< trim END 2589 vim9script 2590 def F list<string> 2591 END 2592 CheckScriptFailure(lines, 'E488:') 2593enddef 2594 2595def Test_partial_call() 2596 var lines =<< trim END 2597 var Xsetlist: func 2598 Xsetlist = function('setloclist', [0]) 2599 Xsetlist([], ' ', {title: 'test'}) 2600 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2601 2602 Xsetlist = function('setloclist', [0, [], ' ']) 2603 Xsetlist({title: 'test'}) 2604 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2605 2606 Xsetlist = function('setqflist') 2607 Xsetlist([], ' ', {title: 'test'}) 2608 getqflist({title: 1})->assert_equal({title: 'test'}) 2609 2610 Xsetlist = function('setqflist', [[], ' ']) 2611 Xsetlist({title: 'test'}) 2612 getqflist({title: 1})->assert_equal({title: 'test'}) 2613 2614 var Len: func: number = function('len', ['word']) 2615 assert_equal(4, Len()) 2616 2617 var RepeatFunc = function('repeat', ['o']) 2618 assert_equal('ooooo', RepeatFunc(5)) 2619 END 2620 CheckDefAndScriptSuccess(lines) 2621enddef 2622 2623def Test_cmd_modifier() 2624 tab echo '0' 2625 CheckDefFailure(['5tab echo 3'], 'E16:') 2626enddef 2627 2628def Test_restore_modifiers() 2629 # check that when compiling a :def function command modifiers are not messed 2630 # up. 2631 var lines =<< trim END 2632 vim9script 2633 set eventignore= 2634 autocmd QuickFixCmdPost * copen 2635 def AutocmdsDisabled() 2636 eval 1 + 2 2637 enddef 2638 func Func() 2639 noautocmd call s:AutocmdsDisabled() 2640 let g:ei_after = &eventignore 2641 endfunc 2642 Func() 2643 END 2644 CheckScriptSuccess(lines) 2645 g:ei_after->assert_equal('') 2646enddef 2647 2648def StackTop() 2649 eval 1 + 2 2650 eval 2 + 3 2651 # call not on fourth line 2652 StackBot() 2653enddef 2654 2655def StackBot() 2656 # throw an error 2657 eval [][0] 2658enddef 2659 2660def Test_callstack_def() 2661 try 2662 StackTop() 2663 catch 2664 v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2') 2665 endtry 2666enddef 2667 2668" Re-using spot for variable used in block 2669def Test_block_scoped_var() 2670 var lines =<< trim END 2671 vim9script 2672 def Func() 2673 var x = ['a', 'b', 'c'] 2674 if 1 2675 var y = 'x' 2676 map(x, (_, _) => y) 2677 endif 2678 var z = x 2679 assert_equal(['x', 'x', 'x'], z) 2680 enddef 2681 Func() 2682 END 2683 CheckScriptSuccess(lines) 2684enddef 2685 2686def Test_reset_did_emsg() 2687 var lines =<< trim END 2688 @s = 'blah' 2689 au BufWinLeave * # 2690 def Func() 2691 var winid = popup_create('popup', {}) 2692 exe '*s' 2693 popup_close(winid) 2694 enddef 2695 Func() 2696 END 2697 CheckScriptFailure(lines, 'E492:', 8) 2698 delfunc! g:Func 2699enddef 2700 2701def Test_did_emsg_reset() 2702 # executing an autocommand resets did_emsg, this should not result in a 2703 # builtin function considered failing 2704 var lines =<< trim END 2705 vim9script 2706 au BufWinLeave * # 2707 def Func() 2708 popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()}) 2709 eval [][0] 2710 enddef 2711 nno <F3> <cmd>call <sid>Func()<cr> 2712 feedkeys("\<F3>\e", 'xt') 2713 END 2714 writefile(lines, 'XemsgReset') 2715 assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2) 2716 delete('XemsgReset') 2717 nunmap <F3> 2718 au! BufWinLeave 2719enddef 2720 2721def Test_abort_with_silent_call() 2722 var lines =<< trim END 2723 vim9script 2724 g:result = 'none' 2725 def Func() 2726 g:result += 3 2727 g:result = 'yes' 2728 enddef 2729 # error is silenced, but function aborts on error 2730 silent! Func() 2731 assert_equal('none', g:result) 2732 unlet g:result 2733 END 2734 CheckScriptSuccess(lines) 2735enddef 2736 2737def Test_continues_with_silent_error() 2738 var lines =<< trim END 2739 vim9script 2740 g:result = 'none' 2741 def Func() 2742 silent! g:result += 3 2743 g:result = 'yes' 2744 enddef 2745 # error is silenced, function does not abort 2746 Func() 2747 assert_equal('yes', g:result) 2748 unlet g:result 2749 END 2750 CheckScriptSuccess(lines) 2751enddef 2752 2753def Test_abort_even_with_silent() 2754 var lines =<< trim END 2755 vim9script 2756 g:result = 'none' 2757 def Func() 2758 eval {-> ''}() .. '' .. {}['X'] 2759 g:result = 'yes' 2760 enddef 2761 silent! Func() 2762 assert_equal('none', g:result) 2763 unlet g:result 2764 END 2765 CheckScriptSuccess(lines) 2766enddef 2767 2768def Test_cmdmod_silent_restored() 2769 var lines =<< trim END 2770 vim9script 2771 def Func() 2772 g:result = 'none' 2773 silent! g:result += 3 2774 g:result = 'none' 2775 g:result += 3 2776 enddef 2777 Func() 2778 END 2779 # can't use CheckScriptFailure, it ignores the :silent! 2780 var fname = 'Xdefsilent' 2781 writefile(lines, fname) 2782 var caught = 'no' 2783 try 2784 exe 'source ' .. fname 2785 catch /E1030:/ 2786 caught = 'yes' 2787 assert_match('Func, line 4', v:throwpoint) 2788 endtry 2789 assert_equal('yes', caught) 2790 delete(fname) 2791enddef 2792 2793def Test_cmdmod_silent_nested() 2794 var lines =<< trim END 2795 vim9script 2796 var result = '' 2797 2798 def Error() 2799 result ..= 'Eb' 2800 eval [][0] 2801 result ..= 'Ea' 2802 enddef 2803 2804 def Crash() 2805 result ..= 'Cb' 2806 sil! Error() 2807 result ..= 'Ca' 2808 enddef 2809 2810 Crash() 2811 assert_equal('CbEbEaCa', result) 2812 END 2813 CheckScriptSuccess(lines) 2814enddef 2815 2816def Test_dict_member_with_silent() 2817 var lines =<< trim END 2818 vim9script 2819 g:result = 'none' 2820 var d: dict<any> 2821 def Func() 2822 try 2823 g:result = map([], (_, v) => ({}[v]))->join() .. d[''] 2824 catch 2825 endtry 2826 enddef 2827 silent! Func() 2828 assert_equal('0', g:result) 2829 unlet g:result 2830 END 2831 CheckScriptSuccess(lines) 2832enddef 2833 2834def Test_skip_cmds_with_silent() 2835 var lines =<< trim END 2836 vim9script 2837 2838 def Func(b: bool) 2839 Crash() 2840 enddef 2841 2842 def Crash() 2843 sil! :/not found/d _ 2844 sil! :/not found/put _ 2845 enddef 2846 2847 Func(true) 2848 END 2849 CheckScriptSuccess(lines) 2850enddef 2851 2852def Test_opfunc() 2853 nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@ 2854 def g:Opfunc(_: any): string 2855 setline(1, 'ASDF') 2856 return '' 2857 enddef 2858 new 2859 setline(1, 'asdf') 2860 feedkeys("\<F3>$", 'x') 2861 assert_equal('ASDF', getline(1)) 2862 2863 bwipe! 2864 nunmap <F3> 2865enddef 2866 2867" this was crashing on exit 2868def Test_nested_lambda_in_closure() 2869 var lines =<< trim END 2870 vim9script 2871 command WriteDone writefile(['Done'], 'XnestedDone') 2872 def Outer() 2873 def g:Inner() 2874 echo map([1, 2, 3], {_, v -> v + 1}) 2875 enddef 2876 g:Inner() 2877 enddef 2878 defcompile 2879 # not reached 2880 END 2881 if !RunVim([], lines, '--clean -c WriteDone -c quit') 2882 return 2883 endif 2884 assert_equal(['Done'], readfile('XnestedDone')) 2885 delete('XnestedDone') 2886enddef 2887 2888def Test_check_func_arg_types() 2889 var lines =<< trim END 2890 vim9script 2891 def F1(x: string): string 2892 return x 2893 enddef 2894 2895 def F2(x: number): number 2896 return x + 1 2897 enddef 2898 2899 def G(g: func): dict<func> 2900 return {f: g} 2901 enddef 2902 2903 def H(d: dict<func>): string 2904 return d.f('a') 2905 enddef 2906 END 2907 2908 CheckScriptSuccess(lines + ['echo H(G(F1))']) 2909 CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:') 2910enddef 2911 2912def Test_compile_error() 2913 var lines =<< trim END 2914 def g:Broken() 2915 echo 'a' + {} 2916 enddef 2917 call g:Broken() 2918 END 2919 # First call: compilation error 2920 CheckScriptFailure(lines, 'E1051: Wrong argument type for +') 2921 2922 # Second call won't try compiling again 2923 assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken') 2924 delfunc g:Broken 2925 2926 # No error when compiling with :silent! 2927 lines =<< trim END 2928 def g:Broken() 2929 echo 'a' + [] 2930 enddef 2931 silent! defcompile 2932 END 2933 CheckScriptSuccess(lines) 2934 2935 # Calling the function won't try compiling again 2936 assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken') 2937 delfunc g:Broken 2938enddef 2939 2940def Test_ignored_argument() 2941 var lines =<< trim END 2942 vim9script 2943 def Ignore(_, _): string 2944 return 'yes' 2945 enddef 2946 assert_equal('yes', Ignore(1, 2)) 2947 2948 func Ok(_) 2949 return a:_ 2950 endfunc 2951 assert_equal('ok', Ok('ok')) 2952 2953 func Oktoo() 2954 let _ = 'too' 2955 return _ 2956 endfunc 2957 assert_equal('too', Oktoo()) 2958 2959 assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1))) 2960 END 2961 CheckScriptSuccess(lines) 2962 2963 lines =<< trim END 2964 def Ignore(_: string): string 2965 return _ 2966 enddef 2967 defcompile 2968 END 2969 CheckScriptFailure(lines, 'E1181:', 1) 2970 2971 lines =<< trim END 2972 var _ = 1 2973 END 2974 CheckDefAndScriptFailure(lines, 'E1181:', 1) 2975 2976 lines =<< trim END 2977 var x = _ 2978 END 2979 CheckDefAndScriptFailure(lines, 'E1181:', 1) 2980enddef 2981 2982def Test_too_many_arguments() 2983 var lines =<< trim END 2984 echo [0, 1, 2]->map(() => 123) 2985 END 2986 CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1) 2987 2988 lines =<< trim END 2989 echo [0, 1, 2]->map((_) => 123) 2990 END 2991 CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1) 2992enddef 2993 2994def Test_closing_brace_at_start_of_line() 2995 var lines =<< trim END 2996 def Func() 2997 enddef 2998 Func( 2999 ) 3000 END 3001 call CheckDefAndScriptSuccess(lines) 3002enddef 3003 3004if has('python3') 3005 def Test_python3_heredoc() 3006 py3 << trim EOF 3007 import vim 3008 vim.vars['didit'] = 'yes' 3009 EOF 3010 assert_equal('yes', g:didit) 3011 3012 python3 << trim EOF 3013 import vim 3014 vim.vars['didit'] = 'again' 3015 EOF 3016 assert_equal('again', g:didit) 3017 enddef 3018endif 3019 3020" This messes up syntax highlight, keep near the end. 3021if has('lua') 3022 def Test_lua_heredoc() 3023 g:d = {} 3024 lua << trim EOF 3025 x = vim.eval('g:d') 3026 x['key'] = 'val' 3027 EOF 3028 assert_equal('val', g:d.key) 3029 enddef 3030endif 3031 3032 3033" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 3034