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:') 1152enddef 1153 1154let s:value = '' 1155 1156def FuncOneDefArg(opt = 'text') 1157 s:value = opt 1158enddef 1159 1160def FuncTwoDefArg(nr = 123, opt = 'text'): string 1161 return nr .. opt 1162enddef 1163 1164def FuncVarargs(...arg: list<string>): string 1165 return join(arg, ',') 1166enddef 1167 1168def Test_func_type_varargs() 1169 var RefDefArg: func(?string) 1170 RefDefArg = FuncOneDefArg 1171 RefDefArg() 1172 s:value->assert_equal('text') 1173 RefDefArg('some') 1174 s:value->assert_equal('some') 1175 1176 var RefDef2Arg: func(?number, ?string): string 1177 RefDef2Arg = FuncTwoDefArg 1178 RefDef2Arg()->assert_equal('123text') 1179 RefDef2Arg(99)->assert_equal('99text') 1180 RefDef2Arg(77, 'some')->assert_equal('77some') 1181 1182 CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:') 1183 CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:') 1184 1185 var RefVarargs: func(...list<string>): string 1186 RefVarargs = FuncVarargs 1187 RefVarargs()->assert_equal('') 1188 RefVarargs('one')->assert_equal('one') 1189 RefVarargs('one', 'two')->assert_equal('one,two') 1190 1191 CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:') 1192 CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:') 1193enddef 1194 1195" Only varargs 1196def MyVarargsOnly(...args: list<string>): string 1197 return join(args, ',') 1198enddef 1199 1200def Test_call_varargs_only() 1201 MyVarargsOnly()->assert_equal('') 1202 MyVarargsOnly('one')->assert_equal('one') 1203 MyVarargsOnly('one', 'two')->assert_equal('one,two') 1204 CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number') 1205 CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number') 1206enddef 1207 1208def Test_using_var_as_arg() 1209 writefile(['def Func(x: number)', 'var x = 234', 'enddef', 'defcompile'], 'Xdef') 1210 assert_fails('so Xdef', 'E1006:', '', 1, 'Func') 1211 delete('Xdef') 1212enddef 1213 1214def DictArg(arg: dict<string>) 1215 arg['key'] = 'value' 1216enddef 1217 1218def ListArg(arg: list<string>) 1219 arg[0] = 'value' 1220enddef 1221 1222def Test_assign_to_argument() 1223 # works for dict and list 1224 var d: dict<string> = {} 1225 DictArg(d) 1226 d['key']->assert_equal('value') 1227 var l: list<string> = [] 1228 ListArg(l) 1229 l[0]->assert_equal('value') 1230 1231 CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:') 1232 delfunc! g:Func 1233enddef 1234 1235" These argument names are reserved in legacy functions. 1236def WithReservedNames(firstline: string, lastline: string): string 1237 return firstline .. lastline 1238enddef 1239 1240def Test_argument_names() 1241 assert_equal('OK', WithReservedNames('O', 'K')) 1242enddef 1243 1244def Test_call_func_defined_later() 1245 g:DefinedLater('one')->assert_equal('one') 1246 assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later') 1247enddef 1248 1249func DefinedLater(arg) 1250 return a:arg 1251endfunc 1252 1253def Test_call_funcref() 1254 g:SomeFunc('abc')->assert_equal(3) 1255 assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call 1256 assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref') 1257 1258 var lines =<< trim END 1259 vim9script 1260 def RetNumber(): number 1261 return 123 1262 enddef 1263 var Funcref: func: number = function('RetNumber') 1264 Funcref()->assert_equal(123) 1265 END 1266 CheckScriptSuccess(lines) 1267 1268 lines =<< trim END 1269 vim9script 1270 def RetNumber(): number 1271 return 123 1272 enddef 1273 def Bar(F: func: number): number 1274 return F() 1275 enddef 1276 var Funcref = function('RetNumber') 1277 Bar(Funcref)->assert_equal(123) 1278 END 1279 CheckScriptSuccess(lines) 1280 1281 lines =<< trim END 1282 vim9script 1283 def UseNumber(nr: number) 1284 echo nr 1285 enddef 1286 var Funcref: func(number) = function('UseNumber') 1287 Funcref(123) 1288 END 1289 CheckScriptSuccess(lines) 1290 1291 lines =<< trim END 1292 vim9script 1293 def UseNumber(nr: number) 1294 echo nr 1295 enddef 1296 var Funcref: func(string) = function('UseNumber') 1297 END 1298 CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)') 1299 1300 lines =<< trim END 1301 vim9script 1302 def EchoNr(nr = 34) 1303 g:echo = nr 1304 enddef 1305 var Funcref: func(?number) = function('EchoNr') 1306 Funcref() 1307 g:echo->assert_equal(34) 1308 Funcref(123) 1309 g:echo->assert_equal(123) 1310 END 1311 CheckScriptSuccess(lines) 1312 1313 lines =<< trim END 1314 vim9script 1315 def EchoList(...l: list<number>) 1316 g:echo = l 1317 enddef 1318 var Funcref: func(...list<number>) = function('EchoList') 1319 Funcref() 1320 g:echo->assert_equal([]) 1321 Funcref(1, 2, 3) 1322 g:echo->assert_equal([1, 2, 3]) 1323 END 1324 CheckScriptSuccess(lines) 1325 1326 lines =<< trim END 1327 vim9script 1328 def OptAndVar(nr: number, opt = 12, ...l: list<number>): number 1329 g:optarg = opt 1330 g:listarg = l 1331 return nr 1332 enddef 1333 var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar') 1334 Funcref(10)->assert_equal(10) 1335 g:optarg->assert_equal(12) 1336 g:listarg->assert_equal([]) 1337 1338 Funcref(11, 22)->assert_equal(11) 1339 g:optarg->assert_equal(22) 1340 g:listarg->assert_equal([]) 1341 1342 Funcref(17, 18, 1, 2, 3)->assert_equal(17) 1343 g:optarg->assert_equal(18) 1344 g:listarg->assert_equal([1, 2, 3]) 1345 END 1346 CheckScriptSuccess(lines) 1347enddef 1348 1349let SomeFunc = function('len') 1350let NotAFunc = 'text' 1351 1352def CombineFuncrefTypes() 1353 # same arguments, different return type 1354 var Ref1: func(bool): string 1355 var Ref2: func(bool): number 1356 var Ref3: func(bool): any 1357 Ref3 = g:cond ? Ref1 : Ref2 1358 1359 # different number of arguments 1360 var Refa1: func(bool): number 1361 var Refa2: func(bool, number): number 1362 var Refa3: func: number 1363 Refa3 = g:cond ? Refa1 : Refa2 1364 1365 # different argument types 1366 var Refb1: func(bool, string): number 1367 var Refb2: func(string, number): number 1368 var Refb3: func(any, any): number 1369 Refb3 = g:cond ? Refb1 : Refb2 1370enddef 1371 1372def FuncWithForwardCall() 1373 return g:DefinedEvenLater("yes") 1374enddef 1375 1376def DefinedEvenLater(arg: string): string 1377 return arg 1378enddef 1379 1380def Test_error_in_nested_function() 1381 # Error in called function requires unwinding the call stack. 1382 assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall') 1383enddef 1384 1385def Test_return_type_wrong() 1386 CheckScriptFailure([ 1387 'def Func(): number', 1388 'return "a"', 1389 'enddef', 1390 'defcompile'], 'expected number but got string') 1391 delfunc! g:Func 1392 CheckScriptFailure([ 1393 'def Func(): string', 1394 'return 1', 1395 'enddef', 1396 'defcompile'], 'expected string but got number') 1397 delfunc! g:Func 1398 CheckScriptFailure([ 1399 'def Func(): void', 1400 'return "a"', 1401 'enddef', 1402 'defcompile'], 1403 'E1096: Returning a value in a function without a return type') 1404 delfunc! g:Func 1405 CheckScriptFailure([ 1406 'def Func()', 1407 'return "a"', 1408 'enddef', 1409 'defcompile'], 1410 'E1096: Returning a value in a function without a return type') 1411 delfunc! g:Func 1412 1413 CheckScriptFailure([ 1414 'def Func(): number', 1415 'return', 1416 'enddef', 1417 'defcompile'], 'E1003:') 1418 delfunc! g:Func 1419 1420 CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') 1421 delfunc! g:Func 1422 CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') 1423 delfunc! g:Func 1424 CheckScriptFailure(['def Func()', 'return 1'], 'E1057:') 1425 delfunc! g:Func 1426 1427 CheckScriptFailure([ 1428 'vim9script', 1429 'def FuncB()', 1430 ' return 123', 1431 'enddef', 1432 'def FuncA()', 1433 ' FuncB()', 1434 'enddef', 1435 'defcompile'], 'E1096:') 1436enddef 1437 1438def Test_arg_type_wrong() 1439 CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') 1440 CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...') 1441 CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:') 1442 CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:') 1443 CheckScriptFailure(['def Func6(...x:list<number>)', 'echo "a"', 'enddef'], 'E1069:') 1444 CheckScriptFailure(['def Func7(...x: int)', 'echo "a"', 'enddef'], 'E1010:') 1445enddef 1446 1447def Test_white_space_before_comma() 1448 var lines =<< trim END 1449 vim9script 1450 def Func(a: number , b: number) 1451 enddef 1452 END 1453 CheckScriptFailure(lines, 'E1068:') 1454 call assert_fails('vim9cmd echo stridx("a" .. "b" , "a")', 'E1068:') 1455enddef 1456 1457def Test_white_space_after_comma() 1458 var lines =<< trim END 1459 vim9script 1460 def Func(a: number,b: number) 1461 enddef 1462 END 1463 CheckScriptFailure(lines, 'E1069:') 1464 1465 # OK in legacy function 1466 lines =<< trim END 1467 vim9script 1468 func Func(a,b) 1469 endfunc 1470 END 1471 CheckScriptSuccess(lines) 1472enddef 1473 1474def Test_vim9script_call() 1475 var lines =<< trim END 1476 vim9script 1477 var name = '' 1478 def MyFunc(arg: string) 1479 name = arg 1480 enddef 1481 MyFunc('foobar') 1482 name->assert_equal('foobar') 1483 1484 var str = 'barfoo' 1485 str->MyFunc() 1486 name->assert_equal('barfoo') 1487 1488 g:value = 'value' 1489 g:value->MyFunc() 1490 name->assert_equal('value') 1491 1492 var listvar = [] 1493 def ListFunc(arg: list<number>) 1494 listvar = arg 1495 enddef 1496 [1, 2, 3]->ListFunc() 1497 listvar->assert_equal([1, 2, 3]) 1498 1499 var dictvar = {} 1500 def DictFunc(arg: dict<number>) 1501 dictvar = arg 1502 enddef 1503 {a: 1, b: 2}->DictFunc() 1504 dictvar->assert_equal({a: 1, b: 2}) 1505 def CompiledDict() 1506 {a: 3, b: 4}->DictFunc() 1507 enddef 1508 CompiledDict() 1509 dictvar->assert_equal({a: 3, b: 4}) 1510 1511 {a: 3, b: 4}->DictFunc() 1512 dictvar->assert_equal({a: 3, b: 4}) 1513 1514 ('text')->MyFunc() 1515 name->assert_equal('text') 1516 ("some")->MyFunc() 1517 name->assert_equal('some') 1518 1519 # line starting with single quote is not a mark 1520 # line starting with double quote can be a method call 1521 'asdfasdf'->MyFunc() 1522 name->assert_equal('asdfasdf') 1523 "xyz"->MyFunc() 1524 name->assert_equal('xyz') 1525 1526 def UseString() 1527 'xyork'->MyFunc() 1528 enddef 1529 UseString() 1530 name->assert_equal('xyork') 1531 1532 def UseString2() 1533 "knife"->MyFunc() 1534 enddef 1535 UseString2() 1536 name->assert_equal('knife') 1537 1538 # prepending a colon makes it a mark 1539 new 1540 setline(1, ['aaa', 'bbb', 'ccc']) 1541 normal! 3Gmt1G 1542 :'t 1543 getcurpos()[1]->assert_equal(3) 1544 bwipe! 1545 1546 MyFunc( 1547 'continued' 1548 ) 1549 assert_equal('continued', 1550 name 1551 ) 1552 1553 call MyFunc( 1554 'more' 1555 .. 1556 'lines' 1557 ) 1558 assert_equal( 1559 'morelines', 1560 name) 1561 END 1562 writefile(lines, 'Xcall.vim') 1563 source Xcall.vim 1564 delete('Xcall.vim') 1565enddef 1566 1567def Test_vim9script_call_fail_decl() 1568 var lines =<< trim END 1569 vim9script 1570 var name = '' 1571 def MyFunc(arg: string) 1572 var name = 123 1573 enddef 1574 defcompile 1575 END 1576 CheckScriptFailure(lines, 'E1054:') 1577enddef 1578 1579def Test_vim9script_call_fail_type() 1580 var lines =<< trim END 1581 vim9script 1582 def MyFunc(arg: string) 1583 echo arg 1584 enddef 1585 MyFunc(1234) 1586 END 1587 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') 1588enddef 1589 1590def Test_vim9script_call_fail_const() 1591 var lines =<< trim END 1592 vim9script 1593 const var = '' 1594 def MyFunc(arg: string) 1595 var = 'asdf' 1596 enddef 1597 defcompile 1598 END 1599 writefile(lines, 'Xcall_const.vim') 1600 assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') 1601 delete('Xcall_const.vim') 1602 1603 lines =<< trim END 1604 const g:Aconst = 77 1605 def Change() 1606 # comment 1607 g:Aconst = 99 1608 enddef 1609 call Change() 1610 unlet g:Aconst 1611 END 1612 CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) 1613enddef 1614 1615" Test that inside :function a Python function can be defined, :def is not 1616" recognized. 1617func Test_function_python() 1618 CheckFeature python3 1619 let py = 'python3' 1620 execute py "<< EOF" 1621def do_something(): 1622 return 1 1623EOF 1624endfunc 1625 1626def Test_delfunc() 1627 var lines =<< trim END 1628 vim9script 1629 def g:GoneSoon() 1630 echo 'hello' 1631 enddef 1632 1633 def CallGoneSoon() 1634 GoneSoon() 1635 enddef 1636 defcompile 1637 1638 delfunc g:GoneSoon 1639 CallGoneSoon() 1640 END 1641 writefile(lines, 'XToDelFunc') 1642 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1643 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1644 1645 delete('XToDelFunc') 1646enddef 1647 1648def Test_redef_failure() 1649 writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') 1650 so Xdef 1651 writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') 1652 so Xdef 1653 writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef') 1654 assert_fails('so Xdef', 'E1027:', '', 1, 'Func0') 1655 writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') 1656 so Xdef 1657 delete('Xdef') 1658 1659 assert_fails('g:Func0()', 'E1091:') 1660 g:Func1()->assert_equal('Func1') 1661 g:Func2()->assert_equal('Func2') 1662 1663 delfunc! Func0 1664 delfunc! Func1 1665 delfunc! Func2 1666enddef 1667 1668def Test_vim9script_func() 1669 var lines =<< trim END 1670 vim9script 1671 func Func(arg) 1672 echo a:arg 1673 endfunc 1674 Func('text') 1675 END 1676 writefile(lines, 'XVim9Func') 1677 so XVim9Func 1678 1679 delete('XVim9Func') 1680enddef 1681 1682let s:funcResult = 0 1683 1684def FuncNoArgNoRet() 1685 s:funcResult = 11 1686enddef 1687 1688def FuncNoArgRetNumber(): number 1689 s:funcResult = 22 1690 return 1234 1691enddef 1692 1693def FuncNoArgRetString(): string 1694 s:funcResult = 45 1695 return 'text' 1696enddef 1697 1698def FuncOneArgNoRet(arg: number) 1699 s:funcResult = arg 1700enddef 1701 1702def FuncOneArgRetNumber(arg: number): number 1703 s:funcResult = arg 1704 return arg 1705enddef 1706 1707def FuncTwoArgNoRet(one: bool, two: number) 1708 s:funcResult = two 1709enddef 1710 1711def FuncOneArgRetString(arg: string): string 1712 return arg 1713enddef 1714 1715def FuncOneArgRetAny(arg: any): any 1716 return arg 1717enddef 1718 1719def Test_func_type() 1720 var Ref1: func() 1721 s:funcResult = 0 1722 Ref1 = FuncNoArgNoRet 1723 Ref1() 1724 s:funcResult->assert_equal(11) 1725 1726 var Ref2: func 1727 s:funcResult = 0 1728 Ref2 = FuncNoArgNoRet 1729 Ref2() 1730 s:funcResult->assert_equal(11) 1731 1732 s:funcResult = 0 1733 Ref2 = FuncOneArgNoRet 1734 Ref2(12) 1735 s:funcResult->assert_equal(12) 1736 1737 s:funcResult = 0 1738 Ref2 = FuncNoArgRetNumber 1739 Ref2()->assert_equal(1234) 1740 s:funcResult->assert_equal(22) 1741 1742 s:funcResult = 0 1743 Ref2 = FuncOneArgRetNumber 1744 Ref2(13)->assert_equal(13) 1745 s:funcResult->assert_equal(13) 1746enddef 1747 1748def Test_repeat_return_type() 1749 var res = 0 1750 for n in repeat([1], 3) 1751 res += n 1752 endfor 1753 res->assert_equal(3) 1754 1755 res = 0 1756 for n in add([1, 2], 3) 1757 res += n 1758 endfor 1759 res->assert_equal(6) 1760enddef 1761 1762def Test_argv_return_type() 1763 next fileone filetwo 1764 var res = '' 1765 for name in argv() 1766 res ..= name 1767 endfor 1768 res->assert_equal('fileonefiletwo') 1769enddef 1770 1771def Test_func_type_part() 1772 var RefVoid: func: void 1773 RefVoid = FuncNoArgNoRet 1774 RefVoid = FuncOneArgNoRet 1775 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number') 1776 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string') 1777 1778 var RefAny: func(): any 1779 RefAny = FuncNoArgRetNumber 1780 RefAny = FuncNoArgRetString 1781 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()') 1782 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)') 1783 1784 var RefAnyNoArgs: func: any = RefAny 1785 1786 var RefNr: func: number 1787 RefNr = FuncNoArgRetNumber 1788 RefNr = FuncOneArgRetNumber 1789 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()') 1790 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string') 1791 1792 var RefStr: func: string 1793 RefStr = FuncNoArgRetString 1794 RefStr = FuncOneArgRetString 1795 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()') 1796 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number') 1797enddef 1798 1799def Test_func_type_fails() 1800 CheckDefFailure(['var ref1: func()'], 'E704:') 1801 1802 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number') 1803 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)') 1804 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number') 1805 CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)') 1806 CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)') 1807 CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)') 1808 1809 CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:') 1810 CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:') 1811 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:') 1812 CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:') 1813enddef 1814 1815def Test_func_return_type() 1816 var nr: number 1817 nr = FuncNoArgRetNumber() 1818 nr->assert_equal(1234) 1819 1820 nr = FuncOneArgRetAny(122) 1821 nr->assert_equal(122) 1822 1823 var str: string 1824 str = FuncOneArgRetAny('yes') 1825 str->assert_equal('yes') 1826 1827 CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number') 1828enddef 1829 1830def Test_func_common_type() 1831 def FuncOne(n: number): number 1832 return n 1833 enddef 1834 def FuncTwo(s: string): number 1835 return len(s) 1836 enddef 1837 def FuncThree(n: number, s: string): number 1838 return n + len(s) 1839 enddef 1840 var list = [FuncOne, FuncTwo, FuncThree] 1841 assert_equal(8, list[0](8)) 1842 assert_equal(4, list[1]('word')) 1843 assert_equal(7, list[2](3, 'word')) 1844enddef 1845 1846def MultiLine( 1847 arg1: string, 1848 arg2 = 1234, 1849 ...rest: list<string> 1850 ): string 1851 return arg1 .. arg2 .. join(rest, '-') 1852enddef 1853 1854def MultiLineComment( 1855 arg1: string, # comment 1856 arg2 = 1234, # comment 1857 ...rest: list<string> # comment 1858 ): string # comment 1859 return arg1 .. arg2 .. join(rest, '-') 1860enddef 1861 1862def Test_multiline() 1863 MultiLine('text')->assert_equal('text1234') 1864 MultiLine('text', 777)->assert_equal('text777') 1865 MultiLine('text', 777, 'one')->assert_equal('text777one') 1866 MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1867enddef 1868 1869func Test_multiline_not_vim9() 1870 call MultiLine('text')->assert_equal('text1234') 1871 call MultiLine('text', 777)->assert_equal('text777') 1872 call MultiLine('text', 777, 'one')->assert_equal('text777one') 1873 call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1874endfunc 1875 1876 1877" When using CheckScriptFailure() for the below test, E1010 is generated instead 1878" of E1056. 1879func Test_E1056_1059() 1880 let caught_1056 = 0 1881 try 1882 def F(): 1883 return 1 1884 enddef 1885 catch /E1056:/ 1886 let caught_1056 = 1 1887 endtry 1888 eval caught_1056->assert_equal(1) 1889 1890 let caught_1059 = 0 1891 try 1892 def F5(items : list) 1893 echo 'a' 1894 enddef 1895 catch /E1059:/ 1896 let caught_1059 = 1 1897 endtry 1898 eval caught_1059->assert_equal(1) 1899endfunc 1900 1901func DelMe() 1902 echo 'DelMe' 1903endfunc 1904 1905def Test_error_reporting() 1906 # comment lines at the start of the function 1907 var lines =<< trim END 1908 " comment 1909 def Func() 1910 # comment 1911 # comment 1912 invalid 1913 enddef 1914 defcompile 1915 END 1916 writefile(lines, 'Xdef') 1917 try 1918 source Xdef 1919 assert_report('should have failed') 1920 catch /E476:/ 1921 v:exception->assert_match('Invalid command: invalid') 1922 v:throwpoint->assert_match(', line 3$') 1923 endtry 1924 delfunc! g:Func 1925 1926 # comment lines after the start of the function 1927 lines =<< trim END 1928 " comment 1929 def Func() 1930 var x = 1234 1931 # comment 1932 # comment 1933 invalid 1934 enddef 1935 defcompile 1936 END 1937 writefile(lines, 'Xdef') 1938 try 1939 source Xdef 1940 assert_report('should have failed') 1941 catch /E476:/ 1942 v:exception->assert_match('Invalid command: invalid') 1943 v:throwpoint->assert_match(', line 4$') 1944 endtry 1945 delfunc! g:Func 1946 1947 lines =<< trim END 1948 vim9script 1949 def Func() 1950 var db = {foo: 1, bar: 2} 1951 # comment 1952 var x = db.asdf 1953 enddef 1954 defcompile 1955 Func() 1956 END 1957 writefile(lines, 'Xdef') 1958 try 1959 source Xdef 1960 assert_report('should have failed') 1961 catch /E716:/ 1962 v:throwpoint->assert_match('_Func, line 3$') 1963 endtry 1964 delfunc! g:Func 1965 1966 delete('Xdef') 1967enddef 1968 1969def Test_deleted_function() 1970 CheckDefExecFailure([ 1971 'var RefMe: func = function("g:DelMe")', 1972 'delfunc g:DelMe', 1973 'echo RefMe()'], 'E117:') 1974enddef 1975 1976def Test_unknown_function() 1977 CheckDefExecFailure([ 1978 'var Ref: func = function("NotExist")', 1979 'delfunc g:NotExist'], 'E700:') 1980enddef 1981 1982def RefFunc(Ref: func(any): any): string 1983 return Ref('more') 1984enddef 1985 1986def Test_closure_simple() 1987 var local = 'some ' 1988 RefFunc((s) => local .. s)->assert_equal('some more') 1989enddef 1990 1991def MakeRef() 1992 var local = 'some ' 1993 g:Ref = (s) => local .. s 1994enddef 1995 1996def Test_closure_ref_after_return() 1997 MakeRef() 1998 g:Ref('thing')->assert_equal('some thing') 1999 unlet g:Ref 2000enddef 2001 2002def MakeTwoRefs() 2003 var local = ['some'] 2004 g:Extend = (s) => local->add(s) 2005 g:Read = () => local 2006enddef 2007 2008def Test_closure_two_refs() 2009 MakeTwoRefs() 2010 join(g:Read(), ' ')->assert_equal('some') 2011 g:Extend('more') 2012 join(g:Read(), ' ')->assert_equal('some more') 2013 g:Extend('even') 2014 join(g:Read(), ' ')->assert_equal('some more even') 2015 2016 unlet g:Extend 2017 unlet g:Read 2018enddef 2019 2020def ReadRef(Ref: func(): list<string>): string 2021 return join(Ref(), ' ') 2022enddef 2023 2024def ExtendRef(Ref: func(string): list<string>, add: string) 2025 Ref(add) 2026enddef 2027 2028def Test_closure_two_indirect_refs() 2029 MakeTwoRefs() 2030 ReadRef(g:Read)->assert_equal('some') 2031 ExtendRef(g:Extend, 'more') 2032 ReadRef(g:Read)->assert_equal('some more') 2033 ExtendRef(g:Extend, 'even') 2034 ReadRef(g:Read)->assert_equal('some more even') 2035 2036 unlet g:Extend 2037 unlet g:Read 2038enddef 2039 2040def MakeArgRefs(theArg: string) 2041 var local = 'loc_val' 2042 g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s 2043enddef 2044 2045def MakeArgRefsVarargs(theArg: string, ...rest: list<string>) 2046 var local = 'the_loc' 2047 g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest) 2048enddef 2049 2050def Test_closure_using_argument() 2051 MakeArgRefs('arg_val') 2052 g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val') 2053 2054 MakeArgRefsVarargs('arg_val', 'one', 'two') 2055 g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two') 2056 2057 unlet g:UseArg 2058 unlet g:UseVararg 2059 2060 var lines =<< trim END 2061 vim9script 2062 def Test(Fun: func(number): number): list<number> 2063 return map([1, 2, 3], (_, i) => Fun(i)) 2064 enddef 2065 def Inc(nr: number): number 2066 return nr + 2 2067 enddef 2068 assert_equal([3, 4, 5], Test(Inc)) 2069 END 2070 CheckScriptSuccess(lines) 2071enddef 2072 2073def MakeGetAndAppendRefs() 2074 var local = 'a' 2075 2076 def Append(arg: string) 2077 local ..= arg 2078 enddef 2079 g:Append = Append 2080 2081 def Get(): string 2082 return local 2083 enddef 2084 g:Get = Get 2085enddef 2086 2087def Test_closure_append_get() 2088 MakeGetAndAppendRefs() 2089 g:Get()->assert_equal('a') 2090 g:Append('-b') 2091 g:Get()->assert_equal('a-b') 2092 g:Append('-c') 2093 g:Get()->assert_equal('a-b-c') 2094 2095 unlet g:Append 2096 unlet g:Get 2097enddef 2098 2099def Test_nested_closure() 2100 var local = 'text' 2101 def Closure(arg: string): string 2102 return local .. arg 2103 enddef 2104 Closure('!!!')->assert_equal('text!!!') 2105enddef 2106 2107func GetResult(Ref) 2108 return a:Ref('some') 2109endfunc 2110 2111def Test_call_closure_not_compiled() 2112 var text = 'text' 2113 g:Ref = (s) => s .. text 2114 GetResult(g:Ref)->assert_equal('sometext') 2115enddef 2116 2117def Test_double_closure_fails() 2118 var lines =<< trim END 2119 vim9script 2120 def Func() 2121 var name = 0 2122 for i in range(2) 2123 timer_start(0, () => name) 2124 endfor 2125 enddef 2126 Func() 2127 END 2128 CheckScriptSuccess(lines) 2129enddef 2130 2131def Test_nested_closure_used() 2132 var lines =<< trim END 2133 vim9script 2134 def Func() 2135 var x = 'hello' 2136 var Closure = () => x 2137 g:Myclosure = () => Closure() 2138 enddef 2139 Func() 2140 assert_equal('hello', g:Myclosure()) 2141 END 2142 CheckScriptSuccess(lines) 2143enddef 2144 2145def Test_nested_closure_fails() 2146 var lines =<< trim END 2147 vim9script 2148 def FuncA() 2149 FuncB(0) 2150 enddef 2151 def FuncB(n: number): list<string> 2152 return map([0], (_, v) => n) 2153 enddef 2154 FuncA() 2155 END 2156 CheckScriptFailure(lines, 'E1012:') 2157enddef 2158 2159def Test_global_closure() 2160 var lines =<< trim END 2161 vim9script 2162 def ReverseEveryNLines(n: number, line1: number, line2: number) 2163 var mods = 'sil keepj keepp lockm ' 2164 var range = ':' .. line1 .. ',' .. line2 2165 def g:Offset(): number 2166 var offset = (line('.') - line1 + 1) % n 2167 return offset != 0 ? offset : n 2168 enddef 2169 exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()' 2170 enddef 2171 2172 new 2173 repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1) 2174 ReverseEveryNLines(3, 1, 9) 2175 END 2176 CheckScriptSuccess(lines) 2177 var expected = repeat(['ccc', 'bbb', 'aaa'], 3) 2178 assert_equal(expected, getline(1, 9)) 2179 bwipe! 2180enddef 2181 2182def Test_global_closure_called_directly() 2183 var lines =<< trim END 2184 vim9script 2185 def Outer() 2186 var x = 1 2187 def g:Inner() 2188 var y = x 2189 x += 1 2190 assert_equal(1, y) 2191 enddef 2192 g:Inner() 2193 assert_equal(2, x) 2194 enddef 2195 Outer() 2196 END 2197 CheckScriptSuccess(lines) 2198 delfunc g:Inner 2199enddef 2200 2201def Test_failure_in_called_function() 2202 # this was using the frame index as the return value 2203 var lines =<< trim END 2204 vim9script 2205 au TerminalWinOpen * eval [][0] 2206 def PopupTerm(a: any) 2207 # make sure typvals on stack are string 2208 ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join() 2209 FireEvent() 2210 enddef 2211 def FireEvent() 2212 do TerminalWinOpen 2213 enddef 2214 # use try/catch to make eval fail 2215 try 2216 call PopupTerm(0) 2217 catch 2218 endtry 2219 au! TerminalWinOpen 2220 END 2221 CheckScriptSuccess(lines) 2222enddef 2223 2224def Test_nested_lambda() 2225 var lines =<< trim END 2226 vim9script 2227 def Func() 2228 var x = 4 2229 var Lambda1 = () => 7 2230 var Lambda2 = () => [Lambda1(), x] 2231 var res = Lambda2() 2232 assert_equal([7, 4], res) 2233 enddef 2234 Func() 2235 END 2236 CheckScriptSuccess(lines) 2237enddef 2238 2239def Test_double_nested_lambda() 2240 var lines =<< trim END 2241 vim9script 2242 def F(head: string): func(string): func(string): string 2243 return (sep: string): func(string): string => ((tail: string): string => { 2244 return head .. sep .. tail 2245 }) 2246 enddef 2247 assert_equal('hello-there', F('hello')('-')('there')) 2248 END 2249 CheckScriptSuccess(lines) 2250enddef 2251 2252def Test_nested_inline_lambda() 2253 var lines =<< trim END 2254 vim9script 2255 def F(text: string): func(string): func(string): string 2256 return (arg: string): func(string): string => ((sep: string): string => { 2257 return sep .. arg .. text 2258 }) 2259 enddef 2260 assert_equal('--there++', F('++')('there')('--')) 2261 END 2262 CheckScriptSuccess(lines) 2263 2264 lines =<< trim END 2265 vim9script 2266 echo range(4)->mapnew((_, v) => { 2267 return range(v) ->mapnew((_, s) => { 2268 return string(s) 2269 }) 2270 }) 2271 END 2272 CheckScriptSuccess(lines) 2273 2274 lines =<< trim END 2275 vim9script 2276 2277 def s:func() 2278 range(10) 2279 ->mapnew((_, _) => ({ 2280 key: range(10)->mapnew((_, _) => { 2281 return ' ' 2282 }), 2283 })) 2284 enddef 2285 2286 defcomp 2287 END 2288 CheckScriptSuccess(lines) 2289enddef 2290 2291def Shadowed(): list<number> 2292 var FuncList: list<func: number> = [() => 42] 2293 return FuncList->mapnew((_, Shadowed) => Shadowed()) 2294enddef 2295 2296def Test_lambda_arg_shadows_func() 2297 assert_equal([42], Shadowed()) 2298enddef 2299 2300def Line_continuation_in_def(dir: string = ''): string 2301 var path: string = empty(dir) 2302 \ ? 'empty' 2303 \ : 'full' 2304 return path 2305enddef 2306 2307def Test_line_continuation_in_def() 2308 Line_continuation_in_def('.')->assert_equal('full') 2309enddef 2310 2311def Test_script_var_in_lambda() 2312 var lines =<< trim END 2313 vim9script 2314 var script = 'test' 2315 assert_equal(['test'], map(['one'], (_, _) => script)) 2316 END 2317 CheckScriptSuccess(lines) 2318enddef 2319 2320def Line_continuation_in_lambda(): list<string> 2321 var x = range(97, 100) 2322 ->mapnew((_, v) => nr2char(v) 2323 ->toupper()) 2324 ->reverse() 2325 return x 2326enddef 2327 2328def Test_line_continuation_in_lambda() 2329 Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A']) 2330 2331 var lines =<< trim END 2332 vim9script 2333 var res = [{n: 1, m: 2, s: 'xxx'}] 2334 ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s', 2335 v.n, 2336 v.m, 2337 substitute(v.s, '.*', 'yyy', '') 2338 )) 2339 assert_equal(['1:2:yyy'], res) 2340 END 2341 CheckScriptSuccess(lines) 2342enddef 2343 2344def Test_list_lambda() 2345 timer_start(1000, (_) => 0) 2346 var body = execute(timer_info()[0].callback 2347 ->string() 2348 ->substitute("('", ' ', '') 2349 ->substitute("')", '', '') 2350 ->substitute('function\zs', ' ', '')) 2351 assert_match('def <lambda>\d\+(_: any): number\n1 return 0\n enddef', body) 2352enddef 2353 2354def Test_lambda_block_variable() 2355 var lines =<< trim END 2356 vim9script 2357 var flist: list<func> 2358 for i in range(10) 2359 var inloop = i 2360 flist[i] = () => inloop 2361 endfor 2362 END 2363 CheckScriptSuccess(lines) 2364 2365 lines =<< trim END 2366 vim9script 2367 if true 2368 var outloop = 5 2369 var flist: list<func> 2370 for i in range(10) 2371 flist[i] = () => outloop 2372 endfor 2373 endif 2374 END 2375 CheckScriptSuccess(lines) 2376 2377 lines =<< trim END 2378 vim9script 2379 if true 2380 var outloop = 5 2381 endif 2382 var flist: list<func> 2383 for i in range(10) 2384 flist[i] = () => outloop 2385 endfor 2386 END 2387 CheckScriptFailure(lines, 'E1001: Variable not found: outloop', 1) 2388 2389 lines =<< trim END 2390 vim9script 2391 for i in range(10) 2392 var Ref = () => 0 2393 endfor 2394 assert_equal(0, ((i) => 0)(0)) 2395 END 2396 CheckScriptSuccess(lines) 2397enddef 2398 2399def Test_legacy_lambda() 2400 legacy echo {x -> 'hello ' .. x}('foo') 2401 2402 var lines =<< trim END 2403 echo {x -> 'hello ' .. x}('foo') 2404 END 2405 CheckDefAndScriptFailure(lines, 'E720:') 2406 2407 lines =<< trim END 2408 vim9script 2409 def Func() 2410 echo (() => 'no error')() 2411 enddef 2412 legacy call s:Func() 2413 END 2414 CheckScriptSuccess(lines) 2415enddef 2416 2417def Test_legacy() 2418 var lines =<< trim END 2419 vim9script 2420 func g:LegacyFunction() 2421 let g:legacyvar = 1 2422 endfunc 2423 def Testit() 2424 legacy call g:LegacyFunction() 2425 enddef 2426 Testit() 2427 assert_equal(1, g:legacyvar) 2428 unlet g:legacyvar 2429 delfunc g:LegacyFunction 2430 END 2431 CheckScriptSuccess(lines) 2432enddef 2433 2434def Test_legacy_errors() 2435 for cmd in ['if', 'elseif', 'else', 'endif', 2436 'for', 'endfor', 'continue', 'break', 2437 'while', 'endwhile', 2438 'try', 'catch', 'finally', 'endtry'] 2439 CheckDefFailure(['legacy ' .. cmd .. ' expr'], 'E1189:') 2440 endfor 2441enddef 2442 2443def DoFilterThis(a: string): list<string> 2444 # closure nested inside another closure using argument 2445 var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0) 2446 return ['x', 'y', 'a', 'x2', 'c']->Filter() 2447enddef 2448 2449def Test_nested_closure_using_argument() 2450 assert_equal(['x', 'x2'], DoFilterThis('x')) 2451enddef 2452 2453def Test_triple_nested_closure() 2454 var what = 'x' 2455 var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0 2456 var Filter = (l) => filter(l, (_, v) => Match(v, what)) 2457 assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter()) 2458enddef 2459 2460func Test_silent_echo() 2461 CheckScreendump 2462 2463 let lines =<< trim END 2464 vim9script 2465 def EchoNothing() 2466 silent echo '' 2467 enddef 2468 defcompile 2469 END 2470 call writefile(lines, 'XTest_silent_echo') 2471 2472 " Check that the balloon shows up after a mouse move 2473 let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6}) 2474 call term_sendkeys(buf, ":abc") 2475 call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {}) 2476 2477 " clean up 2478 call StopVimInTerminal(buf) 2479 call delete('XTest_silent_echo') 2480endfunc 2481 2482def SilentlyError() 2483 execute('silent! invalid') 2484 g:did_it = 'yes' 2485enddef 2486 2487func UserError() 2488 silent! invalid 2489endfunc 2490 2491def SilentlyUserError() 2492 UserError() 2493 g:did_it = 'yes' 2494enddef 2495 2496" This can't be a :def function, because the assert would not be reached. 2497func Test_ignore_silent_error() 2498 let g:did_it = 'no' 2499 call SilentlyError() 2500 call assert_equal('yes', g:did_it) 2501 2502 let g:did_it = 'no' 2503 call SilentlyUserError() 2504 call assert_equal('yes', g:did_it) 2505 2506 unlet g:did_it 2507endfunc 2508 2509def Test_ignore_silent_error_in_filter() 2510 var lines =<< trim END 2511 vim9script 2512 def Filter(winid: number, key: string): bool 2513 if key == 'o' 2514 silent! eval [][0] 2515 return true 2516 endif 2517 return popup_filter_menu(winid, key) 2518 enddef 2519 2520 popup_create('popup', {filter: Filter}) 2521 feedkeys("o\r", 'xnt') 2522 END 2523 CheckScriptSuccess(lines) 2524enddef 2525 2526def Fibonacci(n: number): number 2527 if n < 2 2528 return n 2529 else 2530 return Fibonacci(n - 1) + Fibonacci(n - 2) 2531 endif 2532enddef 2533 2534def Test_recursive_call() 2535 Fibonacci(20)->assert_equal(6765) 2536enddef 2537 2538def TreeWalk(dir: string): list<any> 2539 return readdir(dir)->mapnew((_, val) => 2540 fnamemodify(dir .. '/' .. val, ':p')->isdirectory() 2541 ? {[val]: TreeWalk(dir .. '/' .. val)} 2542 : val 2543 ) 2544enddef 2545 2546def Test_closure_in_map() 2547 mkdir('XclosureDir/tdir', 'p') 2548 writefile(['111'], 'XclosureDir/file1') 2549 writefile(['222'], 'XclosureDir/file2') 2550 writefile(['333'], 'XclosureDir/tdir/file3') 2551 2552 TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}]) 2553 2554 delete('XclosureDir', 'rf') 2555enddef 2556 2557def Test_invalid_function_name() 2558 var lines =<< trim END 2559 vim9script 2560 def s: list<string> 2561 END 2562 CheckScriptFailure(lines, 'E129:') 2563 2564 lines =<< trim END 2565 vim9script 2566 def g: list<string> 2567 END 2568 CheckScriptFailure(lines, 'E129:') 2569 2570 lines =<< trim END 2571 vim9script 2572 def <SID>: list<string> 2573 END 2574 CheckScriptFailure(lines, 'E884:') 2575 2576 lines =<< trim END 2577 vim9script 2578 def F list<string> 2579 END 2580 CheckScriptFailure(lines, 'E488:') 2581enddef 2582 2583def Test_partial_call() 2584 var lines =<< trim END 2585 var Xsetlist: func 2586 Xsetlist = function('setloclist', [0]) 2587 Xsetlist([], ' ', {title: 'test'}) 2588 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2589 2590 Xsetlist = function('setloclist', [0, [], ' ']) 2591 Xsetlist({title: 'test'}) 2592 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2593 2594 Xsetlist = function('setqflist') 2595 Xsetlist([], ' ', {title: 'test'}) 2596 getqflist({title: 1})->assert_equal({title: 'test'}) 2597 2598 Xsetlist = function('setqflist', [[], ' ']) 2599 Xsetlist({title: 'test'}) 2600 getqflist({title: 1})->assert_equal({title: 'test'}) 2601 2602 var Len: func: number = function('len', ['word']) 2603 assert_equal(4, Len()) 2604 2605 var RepeatFunc = function('repeat', ['o']) 2606 assert_equal('ooooo', RepeatFunc(5)) 2607 END 2608 CheckDefAndScriptSuccess(lines) 2609enddef 2610 2611def Test_cmd_modifier() 2612 tab echo '0' 2613 CheckDefFailure(['5tab echo 3'], 'E16:') 2614enddef 2615 2616def Test_restore_modifiers() 2617 # check that when compiling a :def function command modifiers are not messed 2618 # up. 2619 var lines =<< trim END 2620 vim9script 2621 set eventignore= 2622 autocmd QuickFixCmdPost * copen 2623 def AutocmdsDisabled() 2624 eval 1 + 2 2625 enddef 2626 func Func() 2627 noautocmd call s:AutocmdsDisabled() 2628 let g:ei_after = &eventignore 2629 endfunc 2630 Func() 2631 END 2632 CheckScriptSuccess(lines) 2633 g:ei_after->assert_equal('') 2634enddef 2635 2636def StackTop() 2637 eval 1 + 2 2638 eval 2 + 3 2639 # call not on fourth line 2640 StackBot() 2641enddef 2642 2643def StackBot() 2644 # throw an error 2645 eval [][0] 2646enddef 2647 2648def Test_callstack_def() 2649 try 2650 StackTop() 2651 catch 2652 v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2') 2653 endtry 2654enddef 2655 2656" Re-using spot for variable used in block 2657def Test_block_scoped_var() 2658 var lines =<< trim END 2659 vim9script 2660 def Func() 2661 var x = ['a', 'b', 'c'] 2662 if 1 2663 var y = 'x' 2664 map(x, (_, _) => y) 2665 endif 2666 var z = x 2667 assert_equal(['x', 'x', 'x'], z) 2668 enddef 2669 Func() 2670 END 2671 CheckScriptSuccess(lines) 2672enddef 2673 2674def Test_reset_did_emsg() 2675 var lines =<< trim END 2676 @s = 'blah' 2677 au BufWinLeave * # 2678 def Func() 2679 var winid = popup_create('popup', {}) 2680 exe '*s' 2681 popup_close(winid) 2682 enddef 2683 Func() 2684 END 2685 CheckScriptFailure(lines, 'E492:', 8) 2686 delfunc! g:Func 2687enddef 2688 2689def Test_did_emsg_reset() 2690 # executing an autocommand resets did_emsg, this should not result in a 2691 # builtin function considered failing 2692 var lines =<< trim END 2693 vim9script 2694 au BufWinLeave * # 2695 def Func() 2696 popup_menu('', {callback: (a, b) => popup_create('', {})->popup_close()}) 2697 eval [][0] 2698 enddef 2699 nno <F3> <cmd>call <sid>Func()<cr> 2700 feedkeys("\<F3>\e", 'xt') 2701 END 2702 writefile(lines, 'XemsgReset') 2703 assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2) 2704 delete('XemsgReset') 2705 nunmap <F3> 2706 au! BufWinLeave 2707enddef 2708 2709def Test_abort_with_silent_call() 2710 var lines =<< trim END 2711 vim9script 2712 g:result = 'none' 2713 def Func() 2714 g:result += 3 2715 g:result = 'yes' 2716 enddef 2717 # error is silenced, but function aborts on error 2718 silent! Func() 2719 assert_equal('none', g:result) 2720 unlet g:result 2721 END 2722 CheckScriptSuccess(lines) 2723enddef 2724 2725def Test_continues_with_silent_error() 2726 var lines =<< trim END 2727 vim9script 2728 g:result = 'none' 2729 def Func() 2730 silent! g:result += 3 2731 g:result = 'yes' 2732 enddef 2733 # error is silenced, function does not abort 2734 Func() 2735 assert_equal('yes', g:result) 2736 unlet g:result 2737 END 2738 CheckScriptSuccess(lines) 2739enddef 2740 2741def Test_abort_even_with_silent() 2742 var lines =<< trim END 2743 vim9script 2744 g:result = 'none' 2745 def Func() 2746 eval {-> ''}() .. '' .. {}['X'] 2747 g:result = 'yes' 2748 enddef 2749 silent! Func() 2750 assert_equal('none', g:result) 2751 unlet g:result 2752 END 2753 CheckScriptSuccess(lines) 2754enddef 2755 2756def Test_cmdmod_silent_restored() 2757 var lines =<< trim END 2758 vim9script 2759 def Func() 2760 g:result = 'none' 2761 silent! g:result += 3 2762 g:result = 'none' 2763 g:result += 3 2764 enddef 2765 Func() 2766 END 2767 # can't use CheckScriptFailure, it ignores the :silent! 2768 var fname = 'Xdefsilent' 2769 writefile(lines, fname) 2770 var caught = 'no' 2771 try 2772 exe 'source ' .. fname 2773 catch /E1030:/ 2774 caught = 'yes' 2775 assert_match('Func, line 4', v:throwpoint) 2776 endtry 2777 assert_equal('yes', caught) 2778 delete(fname) 2779enddef 2780 2781def Test_cmdmod_silent_nested() 2782 var lines =<< trim END 2783 vim9script 2784 var result = '' 2785 2786 def Error() 2787 result ..= 'Eb' 2788 eval [][0] 2789 result ..= 'Ea' 2790 enddef 2791 2792 def Crash() 2793 result ..= 'Cb' 2794 sil! Error() 2795 result ..= 'Ca' 2796 enddef 2797 2798 Crash() 2799 assert_equal('CbEbEaCa', result) 2800 END 2801 CheckScriptSuccess(lines) 2802enddef 2803 2804def Test_dict_member_with_silent() 2805 var lines =<< trim END 2806 vim9script 2807 g:result = 'none' 2808 var d: dict<any> 2809 def Func() 2810 try 2811 g:result = map([], (_, v) => ({}[v]))->join() .. d[''] 2812 catch 2813 endtry 2814 enddef 2815 silent! Func() 2816 assert_equal('0', g:result) 2817 unlet g:result 2818 END 2819 CheckScriptSuccess(lines) 2820enddef 2821 2822def Test_skip_cmds_with_silent() 2823 var lines =<< trim END 2824 vim9script 2825 2826 def Func(b: bool) 2827 Crash() 2828 enddef 2829 2830 def Crash() 2831 sil! :/not found/d _ 2832 sil! :/not found/put _ 2833 enddef 2834 2835 Func(true) 2836 END 2837 CheckScriptSuccess(lines) 2838enddef 2839 2840def Test_opfunc() 2841 nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@ 2842 def g:Opfunc(_: any): string 2843 setline(1, 'ASDF') 2844 return '' 2845 enddef 2846 new 2847 setline(1, 'asdf') 2848 feedkeys("\<F3>$", 'x') 2849 assert_equal('ASDF', getline(1)) 2850 2851 bwipe! 2852 nunmap <F3> 2853enddef 2854 2855" this was crashing on exit 2856def Test_nested_lambda_in_closure() 2857 var lines =<< trim END 2858 vim9script 2859 command WriteDone writefile(['Done'], 'XnestedDone') 2860 def Outer() 2861 def g:Inner() 2862 echo map([1, 2, 3], {_, v -> v + 1}) 2863 enddef 2864 g:Inner() 2865 enddef 2866 defcompile 2867 # not reached 2868 END 2869 if !RunVim([], lines, '--clean -c WriteDone -c quit') 2870 return 2871 endif 2872 assert_equal(['Done'], readfile('XnestedDone')) 2873 delete('XnestedDone') 2874enddef 2875 2876def Test_check_func_arg_types() 2877 var lines =<< trim END 2878 vim9script 2879 def F1(x: string): string 2880 return x 2881 enddef 2882 2883 def F2(x: number): number 2884 return x + 1 2885 enddef 2886 2887 def G(g: func): dict<func> 2888 return {f: g} 2889 enddef 2890 2891 def H(d: dict<func>): string 2892 return d.f('a') 2893 enddef 2894 END 2895 2896 CheckScriptSuccess(lines + ['echo H(G(F1))']) 2897 CheckScriptFailure(lines + ['echo H(G(F2))'], 'E1013:') 2898enddef 2899 2900def Test_compile_error() 2901 var lines =<< trim END 2902 def g:Broken() 2903 echo 'a' + {} 2904 enddef 2905 call g:Broken() 2906 END 2907 # First call: compilation error 2908 CheckScriptFailure(lines, 'E1051: Wrong argument type for +') 2909 2910 # Second call won't try compiling again 2911 assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken') 2912 delfunc g:Broken 2913 2914 # No error when compiling with :silent! 2915 lines =<< trim END 2916 def g:Broken() 2917 echo 'a' + [] 2918 enddef 2919 silent! defcompile 2920 END 2921 CheckScriptSuccess(lines) 2922 2923 # Calling the function won't try compiling again 2924 assert_fails('call g:Broken()', 'E1091: Function is not compiled: Broken') 2925 delfunc g:Broken 2926enddef 2927 2928def Test_ignored_argument() 2929 var lines =<< trim END 2930 vim9script 2931 def Ignore(_, _): string 2932 return 'yes' 2933 enddef 2934 assert_equal('yes', Ignore(1, 2)) 2935 2936 func Ok(_) 2937 return a:_ 2938 endfunc 2939 assert_equal('ok', Ok('ok')) 2940 2941 func Oktoo() 2942 let _ = 'too' 2943 return _ 2944 endfunc 2945 assert_equal('too', Oktoo()) 2946 2947 assert_equal([[1], [2], [3]], range(3)->mapnew((_, v) => [v]->map((_, w) => w + 1))) 2948 END 2949 CheckScriptSuccess(lines) 2950 2951 lines =<< trim END 2952 def Ignore(_: string): string 2953 return _ 2954 enddef 2955 defcompile 2956 END 2957 CheckScriptFailure(lines, 'E1181:', 1) 2958 2959 lines =<< trim END 2960 var _ = 1 2961 END 2962 CheckDefAndScriptFailure(lines, 'E1181:', 1) 2963 2964 lines =<< trim END 2965 var x = _ 2966 END 2967 CheckDefAndScriptFailure(lines, 'E1181:', 1) 2968enddef 2969 2970def Test_too_many_arguments() 2971 var lines =<< trim END 2972 echo [0, 1, 2]->map(() => 123) 2973 END 2974 CheckDefExecAndScriptFailure(lines, 'E1106: 2 arguments too many', 1) 2975 2976 lines =<< trim END 2977 echo [0, 1, 2]->map((_) => 123) 2978 END 2979 CheckDefExecAndScriptFailure(lines, 'E1106: One argument too many', 1) 2980enddef 2981 2982def Test_closing_brace_at_start_of_line() 2983 var lines =<< trim END 2984 def Func() 2985 enddef 2986 Func( 2987 ) 2988 END 2989 call CheckDefAndScriptSuccess(lines) 2990enddef 2991 2992if has('python3') 2993 def Test_python3_heredoc() 2994 py3 << trim EOF 2995 import vim 2996 vim.vars['didit'] = 'yes' 2997 EOF 2998 assert_equal('yes', g:didit) 2999 3000 python3 << trim EOF 3001 import vim 3002 vim.vars['didit'] = 'again' 3003 EOF 3004 assert_equal('again', g:didit) 3005 enddef 3006endif 3007 3008" This messes up syntax highlight, keep near the end. 3009if has('lua') 3010 def Test_lua_heredoc() 3011 g:d = {} 3012 lua << trim EOF 3013 x = vim.eval('g:d') 3014 x['key'] = 'val' 3015 EOF 3016 assert_equal('val', g:d.key) 3017 enddef 3018endif 3019 3020 3021" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 3022