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