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