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