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