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() 21endfunc 22 23def TestCompilingError() 24 var lines =<< trim END 25 vim9script 26 def Fails() 27 echo nothing 28 enddef 29 defcompile 30 END 31 call writefile(lines, 'XTest_compile_error') 32 var buf = RunVimInTerminal('-S XTest_compile_error', 33 {rows: 10, wait_for_ruler: 0}) 34 var text = '' 35 for loop in range(100) 36 text = '' 37 for i in range(1, 9) 38 text ..= term_getline(buf, i) 39 endfor 40 if text =~ 'Variable not found: nothing' 41 break 42 endif 43 sleep 20m 44 endfor 45 assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', text) 46 47 # clean up 48 call StopVimInTerminal(buf) 49 call delete('XTest_compile_error') 50enddef 51 52def CallRecursive(n: number): number 53 return CallRecursive(n + 1) 54enddef 55 56def CallMapRecursive(l: list<number>): number 57 return map(l, (_, v) => CallMapRecursive([v]))[0] 58enddef 59 60def Test_funcdepth_error() 61 set maxfuncdepth=10 62 63 var caught = false 64 try 65 CallRecursive(1) 66 catch /E132:/ 67 caught = true 68 endtry 69 assert_true(caught) 70 71 caught = false 72 try 73 CallMapRecursive([1]) 74 catch /E132:/ 75 caught = true 76 endtry 77 assert_true(caught) 78 79 set maxfuncdepth& 80enddef 81 82def Test_endfunc_enddef() 83 var lines =<< trim END 84 def Test() 85 echo 'test' 86 endfunc 87 enddef 88 END 89 CheckScriptFailure(lines, 'E1151:', 3) 90 91 lines =<< trim END 92 def Test() 93 func Nested() 94 echo 'test' 95 enddef 96 enddef 97 END 98 CheckScriptFailure(lines, 'E1152:', 4) 99enddef 100 101def Test_missing_endfunc_enddef() 102 var lines =<< trim END 103 vim9script 104 def Test() 105 echo 'test' 106 endef 107 END 108 CheckScriptFailure(lines, 'E1057:', 2) 109 110 lines =<< trim END 111 vim9script 112 func Some() 113 echo 'test' 114 enfffunc 115 END 116 CheckScriptFailure(lines, 'E126:', 2) 117enddef 118 119def Test_white_space_before_paren() 120 var lines =<< trim END 121 vim9script 122 def Test () 123 echo 'test' 124 enddef 125 END 126 CheckScriptFailure(lines, 'E1068:', 2) 127 128 lines =<< trim END 129 vim9script 130 func Test () 131 echo 'test' 132 endfunc 133 END 134 CheckScriptFailure(lines, 'E1068:', 2) 135 136 lines =<< trim END 137 def Test () 138 echo 'test' 139 enddef 140 END 141 CheckScriptFailure(lines, 'E1068:', 1) 142 143 lines =<< trim END 144 func Test () 145 echo 'test' 146 endfunc 147 END 148 CheckScriptSuccess(lines) 149enddef 150 151def Test_enddef_dict_key() 152 var d = { 153 enddef: 'x', 154 endfunc: 'y', 155 } 156 assert_equal({enddef: 'x', endfunc: 'y'}, d) 157enddef 158 159def ReturnString(): string 160 return 'string' 161enddef 162 163def ReturnNumber(): number 164 return 123 165enddef 166 167let g:notNumber = 'string' 168 169def ReturnGlobal(): number 170 return g:notNumber 171enddef 172 173def Test_return_something() 174 ReturnString()->assert_equal('string') 175 ReturnNumber()->assert_equal(123) 176 assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal') 177enddef 178 179def Test_check_argument_type() 180 var lines =<< trim END 181 vim9script 182 def Val(a: number, b: number): number 183 return 0 184 enddef 185 def Func() 186 var x: any = true 187 Val(0, x) 188 enddef 189 disass Func 190 Func() 191 END 192 CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2) 193enddef 194 195def Test_missing_return() 196 CheckDefFailure(['def Missing(): number', 197 ' if g:cond', 198 ' echo "no return"', 199 ' else', 200 ' return 0', 201 ' endif' 202 'enddef'], 'E1027:') 203 CheckDefFailure(['def Missing(): number', 204 ' if g:cond', 205 ' return 1', 206 ' else', 207 ' echo "no return"', 208 ' endif' 209 'enddef'], 'E1027:') 210 CheckDefFailure(['def Missing(): number', 211 ' if g:cond', 212 ' return 1', 213 ' else', 214 ' return 2', 215 ' endif' 216 ' return 3' 217 'enddef'], 'E1095:') 218enddef 219 220def Test_return_bool() 221 var lines =<< trim END 222 vim9script 223 def MenuFilter(id: number, key: string): bool 224 return popup_filter_menu(id, key) 225 enddef 226 def YesnoFilter(id: number, key: string): bool 227 return popup_filter_yesno(id, key) 228 enddef 229 defcompile 230 END 231 CheckScriptSuccess(lines) 232enddef 233 234let s:nothing = 0 235def ReturnNothing() 236 s:nothing = 1 237 if true 238 return 239 endif 240 s:nothing = 2 241enddef 242 243def Test_return_nothing() 244 ReturnNothing() 245 s:nothing->assert_equal(1) 246enddef 247 248def Test_return_invalid() 249 var lines =<< trim END 250 vim9script 251 def Func(): invalid 252 return xxx 253 enddef 254 defcompile 255 END 256 CheckScriptFailure(lines, 'E1010:', 2) 257 258 lines =<< trim END 259 vim9script 260 def Test(Fun: func(number): number): list<number> 261 return map([1, 2, 3], (_, i) => Fun(i)) 262 enddef 263 defcompile 264 def Inc(nr: number): nr 265 return nr + 2 266 enddef 267 echo Test(Inc) 268 END 269 # doing this twice was leaking memory 270 CheckScriptFailure(lines, 'E1010:') 271 CheckScriptFailure(lines, 'E1010:') 272enddef 273 274func Increment() 275 let g:counter += 1 276endfunc 277 278def Test_call_ufunc_count() 279 g:counter = 1 280 Increment() 281 Increment() 282 Increment() 283 # works with and without :call 284 g:counter->assert_equal(4) 285 eval g:counter->assert_equal(4) 286 unlet g:counter 287enddef 288 289def MyVarargs(arg: string, ...rest: list<string>): string 290 var res = arg 291 for s in rest 292 res ..= ',' .. s 293 endfor 294 return res 295enddef 296 297def Test_call_varargs() 298 MyVarargs('one')->assert_equal('one') 299 MyVarargs('one', 'two')->assert_equal('one,two') 300 MyVarargs('one', 'two', 'three')->assert_equal('one,two,three') 301enddef 302 303def MyDefaultArgs(name = 'string'): string 304 return name 305enddef 306 307def MyDefaultSecond(name: string, second: bool = true): string 308 return second ? name : 'none' 309enddef 310 311def Test_call_default_args() 312 MyDefaultArgs()->assert_equal('string') 313 MyDefaultArgs('one')->assert_equal('one') 314 assert_fails('MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args') 315 316 MyDefaultSecond('test')->assert_equal('test') 317 MyDefaultSecond('test', true)->assert_equal('test') 318 MyDefaultSecond('test', false)->assert_equal('none') 319 320 CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:') 321 delfunc g:Func 322 CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: Argument 1: type mismatch, expected number but got string') 323 delfunc g:Func 324enddef 325 326def FuncWithComment( # comment 327 a: number, #comment 328 b: bool, # comment 329 c: string) #comment 330 assert_equal(4, a) 331 assert_equal(true, b) 332 assert_equal('yes', c) 333enddef 334 335def Test_func_with_comments() 336 FuncWithComment(4, true, 'yes') 337 338 var lines =<< trim END 339 def Func(# comment 340 arg: string) 341 enddef 342 END 343 CheckScriptFailure(lines, 'E125:', 1) 344 345 lines =<< trim END 346 def Func( 347 arg: string# comment 348 ) 349 enddef 350 END 351 CheckScriptFailure(lines, 'E475:', 2) 352 353 lines =<< trim END 354 def Func( 355 arg: string 356 )# comment 357 enddef 358 END 359 CheckScriptFailure(lines, 'E488:', 3) 360enddef 361 362def Test_nested_function() 363 def Nested(arg: string): string 364 return 'nested ' .. arg 365 enddef 366 Nested('function')->assert_equal('nested function') 367 368 CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') 369 CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') 370 371 CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') 372 CheckDefFailure(['def s:Nested()', 'enddef'], 'E1075:') 373 CheckDefFailure(['def b:Nested()', 'enddef'], 'E1075:') 374 375 var lines =<< trim END 376 def Outer() 377 def Inner() 378 # comment 379 enddef 380 def Inner() 381 enddef 382 enddef 383 END 384 CheckDefFailure(lines, 'E1073:') 385 386 lines =<< trim END 387 def Outer() 388 def Inner() 389 # comment 390 enddef 391 def! Inner() 392 enddef 393 enddef 394 END 395 CheckDefFailure(lines, 'E1117:') 396 397 # nested function inside conditional 398 # TODO: should it work when "thecount" is inside the "if"? 399 lines =<< trim END 400 vim9script 401 var thecount = 0 402 if true 403 def Test(): number 404 def TheFunc(): number 405 thecount += 1 406 return thecount 407 enddef 408 return TheFunc() 409 enddef 410 endif 411 defcompile 412 assert_equal(1, Test()) 413 assert_equal(2, Test()) 414 END 415 CheckScriptSuccess(lines) 416enddef 417 418def Test_not_nested_function() 419 echo printf('%d', 420 function('len')('xxx')) 421enddef 422 423func Test_call_default_args_from_func() 424 call MyDefaultArgs()->assert_equal('string') 425 call MyDefaultArgs('one')->assert_equal('one') 426 call assert_fails('call MyDefaultArgs("one", "two")', 'E118:', '', 3, 'Test_call_default_args_from_func') 427endfunc 428 429def Test_nested_global_function() 430 var lines =<< trim END 431 vim9script 432 def Outer() 433 def g:Inner(): string 434 return 'inner' 435 enddef 436 enddef 437 defcompile 438 Outer() 439 g:Inner()->assert_equal('inner') 440 delfunc g:Inner 441 Outer() 442 g:Inner()->assert_equal('inner') 443 delfunc g:Inner 444 Outer() 445 g:Inner()->assert_equal('inner') 446 delfunc g:Inner 447 END 448 CheckScriptSuccess(lines) 449 450 lines =<< trim END 451 vim9script 452 def Outer() 453 def g:Inner(): string 454 return 'inner' 455 enddef 456 enddef 457 defcompile 458 Outer() 459 Outer() 460 END 461 CheckScriptFailure(lines, "E122:") 462 delfunc g:Inner 463 464 lines =<< trim END 465 vim9script 466 def Outer() 467 def g:Inner() 468 echo map([1, 2, 3], (_, v) => v + 1) 469 enddef 470 g:Inner() 471 enddef 472 Outer() 473 END 474 CheckScriptSuccess(lines) 475 delfunc g:Inner 476 477 lines =<< trim END 478 vim9script 479 def Func() 480 echo 'script' 481 enddef 482 def Outer() 483 def Func() 484 echo 'inner' 485 enddef 486 enddef 487 defcompile 488 END 489 CheckScriptFailure(lines, "E1073:") 490enddef 491 492def DefListAll() 493 def 494enddef 495 496def DefListOne() 497 def DefListOne 498enddef 499 500def DefListMatches() 501 def /DefList 502enddef 503 504def Test_nested_def_list() 505 var funcs = split(execute('call DefListAll()'), "\n") 506 assert_true(len(funcs) > 10) 507 assert_true(funcs->index('def DefListAll()') >= 0) 508 509 funcs = split(execute('call DefListOne()'), "\n") 510 assert_equal([' def DefListOne()', '1 def DefListOne', ' enddef'], funcs) 511 512 funcs = split(execute('call DefListMatches()'), "\n") 513 assert_true(len(funcs) >= 3) 514 assert_true(funcs->index('def DefListAll()') >= 0) 515 assert_true(funcs->index('def DefListOne()') >= 0) 516 assert_true(funcs->index('def DefListMatches()') >= 0) 517 518 var lines =<< trim END 519 vim9script 520 def Func() 521 def +Func+ 522 enddef 523 defcompile 524 END 525 CheckScriptFailure(lines, 'E476:', 1) 526enddef 527 528def Test_global_local_function() 529 var lines =<< trim END 530 vim9script 531 def g:Func(): string 532 return 'global' 533 enddef 534 def Func(): string 535 return 'local' 536 enddef 537 g:Func()->assert_equal('global') 538 Func()->assert_equal('local') 539 delfunc g:Func 540 END 541 CheckScriptSuccess(lines) 542 543 lines =<< trim END 544 vim9script 545 def g:Funcy() 546 echo 'funcy' 547 enddef 548 s:Funcy() 549 END 550 CheckScriptFailure(lines, 'E117:') 551enddef 552 553def Test_local_function_shadows_global() 554 var lines =<< trim END 555 vim9script 556 def g:Gfunc(): string 557 return 'global' 558 enddef 559 def AnotherFunc(): number 560 var Gfunc = function('len') 561 return Gfunc('testing') 562 enddef 563 g:Gfunc()->assert_equal('global') 564 AnotherFunc()->assert_equal(7) 565 delfunc g:Gfunc 566 END 567 CheckScriptSuccess(lines) 568 569 lines =<< trim END 570 vim9script 571 def g:Func(): string 572 return 'global' 573 enddef 574 def AnotherFunc() 575 g:Func = function('len') 576 enddef 577 AnotherFunc() 578 END 579 CheckScriptFailure(lines, 'E705:') 580 delfunc g:Func 581enddef 582 583func TakesOneArg(arg) 584 echo a:arg 585endfunc 586 587def Test_call_wrong_args() 588 CheckDefFailure(['TakesOneArg()'], 'E119:') 589 CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') 590 CheckDefFailure(['bufnr(xxx)'], 'E1001:') 591 CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:') 592 593 var lines =<< trim END 594 vim9script 595 def Func(s: string) 596 echo s 597 enddef 598 Func([]) 599 END 600 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got list<unknown>', 5) 601 602 lines =<< trim END 603 vim9script 604 def FuncOne(nr: number) 605 echo nr 606 enddef 607 def FuncTwo() 608 FuncOne() 609 enddef 610 defcompile 611 END 612 writefile(lines, 'Xscript') 613 var didCatch = false 614 try 615 source Xscript 616 catch 617 assert_match('E119: Not enough arguments for function: <SNR>\d\+_FuncOne', v:exception) 618 assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint) 619 didCatch = true 620 endtry 621 assert_true(didCatch) 622 623 lines =<< trim END 624 vim9script 625 def FuncOne(nr: number) 626 echo nr 627 enddef 628 def FuncTwo() 629 FuncOne(1, 2) 630 enddef 631 defcompile 632 END 633 writefile(lines, 'Xscript') 634 didCatch = false 635 try 636 source Xscript 637 catch 638 assert_match('E118: Too many arguments for function: <SNR>\d\+_FuncOne', v:exception) 639 assert_match('Xscript\[8\]..function <SNR>\d\+_FuncTwo, line 1', v:throwpoint) 640 didCatch = true 641 endtry 642 assert_true(didCatch) 643 644 delete('Xscript') 645enddef 646 647def Test_call_funcref_wrong_args() 648 var head =<< trim END 649 vim9script 650 def Func3(a1: string, a2: number, a3: list<number>) 651 echo a1 .. a2 .. a3[0] 652 enddef 653 def Testme() 654 var funcMap: dict<func> = {func: Func3} 655 END 656 var tail =<< trim END 657 enddef 658 Testme() 659 END 660 CheckScriptSuccess(head + ["funcMap['func']('str', 123, [1, 2, 3])"] + tail) 661 662 CheckScriptFailure(head + ["funcMap['func']('str', 123)"] + tail, 'E119:') 663 CheckScriptFailure(head + ["funcMap['func']('str', 123, [1], 4)"] + tail, 'E118:') 664 665 var lines =<< trim END 666 vim9script 667 var Ref: func(number): any 668 Ref = (j) => !j 669 echo Ref(false) 670 END 671 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4) 672 673 lines =<< trim END 674 vim9script 675 var Ref: func(number): any 676 Ref = (j) => !j 677 call Ref(false) 678 END 679 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected number but got bool', 4) 680enddef 681 682def Test_call_lambda_args() 683 CheckDefFailure(['echo ((i) => 0)()'], 684 'E119: Not enough arguments for function: ((i) => 0)()') 685 686 var lines =<< trim END 687 var Ref = (x: number, y: number) => x + y 688 echo Ref(1, 'x') 689 END 690 CheckDefFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got string') 691 692 lines =<< trim END 693 var Ref: func(job, string, number) 694 Ref = (x, y) => 0 695 END 696 CheckDefAndScriptFailure(lines, 'E1012:') 697 698 lines =<< trim END 699 var Ref: func(job, string) 700 Ref = (x, y, z) => 0 701 END 702 CheckDefAndScriptFailure(lines, 'E1012:') 703enddef 704 705def Test_lambda_return_type() 706 var lines =<< trim END 707 var Ref = (): => 123 708 END 709 CheckDefAndScriptFailure(lines, 'E1157:', 1) 710enddef 711 712def Test_lambda_uses_assigned_var() 713 CheckDefSuccess([ 714 'var x: any = "aaa"' 715 'x = filter(["bbb"], (_, v) => v =~ x)']) 716enddef 717 718" Default arg and varargs 719def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string 720 var res = one .. ',' .. two 721 for s in rest 722 res ..= ',' .. s 723 endfor 724 return res 725enddef 726 727def Test_call_def_varargs() 728 assert_fails('MyDefVarargs()', 'E119:', '', 1, 'Test_call_def_varargs') 729 MyDefVarargs('one')->assert_equal('one,foo') 730 MyDefVarargs('one', 'two')->assert_equal('one,two') 731 MyDefVarargs('one', 'two', 'three')->assert_equal('one,two,three') 732 CheckDefFailure(['MyDefVarargs("one", 22)'], 733 'E1013: Argument 2: type mismatch, expected string but got number') 734 CheckDefFailure(['MyDefVarargs("one", "two", 123)'], 735 'E1013: Argument 3: type mismatch, expected string but got number') 736 737 var lines =<< trim END 738 vim9script 739 def Func(...l: list<string>) 740 echo l 741 enddef 742 Func('a', 'b', 'c') 743 END 744 CheckScriptSuccess(lines) 745 746 lines =<< trim END 747 vim9script 748 def Func(...l: list<string>) 749 echo l 750 enddef 751 Func() 752 END 753 CheckScriptSuccess(lines) 754 755 lines =<< trim END 756 vim9script 757 def Func(...l: any) 758 echo l 759 enddef 760 Func(0) 761 END 762 CheckScriptSuccess(lines) 763 764 lines =<< trim END 765 vim9script 766 def Func(..._l: list<string>) 767 echo _l 768 enddef 769 Func('a', 'b', 'c') 770 END 771 CheckScriptSuccess(lines) 772 773 lines =<< trim END 774 vim9script 775 def Func(...l: list<string>) 776 echo l 777 enddef 778 Func(1, 2, 3) 779 END 780 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch') 781 782 lines =<< trim END 783 vim9script 784 def Func(...l: list<string>) 785 echo l 786 enddef 787 Func('a', 9) 788 END 789 CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch') 790 791 lines =<< trim END 792 vim9script 793 def Func(...l: list<string>) 794 echo l 795 enddef 796 Func(1, 'a') 797 END 798 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch') 799 800 lines =<< trim END 801 vim9script 802 def Func( # some comment 803 ...l = [] 804 ) 805 echo l 806 enddef 807 END 808 CheckScriptFailure(lines, 'E1160:') 809enddef 810 811let s:value = '' 812 813def FuncOneDefArg(opt = 'text') 814 s:value = opt 815enddef 816 817def FuncTwoDefArg(nr = 123, opt = 'text'): string 818 return nr .. opt 819enddef 820 821def FuncVarargs(...arg: list<string>): string 822 return join(arg, ',') 823enddef 824 825def Test_func_type_varargs() 826 var RefDefArg: func(?string) 827 RefDefArg = FuncOneDefArg 828 RefDefArg() 829 s:value->assert_equal('text') 830 RefDefArg('some') 831 s:value->assert_equal('some') 832 833 var RefDef2Arg: func(?number, ?string): string 834 RefDef2Arg = FuncTwoDefArg 835 RefDef2Arg()->assert_equal('123text') 836 RefDef2Arg(99)->assert_equal('99text') 837 RefDef2Arg(77, 'some')->assert_equal('77some') 838 839 CheckDefFailure(['var RefWrong: func(string?)'], 'E1010:') 840 CheckDefFailure(['var RefWrong: func(?string, string)'], 'E1007:') 841 842 var RefVarargs: func(...list<string>): string 843 RefVarargs = FuncVarargs 844 RefVarargs()->assert_equal('') 845 RefVarargs('one')->assert_equal('one') 846 RefVarargs('one', 'two')->assert_equal('one,two') 847 848 CheckDefFailure(['var RefWrong: func(...list<string>, string)'], 'E110:') 849 CheckDefFailure(['var RefWrong: func(...list<string>, ?string)'], 'E110:') 850enddef 851 852" Only varargs 853def MyVarargsOnly(...args: list<string>): string 854 return join(args, ',') 855enddef 856 857def Test_call_varargs_only() 858 MyVarargsOnly()->assert_equal('') 859 MyVarargsOnly('one')->assert_equal('one') 860 MyVarargsOnly('one', 'two')->assert_equal('one,two') 861 CheckDefFailure(['MyVarargsOnly(1)'], 'E1013: Argument 1: type mismatch, expected string but got number') 862 CheckDefFailure(['MyVarargsOnly("one", 2)'], 'E1013: Argument 2: type mismatch, expected string but got number') 863enddef 864 865def Test_using_var_as_arg() 866 writefile(['def Func(x: number)', 'var x = 234', 'enddef', 'defcompile'], 'Xdef') 867 assert_fails('so Xdef', 'E1006:', '', 1, 'Func') 868 delete('Xdef') 869enddef 870 871def DictArg(arg: dict<string>) 872 arg['key'] = 'value' 873enddef 874 875def ListArg(arg: list<string>) 876 arg[0] = 'value' 877enddef 878 879def Test_assign_to_argument() 880 # works for dict and list 881 var d: dict<string> = {} 882 DictArg(d) 883 d['key']->assert_equal('value') 884 var l: list<string> = [] 885 ListArg(l) 886 l[0]->assert_equal('value') 887 888 CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:') 889 delfunc! g:Func 890enddef 891 892" These argument names are reserved in legacy functions. 893def WithReservedNames(firstline: string, lastline: string): string 894 return firstline .. lastline 895enddef 896 897def Test_argument_names() 898 assert_equal('OK', WithReservedNames('O', 'K')) 899enddef 900 901def Test_call_func_defined_later() 902 g:DefinedLater('one')->assert_equal('one') 903 assert_fails('NotDefined("one")', 'E117:', '', 2, 'Test_call_func_defined_later') 904enddef 905 906func DefinedLater(arg) 907 return a:arg 908endfunc 909 910def Test_call_funcref() 911 g:SomeFunc('abc')->assert_equal(3) 912 assert_fails('NotAFunc()', 'E117:', '', 2, 'Test_call_funcref') # comment after call 913 assert_fails('g:NotAFunc()', 'E117:', '', 3, 'Test_call_funcref') 914 915 var lines =<< trim END 916 vim9script 917 def RetNumber(): number 918 return 123 919 enddef 920 var Funcref: func: number = function('RetNumber') 921 Funcref()->assert_equal(123) 922 END 923 CheckScriptSuccess(lines) 924 925 lines =<< trim END 926 vim9script 927 def RetNumber(): number 928 return 123 929 enddef 930 def Bar(F: func: number): number 931 return F() 932 enddef 933 var Funcref = function('RetNumber') 934 Bar(Funcref)->assert_equal(123) 935 END 936 CheckScriptSuccess(lines) 937 938 lines =<< trim END 939 vim9script 940 def UseNumber(nr: number) 941 echo nr 942 enddef 943 var Funcref: func(number) = function('UseNumber') 944 Funcref(123) 945 END 946 CheckScriptSuccess(lines) 947 948 lines =<< trim END 949 vim9script 950 def UseNumber(nr: number) 951 echo nr 952 enddef 953 var Funcref: func(string) = function('UseNumber') 954 END 955 CheckScriptFailure(lines, 'E1012: Type mismatch; expected func(string) but got func(number)') 956 957 lines =<< trim END 958 vim9script 959 def EchoNr(nr = 34) 960 g:echo = nr 961 enddef 962 var Funcref: func(?number) = function('EchoNr') 963 Funcref() 964 g:echo->assert_equal(34) 965 Funcref(123) 966 g:echo->assert_equal(123) 967 END 968 CheckScriptSuccess(lines) 969 970 lines =<< trim END 971 vim9script 972 def EchoList(...l: list<number>) 973 g:echo = l 974 enddef 975 var Funcref: func(...list<number>) = function('EchoList') 976 Funcref() 977 g:echo->assert_equal([]) 978 Funcref(1, 2, 3) 979 g:echo->assert_equal([1, 2, 3]) 980 END 981 CheckScriptSuccess(lines) 982 983 lines =<< trim END 984 vim9script 985 def OptAndVar(nr: number, opt = 12, ...l: list<number>): number 986 g:optarg = opt 987 g:listarg = l 988 return nr 989 enddef 990 var Funcref: func(number, ?number, ...list<number>): number = function('OptAndVar') 991 Funcref(10)->assert_equal(10) 992 g:optarg->assert_equal(12) 993 g:listarg->assert_equal([]) 994 995 Funcref(11, 22)->assert_equal(11) 996 g:optarg->assert_equal(22) 997 g:listarg->assert_equal([]) 998 999 Funcref(17, 18, 1, 2, 3)->assert_equal(17) 1000 g:optarg->assert_equal(18) 1001 g:listarg->assert_equal([1, 2, 3]) 1002 END 1003 CheckScriptSuccess(lines) 1004enddef 1005 1006let SomeFunc = function('len') 1007let NotAFunc = 'text' 1008 1009def CombineFuncrefTypes() 1010 # same arguments, different return type 1011 var Ref1: func(bool): string 1012 var Ref2: func(bool): number 1013 var Ref3: func(bool): any 1014 Ref3 = g:cond ? Ref1 : Ref2 1015 1016 # different number of arguments 1017 var Refa1: func(bool): number 1018 var Refa2: func(bool, number): number 1019 var Refa3: func: number 1020 Refa3 = g:cond ? Refa1 : Refa2 1021 1022 # different argument types 1023 var Refb1: func(bool, string): number 1024 var Refb2: func(string, number): number 1025 var Refb3: func(any, any): number 1026 Refb3 = g:cond ? Refb1 : Refb2 1027enddef 1028 1029def FuncWithForwardCall() 1030 return g:DefinedEvenLater("yes") 1031enddef 1032 1033def DefinedEvenLater(arg: string): string 1034 return arg 1035enddef 1036 1037def Test_error_in_nested_function() 1038 # Error in called function requires unwinding the call stack. 1039 assert_fails('FuncWithForwardCall()', 'E1096:', '', 1, 'FuncWithForwardCall') 1040enddef 1041 1042def Test_return_type_wrong() 1043 CheckScriptFailure([ 1044 'def Func(): number', 1045 'return "a"', 1046 'enddef', 1047 'defcompile'], 'expected number but got string') 1048 delfunc! g:Func 1049 CheckScriptFailure([ 1050 'def Func(): string', 1051 'return 1', 1052 'enddef', 1053 'defcompile'], 'expected string but got number') 1054 delfunc! g:Func 1055 CheckScriptFailure([ 1056 'def Func(): void', 1057 'return "a"', 1058 'enddef', 1059 'defcompile'], 1060 'E1096: Returning a value in a function without a return type') 1061 delfunc! g:Func 1062 CheckScriptFailure([ 1063 'def Func()', 1064 'return "a"', 1065 'enddef', 1066 'defcompile'], 1067 'E1096: Returning a value in a function without a return type') 1068 delfunc! g:Func 1069 1070 CheckScriptFailure([ 1071 'def Func(): number', 1072 'return', 1073 'enddef', 1074 'defcompile'], 'E1003:') 1075 delfunc! g:Func 1076 1077 CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') 1078 delfunc! g:Func 1079 CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') 1080 delfunc! g:Func 1081 CheckScriptFailure(['def Func()', 'return 1'], 'E1057:') 1082 delfunc! g:Func 1083 1084 CheckScriptFailure([ 1085 'vim9script', 1086 'def FuncB()', 1087 ' return 123', 1088 'enddef', 1089 'def FuncA()', 1090 ' FuncB()', 1091 'enddef', 1092 'defcompile'], 'E1096:') 1093enddef 1094 1095def Test_arg_type_wrong() 1096 CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') 1097 CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...') 1098 CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:') 1099 CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:') 1100enddef 1101 1102def Test_vim9script_call() 1103 var lines =<< trim END 1104 vim9script 1105 var name = '' 1106 def MyFunc(arg: string) 1107 name = arg 1108 enddef 1109 MyFunc('foobar') 1110 name->assert_equal('foobar') 1111 1112 var str = 'barfoo' 1113 str->MyFunc() 1114 name->assert_equal('barfoo') 1115 1116 g:value = 'value' 1117 g:value->MyFunc() 1118 name->assert_equal('value') 1119 1120 var listvar = [] 1121 def ListFunc(arg: list<number>) 1122 listvar = arg 1123 enddef 1124 [1, 2, 3]->ListFunc() 1125 listvar->assert_equal([1, 2, 3]) 1126 1127 var dictvar = {} 1128 def DictFunc(arg: dict<number>) 1129 dictvar = arg 1130 enddef 1131 {a: 1, b: 2}->DictFunc() 1132 dictvar->assert_equal({a: 1, b: 2}) 1133 def CompiledDict() 1134 {a: 3, b: 4}->DictFunc() 1135 enddef 1136 CompiledDict() 1137 dictvar->assert_equal({a: 3, b: 4}) 1138 1139 {a: 3, b: 4}->DictFunc() 1140 dictvar->assert_equal({a: 3, b: 4}) 1141 1142 ('text')->MyFunc() 1143 name->assert_equal('text') 1144 ("some")->MyFunc() 1145 name->assert_equal('some') 1146 1147 # line starting with single quote is not a mark 1148 # line starting with double quote can be a method call 1149 'asdfasdf'->MyFunc() 1150 name->assert_equal('asdfasdf') 1151 "xyz"->MyFunc() 1152 name->assert_equal('xyz') 1153 1154 def UseString() 1155 'xyork'->MyFunc() 1156 enddef 1157 UseString() 1158 name->assert_equal('xyork') 1159 1160 def UseString2() 1161 "knife"->MyFunc() 1162 enddef 1163 UseString2() 1164 name->assert_equal('knife') 1165 1166 # prepending a colon makes it a mark 1167 new 1168 setline(1, ['aaa', 'bbb', 'ccc']) 1169 normal! 3Gmt1G 1170 :'t 1171 getcurpos()[1]->assert_equal(3) 1172 bwipe! 1173 1174 MyFunc( 1175 'continued' 1176 ) 1177 assert_equal('continued', 1178 name 1179 ) 1180 1181 call MyFunc( 1182 'more' 1183 .. 1184 'lines' 1185 ) 1186 assert_equal( 1187 'morelines', 1188 name) 1189 END 1190 writefile(lines, 'Xcall.vim') 1191 source Xcall.vim 1192 delete('Xcall.vim') 1193enddef 1194 1195def Test_vim9script_call_fail_decl() 1196 var lines =<< trim END 1197 vim9script 1198 var name = '' 1199 def MyFunc(arg: string) 1200 var name = 123 1201 enddef 1202 defcompile 1203 END 1204 CheckScriptFailure(lines, 'E1054:') 1205enddef 1206 1207def Test_vim9script_call_fail_type() 1208 var lines =<< trim END 1209 vim9script 1210 def MyFunc(arg: string) 1211 echo arg 1212 enddef 1213 MyFunc(1234) 1214 END 1215 CheckScriptFailure(lines, 'E1013: Argument 1: type mismatch, expected string but got number') 1216enddef 1217 1218def Test_vim9script_call_fail_const() 1219 var lines =<< trim END 1220 vim9script 1221 const var = '' 1222 def MyFunc(arg: string) 1223 var = 'asdf' 1224 enddef 1225 defcompile 1226 END 1227 writefile(lines, 'Xcall_const.vim') 1228 assert_fails('source Xcall_const.vim', 'E46:', '', 1, 'MyFunc') 1229 delete('Xcall_const.vim') 1230 1231 lines =<< trim END 1232 const g:Aconst = 77 1233 def Change() 1234 # comment 1235 g:Aconst = 99 1236 enddef 1237 call Change() 1238 unlet g:Aconst 1239 END 1240 CheckScriptFailure(lines, 'E741: Value is locked: Aconst', 2) 1241enddef 1242 1243" Test that inside :function a Python function can be defined, :def is not 1244" recognized. 1245func Test_function_python() 1246 CheckFeature python3 1247 let py = 'python3' 1248 execute py "<< EOF" 1249def do_something(): 1250 return 1 1251EOF 1252endfunc 1253 1254def Test_delfunc() 1255 var lines =<< trim END 1256 vim9script 1257 def g:GoneSoon() 1258 echo 'hello' 1259 enddef 1260 1261 def CallGoneSoon() 1262 GoneSoon() 1263 enddef 1264 defcompile 1265 1266 delfunc g:GoneSoon 1267 CallGoneSoon() 1268 END 1269 writefile(lines, 'XToDelFunc') 1270 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1271 assert_fails('so XToDelFunc', 'E933:', '', 1, 'CallGoneSoon') 1272 1273 delete('XToDelFunc') 1274enddef 1275 1276def Test_redef_failure() 1277 writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef') 1278 so Xdef 1279 writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') 1280 so Xdef 1281 writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef') 1282 assert_fails('so Xdef', 'E1027:', '', 1, 'Func0') 1283 writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') 1284 so Xdef 1285 delete('Xdef') 1286 1287 g:Func0()->assert_equal(0) 1288 g:Func1()->assert_equal('Func1') 1289 g:Func2()->assert_equal('Func2') 1290 1291 delfunc! Func0 1292 delfunc! Func1 1293 delfunc! Func2 1294enddef 1295 1296def Test_vim9script_func() 1297 var lines =<< trim END 1298 vim9script 1299 func Func(arg) 1300 echo a:arg 1301 endfunc 1302 Func('text') 1303 END 1304 writefile(lines, 'XVim9Func') 1305 so XVim9Func 1306 1307 delete('XVim9Func') 1308enddef 1309 1310let s:funcResult = 0 1311 1312def FuncNoArgNoRet() 1313 s:funcResult = 11 1314enddef 1315 1316def FuncNoArgRetNumber(): number 1317 s:funcResult = 22 1318 return 1234 1319enddef 1320 1321def FuncNoArgRetString(): string 1322 s:funcResult = 45 1323 return 'text' 1324enddef 1325 1326def FuncOneArgNoRet(arg: number) 1327 s:funcResult = arg 1328enddef 1329 1330def FuncOneArgRetNumber(arg: number): number 1331 s:funcResult = arg 1332 return arg 1333enddef 1334 1335def FuncTwoArgNoRet(one: bool, two: number) 1336 s:funcResult = two 1337enddef 1338 1339def FuncOneArgRetString(arg: string): string 1340 return arg 1341enddef 1342 1343def FuncOneArgRetAny(arg: any): any 1344 return arg 1345enddef 1346 1347def Test_func_type() 1348 var Ref1: func() 1349 s:funcResult = 0 1350 Ref1 = FuncNoArgNoRet 1351 Ref1() 1352 s:funcResult->assert_equal(11) 1353 1354 var Ref2: func 1355 s:funcResult = 0 1356 Ref2 = FuncNoArgNoRet 1357 Ref2() 1358 s:funcResult->assert_equal(11) 1359 1360 s:funcResult = 0 1361 Ref2 = FuncOneArgNoRet 1362 Ref2(12) 1363 s:funcResult->assert_equal(12) 1364 1365 s:funcResult = 0 1366 Ref2 = FuncNoArgRetNumber 1367 Ref2()->assert_equal(1234) 1368 s:funcResult->assert_equal(22) 1369 1370 s:funcResult = 0 1371 Ref2 = FuncOneArgRetNumber 1372 Ref2(13)->assert_equal(13) 1373 s:funcResult->assert_equal(13) 1374enddef 1375 1376def Test_repeat_return_type() 1377 var res = 0 1378 for n in repeat([1], 3) 1379 res += n 1380 endfor 1381 res->assert_equal(3) 1382 1383 res = 0 1384 for n in add([1, 2], 3) 1385 res += n 1386 endfor 1387 res->assert_equal(6) 1388enddef 1389 1390def Test_argv_return_type() 1391 next fileone filetwo 1392 var res = '' 1393 for name in argv() 1394 res ..= name 1395 endfor 1396 res->assert_equal('fileonefiletwo') 1397enddef 1398 1399def Test_func_type_part() 1400 var RefVoid: func: void 1401 RefVoid = FuncNoArgNoRet 1402 RefVoid = FuncOneArgNoRet 1403 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...) but got func(): number') 1404 CheckDefFailure(['var RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...) but got func(): string') 1405 1406 var RefAny: func(): any 1407 RefAny = FuncNoArgRetNumber 1408 RefAny = FuncNoArgRetString 1409 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func()') 1410 CheckDefFailure(['var RefAny: func(): any', 'RefAny = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func(): any but got func(number)') 1411 1412 var RefAnyNoArgs: func: any = RefAny 1413 1414 var RefNr: func: number 1415 RefNr = FuncNoArgRetNumber 1416 RefNr = FuncOneArgRetNumber 1417 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): number but got func()') 1418 CheckDefFailure(['var RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1012: Type mismatch; expected func(...): number but got func(): string') 1419 1420 var RefStr: func: string 1421 RefStr = FuncNoArgRetString 1422 RefStr = FuncOneArgRetString 1423 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgNoRet'], 'E1012: Type mismatch; expected func(...): string but got func()') 1424 CheckDefFailure(['var RefStr: func: string', 'RefStr = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func(...): string but got func(): number') 1425enddef 1426 1427def Test_func_type_fails() 1428 CheckDefFailure(['var ref1: func()'], 'E704:') 1429 1430 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(): number') 1431 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1012: Type mismatch; expected func() but got func(number)') 1432 CheckDefFailure(['var Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1012: Type mismatch; expected func() but got func(number): number') 1433 CheckDefFailure(['var Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(bool) but got func(bool, number)') 1434 CheckDefFailure(['var Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(?bool) but got func(bool, number)') 1435 CheckDefFailure(['var Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1012: Type mismatch; expected func(...bool) but got func(bool, number)') 1436 1437 CheckDefFailure(['var RefWrong: func(string ,number)'], 'E1068:') 1438 CheckDefFailure(['var RefWrong: func(string,number)'], 'E1069:') 1439 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:') 1440 CheckDefFailure(['var RefWrong: func(bool):string'], 'E1069:') 1441enddef 1442 1443def Test_func_return_type() 1444 var nr: number 1445 nr = FuncNoArgRetNumber() 1446 nr->assert_equal(1234) 1447 1448 nr = FuncOneArgRetAny(122) 1449 nr->assert_equal(122) 1450 1451 var str: string 1452 str = FuncOneArgRetAny('yes') 1453 str->assert_equal('yes') 1454 1455 CheckDefFailure(['var str: string', 'str = FuncNoArgRetNumber()'], 'E1012: Type mismatch; expected string but got number') 1456enddef 1457 1458def Test_func_common_type() 1459 def FuncOne(n: number): number 1460 return n 1461 enddef 1462 def FuncTwo(s: string): number 1463 return len(s) 1464 enddef 1465 def FuncThree(n: number, s: string): number 1466 return n + len(s) 1467 enddef 1468 var list = [FuncOne, FuncTwo, FuncThree] 1469 assert_equal(8, list[0](8)) 1470 assert_equal(4, list[1]('word')) 1471 assert_equal(7, list[2](3, 'word')) 1472enddef 1473 1474def MultiLine( 1475 arg1: string, 1476 arg2 = 1234, 1477 ...rest: list<string> 1478 ): string 1479 return arg1 .. arg2 .. join(rest, '-') 1480enddef 1481 1482def MultiLineComment( 1483 arg1: string, # comment 1484 arg2 = 1234, # comment 1485 ...rest: list<string> # comment 1486 ): string # comment 1487 return arg1 .. arg2 .. join(rest, '-') 1488enddef 1489 1490def Test_multiline() 1491 MultiLine('text')->assert_equal('text1234') 1492 MultiLine('text', 777)->assert_equal('text777') 1493 MultiLine('text', 777, 'one')->assert_equal('text777one') 1494 MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1495enddef 1496 1497func Test_multiline_not_vim9() 1498 call MultiLine('text')->assert_equal('text1234') 1499 call MultiLine('text', 777)->assert_equal('text777') 1500 call MultiLine('text', 777, 'one')->assert_equal('text777one') 1501 call MultiLine('text', 777, 'one', 'two')->assert_equal('text777one-two') 1502endfunc 1503 1504 1505" When using CheckScriptFailure() for the below test, E1010 is generated instead 1506" of E1056. 1507func Test_E1056_1059() 1508 let caught_1056 = 0 1509 try 1510 def F(): 1511 return 1 1512 enddef 1513 catch /E1056:/ 1514 let caught_1056 = 1 1515 endtry 1516 eval caught_1056->assert_equal(1) 1517 1518 let caught_1059 = 0 1519 try 1520 def F5(items : list) 1521 echo 'a' 1522 enddef 1523 catch /E1059:/ 1524 let caught_1059 = 1 1525 endtry 1526 eval caught_1059->assert_equal(1) 1527endfunc 1528 1529func DelMe() 1530 echo 'DelMe' 1531endfunc 1532 1533def Test_error_reporting() 1534 # comment lines at the start of the function 1535 var lines =<< trim END 1536 " comment 1537 def Func() 1538 # comment 1539 # comment 1540 invalid 1541 enddef 1542 defcompile 1543 END 1544 writefile(lines, 'Xdef') 1545 try 1546 source Xdef 1547 assert_report('should have failed') 1548 catch /E476:/ 1549 v:exception->assert_match('Invalid command: invalid') 1550 v:throwpoint->assert_match(', line 3$') 1551 endtry 1552 delfunc! g:Func 1553 1554 # comment lines after the start of the function 1555 lines =<< trim END 1556 " comment 1557 def Func() 1558 var x = 1234 1559 # comment 1560 # comment 1561 invalid 1562 enddef 1563 defcompile 1564 END 1565 writefile(lines, 'Xdef') 1566 try 1567 source Xdef 1568 assert_report('should have failed') 1569 catch /E476:/ 1570 v:exception->assert_match('Invalid command: invalid') 1571 v:throwpoint->assert_match(', line 4$') 1572 endtry 1573 delfunc! g:Func 1574 1575 lines =<< trim END 1576 vim9script 1577 def Func() 1578 var db = {foo: 1, bar: 2} 1579 # comment 1580 var x = db.asdf 1581 enddef 1582 defcompile 1583 Func() 1584 END 1585 writefile(lines, 'Xdef') 1586 try 1587 source Xdef 1588 assert_report('should have failed') 1589 catch /E716:/ 1590 v:throwpoint->assert_match('_Func, line 3$') 1591 endtry 1592 delfunc! g:Func 1593 1594 delete('Xdef') 1595enddef 1596 1597def Test_deleted_function() 1598 CheckDefExecFailure([ 1599 'var RefMe: func = function("g:DelMe")', 1600 'delfunc g:DelMe', 1601 'echo RefMe()'], 'E117:') 1602enddef 1603 1604def Test_unknown_function() 1605 CheckDefExecFailure([ 1606 'var Ref: func = function("NotExist")', 1607 'delfunc g:NotExist'], 'E700:') 1608enddef 1609 1610def RefFunc(Ref: func(any): any): string 1611 return Ref('more') 1612enddef 1613 1614def Test_closure_simple() 1615 var local = 'some ' 1616 RefFunc((s) => local .. s)->assert_equal('some more') 1617enddef 1618 1619def MakeRef() 1620 var local = 'some ' 1621 g:Ref = (s) => local .. s 1622enddef 1623 1624def Test_closure_ref_after_return() 1625 MakeRef() 1626 g:Ref('thing')->assert_equal('some thing') 1627 unlet g:Ref 1628enddef 1629 1630def MakeTwoRefs() 1631 var local = ['some'] 1632 g:Extend = (s) => local->add(s) 1633 g:Read = () => local 1634enddef 1635 1636def Test_closure_two_refs() 1637 MakeTwoRefs() 1638 join(g:Read(), ' ')->assert_equal('some') 1639 g:Extend('more') 1640 join(g:Read(), ' ')->assert_equal('some more') 1641 g:Extend('even') 1642 join(g:Read(), ' ')->assert_equal('some more even') 1643 1644 unlet g:Extend 1645 unlet g:Read 1646enddef 1647 1648def ReadRef(Ref: func(): list<string>): string 1649 return join(Ref(), ' ') 1650enddef 1651 1652def ExtendRef(Ref: func(string): list<string>, add: string) 1653 Ref(add) 1654enddef 1655 1656def Test_closure_two_indirect_refs() 1657 MakeTwoRefs() 1658 ReadRef(g:Read)->assert_equal('some') 1659 ExtendRef(g:Extend, 'more') 1660 ReadRef(g:Read)->assert_equal('some more') 1661 ExtendRef(g:Extend, 'even') 1662 ReadRef(g:Read)->assert_equal('some more even') 1663 1664 unlet g:Extend 1665 unlet g:Read 1666enddef 1667 1668def MakeArgRefs(theArg: string) 1669 var local = 'loc_val' 1670 g:UseArg = (s) => theArg .. '/' .. local .. '/' .. s 1671enddef 1672 1673def MakeArgRefsVarargs(theArg: string, ...rest: list<string>) 1674 var local = 'the_loc' 1675 g:UseVararg = (s) => theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest) 1676enddef 1677 1678def Test_closure_using_argument() 1679 MakeArgRefs('arg_val') 1680 g:UseArg('call_val')->assert_equal('arg_val/loc_val/call_val') 1681 1682 MakeArgRefsVarargs('arg_val', 'one', 'two') 1683 g:UseVararg('call_val')->assert_equal('arg_val/the_loc/call_val/one two') 1684 1685 unlet g:UseArg 1686 unlet g:UseVararg 1687 1688 var lines =<< trim END 1689 vim9script 1690 def Test(Fun: func(number): number): list<number> 1691 return map([1, 2, 3], (_, i) => Fun(i)) 1692 enddef 1693 def Inc(nr: number): number 1694 return nr + 2 1695 enddef 1696 assert_equal([3, 4, 5], Test(Inc)) 1697 END 1698 CheckScriptSuccess(lines) 1699enddef 1700 1701def MakeGetAndAppendRefs() 1702 var local = 'a' 1703 1704 def Append(arg: string) 1705 local ..= arg 1706 enddef 1707 g:Append = Append 1708 1709 def Get(): string 1710 return local 1711 enddef 1712 g:Get = Get 1713enddef 1714 1715def Test_closure_append_get() 1716 MakeGetAndAppendRefs() 1717 g:Get()->assert_equal('a') 1718 g:Append('-b') 1719 g:Get()->assert_equal('a-b') 1720 g:Append('-c') 1721 g:Get()->assert_equal('a-b-c') 1722 1723 unlet g:Append 1724 unlet g:Get 1725enddef 1726 1727def Test_nested_closure() 1728 var local = 'text' 1729 def Closure(arg: string): string 1730 return local .. arg 1731 enddef 1732 Closure('!!!')->assert_equal('text!!!') 1733enddef 1734 1735func GetResult(Ref) 1736 return a:Ref('some') 1737endfunc 1738 1739def Test_call_closure_not_compiled() 1740 var text = 'text' 1741 g:Ref = (s) => s .. text 1742 GetResult(g:Ref)->assert_equal('sometext') 1743enddef 1744 1745def Test_double_closure_fails() 1746 var lines =<< trim END 1747 vim9script 1748 def Func() 1749 var name = 0 1750 for i in range(2) 1751 timer_start(0, () => name) 1752 endfor 1753 enddef 1754 Func() 1755 END 1756 CheckScriptSuccess(lines) 1757enddef 1758 1759def Test_nested_closure_used() 1760 var lines =<< trim END 1761 vim9script 1762 def Func() 1763 var x = 'hello' 1764 var Closure = () => x 1765 g:Myclosure = () => Closure() 1766 enddef 1767 Func() 1768 assert_equal('hello', g:Myclosure()) 1769 END 1770 CheckScriptSuccess(lines) 1771enddef 1772 1773def Test_nested_closure_fails() 1774 var lines =<< trim END 1775 vim9script 1776 def FuncA() 1777 FuncB(0) 1778 enddef 1779 def FuncB(n: number): list<string> 1780 return map([0], (_, v) => n) 1781 enddef 1782 FuncA() 1783 END 1784 CheckScriptFailure(lines, 'E1012:') 1785enddef 1786 1787def Test_global_closure() 1788 var lines =<< trim END 1789 vim9script 1790 def ReverseEveryNLines(n: number, line1: number, line2: number) 1791 var mods = 'sil keepj keepp lockm ' 1792 var range = ':' .. line1 .. ',' .. line2 1793 def g:Offset(): number 1794 var offset = (line('.') - line1 + 1) % n 1795 return offset != 0 ? offset : n 1796 enddef 1797 exe mods .. range .. 'g/^/exe "m .-" .. g:Offset()' 1798 enddef 1799 1800 new 1801 repeat(['aaa', 'bbb', 'ccc'], 3)->setline(1) 1802 ReverseEveryNLines(3, 1, 9) 1803 END 1804 CheckScriptSuccess(lines) 1805 var expected = repeat(['ccc', 'bbb', 'aaa'], 3) 1806 assert_equal(expected, getline(1, 9)) 1807 bwipe! 1808enddef 1809 1810def Test_global_closure_called_directly() 1811 var lines =<< trim END 1812 vim9script 1813 def Outer() 1814 var x = 1 1815 def g:Inner() 1816 var y = x 1817 x += 1 1818 assert_equal(1, y) 1819 enddef 1820 g:Inner() 1821 assert_equal(2, x) 1822 enddef 1823 Outer() 1824 END 1825 CheckScriptSuccess(lines) 1826 delfunc g:Inner 1827enddef 1828 1829def Test_failure_in_called_function() 1830 # this was using the frame index as the return value 1831 var lines =<< trim END 1832 vim9script 1833 au TerminalWinOpen * eval [][0] 1834 def PopupTerm(a: any) 1835 # make sure typvals on stack are string 1836 ['a', 'b', 'c', 'd', 'e', 'f', 'g']->join() 1837 FireEvent() 1838 enddef 1839 def FireEvent() 1840 do TerminalWinOpen 1841 enddef 1842 # use try/catch to make eval fail 1843 try 1844 call PopupTerm(0) 1845 catch 1846 endtry 1847 au! TerminalWinOpen 1848 END 1849 CheckScriptSuccess(lines) 1850enddef 1851 1852def Test_nested_lambda() 1853 var lines =<< trim END 1854 vim9script 1855 def Func() 1856 var x = 4 1857 var Lambda1 = () => 7 1858 var Lambda2 = () => [Lambda1(), x] 1859 var res = Lambda2() 1860 assert_equal([7, 4], res) 1861 enddef 1862 Func() 1863 END 1864 CheckScriptSuccess(lines) 1865enddef 1866 1867def Shadowed(): list<number> 1868 var FuncList: list<func: number> = [() => 42] 1869 return FuncList->mapnew((_, Shadowed) => Shadowed()) 1870enddef 1871 1872def Test_lambda_arg_shadows_func() 1873 assert_equal([42], Shadowed()) 1874enddef 1875 1876def Line_continuation_in_def(dir: string = ''): string 1877 var path: string = empty(dir) 1878 \ ? 'empty' 1879 \ : 'full' 1880 return path 1881enddef 1882 1883def Test_line_continuation_in_def() 1884 Line_continuation_in_def('.')->assert_equal('full') 1885enddef 1886 1887def Test_script_var_in_lambda() 1888 var lines =<< trim END 1889 vim9script 1890 var script = 'test' 1891 assert_equal(['test'], map(['one'], () => script)) 1892 END 1893 CheckScriptSuccess(lines) 1894enddef 1895 1896def Line_continuation_in_lambda(): list<string> 1897 var x = range(97, 100) 1898 ->mapnew((_, v) => nr2char(v) 1899 ->toupper()) 1900 ->reverse() 1901 return x 1902enddef 1903 1904def Test_line_continuation_in_lambda() 1905 Line_continuation_in_lambda()->assert_equal(['D', 'C', 'B', 'A']) 1906 1907 var lines =<< trim END 1908 vim9script 1909 var res = [{n: 1, m: 2, s: 'xxx'}] 1910 ->mapnew((_, v: dict<any>): string => printf('%d:%d:%s', 1911 v.n, 1912 v.m, 1913 substitute(v.s, '.*', 'yyy', '') 1914 )) 1915 assert_equal(['1:2:yyy'], res) 1916 END 1917 CheckScriptSuccess(lines) 1918enddef 1919 1920def Test_list_lambda() 1921 timer_start(1000, (_) => 0) 1922 var body = execute(timer_info()[0].callback 1923 ->string() 1924 ->substitute("('", ' ', '') 1925 ->substitute("')", '', '') 1926 ->substitute('function\zs', ' ', '')) 1927 assert_match('def <lambda>\d\+(_: any, ...): number\n1 return 0\n enddef', body) 1928enddef 1929 1930def DoFilterThis(a: string): list<string> 1931 # closure nested inside another closure using argument 1932 var Filter = (l) => filter(l, (_, v) => stridx(v, a) == 0) 1933 return ['x', 'y', 'a', 'x2', 'c']->Filter() 1934enddef 1935 1936def Test_nested_closure_using_argument() 1937 assert_equal(['x', 'x2'], DoFilterThis('x')) 1938enddef 1939 1940def Test_triple_nested_closure() 1941 var what = 'x' 1942 var Match = (val: string, cmp: string): bool => stridx(val, cmp) == 0 1943 var Filter = (l) => filter(l, (_, v) => Match(v, what)) 1944 assert_equal(['x', 'x2'], ['x', 'y', 'a', 'x2', 'c']->Filter()) 1945enddef 1946 1947func Test_silent_echo() 1948 CheckScreendump 1949 1950 let lines =<< trim END 1951 vim9script 1952 def EchoNothing() 1953 silent echo '' 1954 enddef 1955 defcompile 1956 END 1957 call writefile(lines, 'XTest_silent_echo') 1958 1959 " Check that the balloon shows up after a mouse move 1960 let buf = RunVimInTerminal('-S XTest_silent_echo', {'rows': 6}) 1961 call term_sendkeys(buf, ":abc") 1962 call VerifyScreenDump(buf, 'Test_vim9_silent_echo', {}) 1963 1964 " clean up 1965 call StopVimInTerminal(buf) 1966 call delete('XTest_silent_echo') 1967endfunc 1968 1969def SilentlyError() 1970 execute('silent! invalid') 1971 g:did_it = 'yes' 1972enddef 1973 1974func UserError() 1975 silent! invalid 1976endfunc 1977 1978def SilentlyUserError() 1979 UserError() 1980 g:did_it = 'yes' 1981enddef 1982 1983" This can't be a :def function, because the assert would not be reached. 1984func Test_ignore_silent_error() 1985 let g:did_it = 'no' 1986 call SilentlyError() 1987 call assert_equal('yes', g:did_it) 1988 1989 let g:did_it = 'no' 1990 call SilentlyUserError() 1991 call assert_equal('yes', g:did_it) 1992 1993 unlet g:did_it 1994endfunc 1995 1996def Test_ignore_silent_error_in_filter() 1997 var lines =<< trim END 1998 vim9script 1999 def Filter(winid: number, key: string): bool 2000 if key == 'o' 2001 silent! eval [][0] 2002 return true 2003 endif 2004 return popup_filter_menu(winid, key) 2005 enddef 2006 2007 popup_create('popup', {filter: Filter}) 2008 feedkeys("o\r", 'xnt') 2009 END 2010 CheckScriptSuccess(lines) 2011enddef 2012 2013def Fibonacci(n: number): number 2014 if n < 2 2015 return n 2016 else 2017 return Fibonacci(n - 1) + Fibonacci(n - 2) 2018 endif 2019enddef 2020 2021def Test_recursive_call() 2022 Fibonacci(20)->assert_equal(6765) 2023enddef 2024 2025def TreeWalk(dir: string): list<any> 2026 return readdir(dir)->mapnew((_, val) => 2027 fnamemodify(dir .. '/' .. val, ':p')->isdirectory() 2028 ? {[val]: TreeWalk(dir .. '/' .. val)} 2029 : val 2030 ) 2031enddef 2032 2033def Test_closure_in_map() 2034 mkdir('XclosureDir/tdir', 'p') 2035 writefile(['111'], 'XclosureDir/file1') 2036 writefile(['222'], 'XclosureDir/file2') 2037 writefile(['333'], 'XclosureDir/tdir/file3') 2038 2039 TreeWalk('XclosureDir')->assert_equal(['file1', 'file2', {tdir: ['file3']}]) 2040 2041 delete('XclosureDir', 'rf') 2042enddef 2043 2044def Test_invalid_function_name() 2045 var lines =<< trim END 2046 vim9script 2047 def s: list<string> 2048 END 2049 CheckScriptFailure(lines, 'E129:') 2050 2051 lines =<< trim END 2052 vim9script 2053 def g: list<string> 2054 END 2055 CheckScriptFailure(lines, 'E129:') 2056 2057 lines =<< trim END 2058 vim9script 2059 def <SID>: list<string> 2060 END 2061 CheckScriptFailure(lines, 'E884:') 2062 2063 lines =<< trim END 2064 vim9script 2065 def F list<string> 2066 END 2067 CheckScriptFailure(lines, 'E488:') 2068enddef 2069 2070def Test_partial_call() 2071 var Xsetlist = function('setloclist', [0]) 2072 Xsetlist([], ' ', {title: 'test'}) 2073 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2074 2075 Xsetlist = function('setloclist', [0, [], ' ']) 2076 Xsetlist({title: 'test'}) 2077 getloclist(0, {title: 1})->assert_equal({title: 'test'}) 2078 2079 Xsetlist = function('setqflist') 2080 Xsetlist([], ' ', {title: 'test'}) 2081 getqflist({title: 1})->assert_equal({title: 'test'}) 2082 2083 Xsetlist = function('setqflist', [[], ' ']) 2084 Xsetlist({title: 'test'}) 2085 getqflist({title: 1})->assert_equal({title: 'test'}) 2086 2087 var Len: func: number = function('len', ['word']) 2088 assert_equal(4, Len()) 2089enddef 2090 2091def Test_cmd_modifier() 2092 tab echo '0' 2093 CheckDefFailure(['5tab echo 3'], 'E16:') 2094enddef 2095 2096def Test_restore_modifiers() 2097 # check that when compiling a :def function command modifiers are not messed 2098 # up. 2099 var lines =<< trim END 2100 vim9script 2101 set eventignore= 2102 autocmd QuickFixCmdPost * copen 2103 def AutocmdsDisabled() 2104 eval 0 2105 enddef 2106 func Func() 2107 noautocmd call s:AutocmdsDisabled() 2108 let g:ei_after = &eventignore 2109 endfunc 2110 Func() 2111 END 2112 CheckScriptSuccess(lines) 2113 g:ei_after->assert_equal('') 2114enddef 2115 2116def StackTop() 2117 eval 1 2118 eval 2 2119 # call not on fourth line 2120 StackBot() 2121enddef 2122 2123def StackBot() 2124 # throw an error 2125 eval [][0] 2126enddef 2127 2128def Test_callstack_def() 2129 try 2130 StackTop() 2131 catch 2132 v:throwpoint->assert_match('Test_callstack_def\[2\]..StackTop\[4\]..StackBot, line 2') 2133 endtry 2134enddef 2135 2136" Re-using spot for variable used in block 2137def Test_block_scoped_var() 2138 var lines =<< trim END 2139 vim9script 2140 def Func() 2141 var x = ['a', 'b', 'c'] 2142 if 1 2143 var y = 'x' 2144 map(x, () => y) 2145 endif 2146 var z = x 2147 assert_equal(['x', 'x', 'x'], z) 2148 enddef 2149 Func() 2150 END 2151 CheckScriptSuccess(lines) 2152enddef 2153 2154def Test_reset_did_emsg() 2155 var lines =<< trim END 2156 @s = 'blah' 2157 au BufWinLeave * # 2158 def Func() 2159 var winid = popup_create('popup', {}) 2160 exe '*s' 2161 popup_close(winid) 2162 enddef 2163 Func() 2164 END 2165 CheckScriptFailure(lines, 'E492:', 8) 2166 delfunc! g:Func 2167enddef 2168 2169def Test_did_emsg_reset() 2170 # executing an autocommand resets did_emsg, this should not result in a 2171 # builtin function considered failing 2172 var lines =<< trim END 2173 vim9script 2174 au BufWinLeave * # 2175 def Func() 2176 popup_menu('', {callback: () => popup_create('', {})->popup_close()}) 2177 eval [][0] 2178 enddef 2179 nno <F3> <cmd>call <sid>Func()<cr> 2180 feedkeys("\<F3>\e", 'xt') 2181 END 2182 writefile(lines, 'XemsgReset') 2183 assert_fails('so XemsgReset', ['E684:', 'E684:'], lines, 2) 2184 delete('XemsgReset') 2185 nunmap <F3> 2186 au! BufWinLeave 2187enddef 2188 2189def Test_abort_with_silent_call() 2190 var lines =<< trim END 2191 vim9script 2192 g:result = 'none' 2193 def Func() 2194 g:result += 3 2195 g:result = 'yes' 2196 enddef 2197 # error is silenced, but function aborts on error 2198 silent! Func() 2199 assert_equal('none', g:result) 2200 unlet g:result 2201 END 2202 CheckScriptSuccess(lines) 2203enddef 2204 2205def Test_continues_with_silent_error() 2206 var lines =<< trim END 2207 vim9script 2208 g:result = 'none' 2209 def Func() 2210 silent! g:result += 3 2211 g:result = 'yes' 2212 enddef 2213 # error is silenced, function does not abort 2214 Func() 2215 assert_equal('yes', g:result) 2216 unlet g:result 2217 END 2218 CheckScriptSuccess(lines) 2219enddef 2220 2221def Test_abort_even_with_silent() 2222 var lines =<< trim END 2223 vim9script 2224 g:result = 'none' 2225 def Func() 2226 eval {-> ''}() .. '' .. {}['X'] 2227 g:result = 'yes' 2228 enddef 2229 silent! Func() 2230 assert_equal('none', g:result) 2231 unlet g:result 2232 END 2233 CheckScriptSuccess(lines) 2234enddef 2235 2236def Test_cmdmod_silent_restored() 2237 var lines =<< trim END 2238 vim9script 2239 def Func() 2240 g:result = 'none' 2241 silent! g:result += 3 2242 g:result = 'none' 2243 g:result += 3 2244 enddef 2245 Func() 2246 END 2247 # can't use CheckScriptFailure, it ignores the :silent! 2248 var fname = 'Xdefsilent' 2249 writefile(lines, fname) 2250 var caught = 'no' 2251 try 2252 exe 'source ' .. fname 2253 catch /E1030:/ 2254 caught = 'yes' 2255 assert_match('Func, line 4', v:throwpoint) 2256 endtry 2257 assert_equal('yes', caught) 2258 delete(fname) 2259enddef 2260 2261def Test_dict_member_with_silent() 2262 var lines =<< trim END 2263 vim9script 2264 g:result = 'none' 2265 var d: dict<any> 2266 def Func() 2267 try 2268 g:result = map([], (_, v) => ({}[v]))->join() .. d[''] 2269 catch 2270 endtry 2271 enddef 2272 silent! Func() 2273 assert_equal('0', g:result) 2274 unlet g:result 2275 END 2276 CheckScriptSuccess(lines) 2277enddef 2278 2279def Test_skip_cmds_with_silent() 2280 var lines =<< trim END 2281 vim9script 2282 2283 def Func(b: bool) 2284 Crash() 2285 enddef 2286 2287 def Crash() 2288 sil! :/not found/d _ 2289 sil! :/not found/put _ 2290 enddef 2291 2292 Func(true) 2293 END 2294 CheckScriptSuccess(lines) 2295enddef 2296 2297def Test_opfunc() 2298 nnoremap <F3> <cmd>set opfunc=Opfunc<cr>g@ 2299 def g:Opfunc(_: any): string 2300 setline(1, 'ASDF') 2301 return '' 2302 enddef 2303 new 2304 setline(1, 'asdf') 2305 feedkeys("\<F3>$", 'x') 2306 assert_equal('ASDF', getline(1)) 2307 2308 bwipe! 2309 nunmap <F3> 2310enddef 2311 2312" this was crashing on exit 2313def Test_nested_lambda_in_closure() 2314 var lines =<< trim END 2315 vim9script 2316 def Outer() 2317 def g:Inner() 2318 echo map([1, 2, 3], {_, v -> v + 1}) 2319 enddef 2320 g:Inner() 2321 enddef 2322 defcompile 2323 writefile(['Done'], 'XnestedDone') 2324 quit 2325 END 2326 if !RunVim([], lines, '--clean') 2327 return 2328 endif 2329 assert_equal(['Done'], readfile('XnestedDone')) 2330 delete('XnestedDone') 2331enddef 2332 2333 2334 2335" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 2336