1" Test various aspects of the Vim9 script language. 2 3source check.vim 4 5" Check that "lines" inside ":def" results in an "error" message. 6func CheckDefFailure(lines, error) 7 call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') 8 call assert_fails('so Xdef', a:error, a:lines) 9 call delete('Xdef') 10endfunc 11 12func CheckScriptFailure(lines, error) 13 call writefile(a:lines, 'Xdef') 14 call assert_fails('so Xdef', a:error, a:lines) 15 call delete('Xdef') 16endfunc 17 18def Test_syntax() 19 let var = 234 20 let other: list<string> = ['asdf'] 21enddef 22 23func Test_def_basic() 24 def SomeFunc(): string 25 return 'yes' 26 enddef 27 call assert_equal('yes', SomeFunc()) 28endfunc 29 30let s:appendToMe = 'xxx' 31let s:addToMe = 111 32let g:existing = 'yes' 33 34def Test_assignment() 35 let bool1: bool = true 36 assert_equal(v:true, bool1) 37 let bool2: bool = false 38 assert_equal(v:false, bool2) 39 40 let list1: list<bool> = [false, true, false] 41 let list2: list<number> = [1, 2, 3] 42 let list3: list<string> = ['sdf', 'asdf'] 43 let list4: list<any> = ['yes', true, 1234] 44 let list5: list<blob> = [0z01, 0z02] 45 46 let listS: list<string> = [] 47 let listN: list<number> = [] 48 49 let dict1: dict<bool> = #{one: false, two: true} 50 let dict2: dict<number> = #{one: 1, two: 2} 51 let dict3: dict<string> = #{key: 'value'} 52 let dict4: dict<any> = #{one: 1, two: '2'} 53 let dict5: dict<blob> = #{one: 0z01, tw: 0z02} 54 55 g:newvar = 'new' 56 assert_equal('new', g:newvar) 57 58 assert_equal('yes', g:existing) 59 g:existing = 'no' 60 assert_equal('no', g:existing) 61 62 v:char = 'abc' 63 assert_equal('abc', v:char) 64 65 $ENVVAR = 'foobar' 66 assert_equal('foobar', $ENVVAR) 67 $ENVVAR = '' 68 69 s:appendToMe ..= 'yyy' 70 assert_equal('xxxyyy', s:appendToMe) 71 s:addToMe += 222 72 assert_equal(333, s:addToMe) 73 s:newVar = 'new' 74 assert_equal('new', s:newVar) 75enddef 76 77func Test_assignment_failure() 78 call CheckDefFailure(['let var=234'], 'E1004:') 79 call CheckDefFailure(['let var =234'], 'E1004:') 80 call CheckDefFailure(['let var= 234'], 'E1004:') 81 82 call CheckDefFailure(['let true = 1'], 'E1034:') 83 call CheckDefFailure(['let false = 1'], 'E1034:') 84 85 call CheckDefFailure(['let var: list<string> = [123]'], 'expected list<string> but got list<number>') 86 call CheckDefFailure(['let var: list<number> = ["xx"]'], 'expected list<number> but got list<string>') 87 88 call CheckDefFailure(['let var: dict<string> = #{key: 123}'], 'expected dict<string> but got dict<number>') 89 call CheckDefFailure(['let var: dict<number> = #{key: "xx"}'], 'expected dict<number> but got dict<string>') 90 91 call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:') 92 call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number but got void') 93endfunc 94 95func Test_const() 96 call CheckDefFailure(['const var = 234', 'var = 99'], 'E1018:') 97 call CheckDefFailure(['const one = 234', 'let one = 99'], 'E1017:') 98 call CheckDefFailure(['const two'], 'E1021:') 99endfunc 100 101def Test_block() 102 let outer = 1 103 { 104 let inner = 2 105 assert_equal(1, outer) 106 assert_equal(2, inner) 107 } 108 assert_equal(1, outer) 109enddef 110 111func Test_block_failure() 112 call CheckDefFailure(['{', 'let inner = 1', '}', 'echo inner'], 'E1001:') 113endfunc 114 115def ReturnString(): string 116 return 'string' 117enddef 118 119def ReturnNumber(): number 120 return 123 121enddef 122 123let g:notNumber = 'string' 124 125def ReturnGlobal(): number 126 return g:notNumber 127enddef 128 129def Test_return_string() 130 assert_equal('string', ReturnString()) 131 assert_equal(123, ReturnNumber()) 132 assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string') 133enddef 134 135func Increment() 136 let g:counter += 1 137endfunc 138 139def Test_call_ufunc_count() 140 g:counter = 1 141 Increment() 142 Increment() 143 Increment() 144 " works with and without :call 145 assert_equal(4, g:counter) 146 call assert_equal(4, g:counter) 147 unlet g:counter 148enddef 149 150def MyVarargs(arg: string, ...rest: list<string>): string 151 let res = arg 152 for s in rest 153 res ..= ',' .. s 154 endfor 155 return res 156enddef 157 158def Test_call_varargs() 159 assert_equal('one', MyVarargs('one')) 160 assert_equal('one,two', MyVarargs('one', 'two')) 161 assert_equal('one,two,three', MyVarargs('one', 'two', 'three')) 162enddef 163 164def MyDefaultArgs(name = 'string'): string 165 return name 166enddef 167 168def Test_call_default_args() 169 assert_equal('string', MyDefaultArgs()) 170 assert_equal('one', MyDefaultArgs('one')) 171 assert_fails('call MyDefaultArgs("one", "two")', 'E118:') 172enddef 173 174func Test_call_default_args_from_func() 175 call assert_equal('string', MyDefaultArgs()) 176 call assert_equal('one', MyDefaultArgs('one')) 177 call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') 178endfunc 179 180" Default arg and varargs 181def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string 182 let res = one .. ',' .. two 183 for s in rest 184 res ..= ',' .. s 185 endfor 186 return res 187enddef 188 189def Test_call_def_varargs() 190 call assert_fails('call MyDefVarargs()', 'E119:') 191 assert_equal('one,foo', MyDefVarargs('one')) 192 assert_equal('one,two', MyDefVarargs('one', 'two')) 193 assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) 194enddef 195 196 197"def Test_call_func_defined_later() 198" call assert_equal('one', DefineLater('one')) 199" call assert_fails('call NotDefined("one")', 'E99:') 200"enddef 201 202func DefineLater(arg) 203 return a:arg 204endfunc 205 206def Test_return_type_wrong() 207 CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') 208 CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') 209 CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') 210 CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') 211enddef 212 213def Test_arg_type_wrong() 214 CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>') 215enddef 216 217def Test_try_catch() 218 let l = [] 219 try 220 add(l, '1') 221 throw 'wrong' 222 add(l, '2') 223 catch 224 add(l, v:exception) 225 finally 226 add(l, '3') 227 endtry 228 assert_equal(['1', 'wrong', '3'], l) 229enddef 230 231def ThrowFromDef() 232 throw 'getout' 233enddef 234 235func CatchInFunc() 236 try 237 call ThrowFromDef() 238 catch 239 let g:thrown_func = v:exception 240 endtry 241endfunc 242 243def CatchInDef() 244 try 245 ThrowFromDef() 246 catch 247 g:thrown_def = v:exception 248 endtry 249enddef 250 251def ReturnFinally(): string 252 try 253 return 'intry' 254 finally 255 g:in_finally = 'finally' 256 endtry 257 return 'end' 258enddef 259 260def Test_try_catch_nested() 261 CatchInFunc() 262 assert_equal('getout', g:thrown_func) 263 264 CatchInDef() 265 assert_equal('getout', g:thrown_def) 266 267 assert_equal('intry', ReturnFinally()) 268 assert_equal('finally', g:in_finally) 269enddef 270 271def Test_try_catch_match() 272 let seq = 'a' 273 try 274 throw 'something' 275 catch /nothing/ 276 seq ..= 'x' 277 catch /some/ 278 seq ..= 'b' 279 catch /asdf/ 280 seq ..= 'x' 281 finally 282 seq ..= 'c' 283 endtry 284 assert_equal('abc', seq) 285enddef 286 287let s:export_script_lines =<< trim END 288 vim9script 289 let name: string = 'bob' 290 def Concat(arg: string): string 291 return name .. arg 292 enddef 293 let g:result = Concat('bie') 294 let g:localname = name 295 296 export const CONST = 1234 297 export let exported = 9876 298 export let exp_name = 'John' 299 export def Exported(): string 300 return 'Exported' 301 enddef 302END 303 304def Test_vim9script() 305 let import_script_lines =<< trim END 306 vim9script 307 import {exported, Exported} from './Xexport.vim' 308 g:imported = exported 309 exported += 3 310 g:imported_added = exported 311 g:imported_func = Exported() 312 313 import {exp_name} from './Xexport.vim' 314 g:imported_name = exp_name 315 exp_name ..= ' Doe' 316 g:imported_name_appended = exp_name 317 END 318 319 writefile(import_script_lines, 'Ximport.vim') 320 writefile(s:export_script_lines, 'Xexport.vim') 321 322 source Ximport.vim 323 324 assert_equal('bobbie', g:result) 325 assert_equal('bob', g:localname) 326 assert_equal(9876, g:imported) 327 assert_equal(9879, g:imported_added) 328 assert_equal('Exported', g:imported_func) 329 assert_equal('John', g:imported_name) 330 assert_equal('John Doe', g:imported_name_appended) 331 assert_false(exists('g:name')) 332 333 unlet g:result 334 unlet g:localname 335 unlet g:imported 336 unlet g:imported_added 337 unlet g:imported_func 338 unlet g:imported_name g:imported_name_appended 339 delete('Ximport.vim') 340 341 let import_star_as_lines =<< trim END 342 vim9script 343 import * as Export from './Xexport.vim' 344 def UseExport() 345 g:imported = Export.exported 346 enddef 347 UseExport() 348 END 349 writefile(import_star_as_lines, 'Ximport.vim') 350 source Ximport.vim 351 assert_equal(9876, g:imported) 352 353 let import_star_lines =<< trim END 354 vim9script 355 import * from './Xexport.vim' 356 g:imported = exported 357 END 358 writefile(import_star_lines, 'Ximport.vim') 359 assert_fails('source Ximport.vim', 'E1045:') 360 361 " try to import something that exists but is not exported 362 let import_not_exported_lines =<< trim END 363 vim9script 364 import name from './Xexport.vim' 365 END 366 writefile(import_not_exported_lines, 'Ximport.vim') 367 assert_fails('source Ximport.vim', 'E1049:') 368 369 " import a very long name, requires making a copy 370 let import_long_name_lines =<< trim END 371 vim9script 372 import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim' 373 END 374 writefile(import_long_name_lines, 'Ximport.vim') 375 assert_fails('source Ximport.vim', 'E1048:') 376 377 let import_no_from_lines =<< trim END 378 vim9script 379 import name './Xexport.vim' 380 END 381 writefile(import_no_from_lines, 'Ximport.vim') 382 assert_fails('source Ximport.vim', 'E1070:') 383 384 let import_invalid_string_lines =<< trim END 385 vim9script 386 import name from Xexport.vim 387 END 388 writefile(import_invalid_string_lines, 'Ximport.vim') 389 assert_fails('source Ximport.vim', 'E1071:') 390 391 let import_wrong_name_lines =<< trim END 392 vim9script 393 import name from './XnoExport.vim' 394 END 395 writefile(import_wrong_name_lines, 'Ximport.vim') 396 assert_fails('source Ximport.vim', 'E1053:') 397 398 let import_missing_comma_lines =<< trim END 399 vim9script 400 import {exported name} from './Xexport.vim' 401 END 402 writefile(import_missing_comma_lines, 'Ximport.vim') 403 assert_fails('source Ximport.vim', 'E1046:') 404 405 delete('Ximport.vim') 406 delete('Xexport.vim') 407 408 " Check that in a Vim9 script 'cpo' is set to the Vim default. 409 set cpo&vi 410 let cpo_before = &cpo 411 let lines =<< trim END 412 vim9script 413 g:cpo_in_vim9script = &cpo 414 END 415 writefile(lines, 'Xvim9_script') 416 source Xvim9_script 417 assert_equal(cpo_before, &cpo) 418 set cpo&vim 419 assert_equal(&cpo, g:cpo_in_vim9script) 420 delete('Xvim9_script') 421enddef 422 423def Test_vim9script_fails() 424 CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') 425 CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') 426 CheckScriptFailure(['export let some = 123'], 'E1042:') 427 CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1042:') 428 CheckScriptFailure(['vim9script', 'export let g:some'], 'E1044:') 429 CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') 430 431 assert_fails('vim9script', 'E1038') 432 assert_fails('export something', 'E1042') 433enddef 434 435def Test_vim9script_call() 436 let lines =<< trim END 437 vim9script 438 let var = '' 439 def MyFunc(arg: string) 440 var = arg 441 enddef 442 MyFunc('foobar') 443 assert_equal('foobar', var) 444 445 let str = 'barfoo' 446 str->MyFunc() 447 assert_equal('barfoo', var) 448 449 let g:value = 'value' 450 g:value->MyFunc() 451 assert_equal('value', var) 452 453 let listvar = [] 454 def ListFunc(arg: list<number>) 455 listvar = arg 456 enddef 457 [1, 2, 3]->ListFunc() 458 assert_equal([1, 2, 3], listvar) 459 460 let dictvar = {} 461 def DictFunc(arg: dict<number>) 462 dictvar = arg 463 enddef 464 {'a': 1, 'b': 2}->DictFunc() 465 assert_equal(#{a: 1, b: 2}, dictvar) 466 #{a: 3, b: 4}->DictFunc() 467 assert_equal(#{a: 3, b: 4}, dictvar) 468 469 ('text')->MyFunc() 470 assert_equal('text', var) 471 ("some")->MyFunc() 472 assert_equal('some', var) 473 END 474 writefile(lines, 'Xcall.vim') 475 source Xcall.vim 476 delete('Xcall.vim') 477enddef 478 479def Test_vim9script_call_fail_decl() 480 let lines =<< trim END 481 vim9script 482 let var = '' 483 def MyFunc(arg: string) 484 let var = 123 485 enddef 486 END 487 writefile(lines, 'Xcall_decl.vim') 488 assert_fails('source Xcall_decl.vim', 'E1054:') 489 delete('Xcall_decl.vim') 490enddef 491 492def Test_vim9script_call_fail_const() 493 let lines =<< trim END 494 vim9script 495 const var = '' 496 def MyFunc(arg: string) 497 var = 'asdf' 498 enddef 499 END 500 writefile(lines, 'Xcall_const.vim') 501 assert_fails('source Xcall_const.vim', 'E46:') 502 delete('Xcall_const.vim') 503enddef 504 505def Test_vim9script_reload() 506 let lines =<< trim END 507 vim9script 508 const var = '' 509 let valone = 1234 510 def MyFunc(arg: string) 511 valone = 5678 512 enddef 513 END 514 let morelines =<< trim END 515 let valtwo = 222 516 export def GetValtwo(): number 517 return valtwo 518 enddef 519 END 520 writefile(lines + morelines, 'Xreload.vim') 521 source Xreload.vim 522 source Xreload.vim 523 source Xreload.vim 524 525 let testlines =<< trim END 526 vim9script 527 def TheFunc() 528 import GetValtwo from './Xreload.vim' 529 assert_equal(222, GetValtwo()) 530 enddef 531 TheFunc() 532 END 533 writefile(testlines, 'Ximport.vim') 534 source Ximport.vim 535 536 " test that when not using "morelines" valtwo is still defined 537 " need to source Xreload.vim again, import doesn't reload a script 538 writefile(lines, 'Xreload.vim') 539 source Xreload.vim 540 source Ximport.vim 541 542 " cannot declare a var twice 543 lines =<< trim END 544 vim9script 545 let valone = 1234 546 let valone = 5678 547 END 548 writefile(lines, 'Xreload.vim') 549 assert_fails('source Xreload.vim', 'E1041:') 550 551 delete('Xreload.vim') 552 delete('Ximport.vim') 553enddef 554 555def Test_import_absolute() 556 let import_lines = [ 557 \ 'vim9script', 558 \ 'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"', 559 \ 'def UseExported()', 560 \ ' g:imported_abs = exported', 561 \ ' exported = 8888', 562 \ ' g:imported_after = exported', 563 \ 'enddef', 564 \ 'UseExported()', 565 \ 'g:import_disassembled = execute("disass UseExported")', 566 \ ] 567 writefile(import_lines, 'Ximport_abs.vim') 568 writefile(s:export_script_lines, 'Xexport_abs.vim') 569 570 source Ximport_abs.vim 571 572 assert_equal(9876, g:imported_abs) 573 assert_equal(8888, g:imported_after) 574 assert_match('<SNR>\d\+_UseExported.*' 575 \ .. 'g:imported_abs = exported.*' 576 \ .. '0 LOADSCRIPT exported from .*Xexport_abs.vim.*' 577 \ .. '1 STOREG g:imported_abs.*' 578 \ .. 'exported = 8888.*' 579 \ .. '3 STORESCRIPT exported in .*Xexport_abs.vim.*' 580 \ .. 'g:imported_after = exported.*' 581 \ .. '4 LOADSCRIPT exported from .*Xexport_abs.vim.*' 582 \ .. '5 STOREG g:imported_after.*' 583 \, g:import_disassembled) 584 unlet g:imported_abs 585 unlet g:import_disassembled 586 587 delete('Ximport_abs.vim') 588 delete('Xexport_abs.vim') 589enddef 590 591def Test_import_rtp() 592 let import_lines = [ 593 \ 'vim9script', 594 \ 'import exported from "Xexport_rtp.vim"', 595 \ 'g:imported_rtp = exported', 596 \ ] 597 writefile(import_lines, 'Ximport_rtp.vim') 598 mkdir('import') 599 writefile(s:export_script_lines, 'import/Xexport_rtp.vim') 600 601 let save_rtp = &rtp 602 &rtp = getcwd() 603 source Ximport_rtp.vim 604 &rtp = save_rtp 605 606 assert_equal(9876, g:imported_rtp) 607 unlet g:imported_rtp 608 609 delete('Ximport_rtp.vim') 610 delete('import/Xexport_rtp.vim') 611 delete('import', 'd') 612enddef 613 614def Test_fixed_size_list() 615 " will be allocated as one piece of memory, check that changes work 616 let l = [1, 2, 3, 4] 617 l->remove(0) 618 l->add(5) 619 l->insert(99, 1) 620 assert_equal([2, 99, 3, 4, 5], l) 621enddef 622 623" Test that inside :function a Python function can be defined, :def is not 624" recognized. 625func Test_function_python() 626 CheckFeature python3 627 let py = 'python3' 628 execute py "<< EOF" 629def do_something(): 630 return 1 631EOF 632endfunc 633 634def IfElse(what: number): string 635 let res = '' 636 if what == 1 637 res = "one" 638 elseif what == 2 639 res = "two" 640 else 641 res = "three" 642 endif 643 return res 644enddef 645 646def Test_if_elseif_else() 647 assert_equal('one', IfElse(1)) 648 assert_equal('two', IfElse(2)) 649 assert_equal('three', IfElse(3)) 650enddef 651 652def Test_delfunc() 653 let lines =<< trim END 654 vim9script 655 def GoneSoon() 656 echo 'hello' 657 enddef 658 659 def CallGoneSoon() 660 GoneSoon() 661 enddef 662 663 delfunc GoneSoon 664 CallGoneSoon() 665 END 666 writefile(lines, 'XToDelFunc') 667 assert_fails('so XToDelFunc', 'E933') 668 assert_fails('so XToDelFunc', 'E933') 669 670 delete('XToDelFunc') 671enddef 672 673def Test_substitute_cmd() 674 new 675 setline(1, 'something') 676 :substitute(some(other( 677 assert_equal('otherthing', getline(1)) 678 bwipe! 679 680 " also when the context is Vim9 script 681 let lines =<< trim END 682 vim9script 683 new 684 setline(1, 'something') 685 :substitute(some(other( 686 assert_equal('otherthing', getline(1)) 687 bwipe! 688 END 689 writefile(lines, 'Xvim9lines') 690 source Xvim9lines 691 692 delete('Xvim9lines') 693enddef 694 695 696" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 697