1" Test the :disassemble command, and compilation as a side effect 2 3source check.vim 4 5func NotCompiled() 6 echo "not" 7endfunc 8 9let s:scriptvar = 4 10let g:globalvar = 'g' 11let b:buffervar = 'b' 12let w:windowvar = 'w' 13let t:tabpagevar = 't' 14 15def s:ScriptFuncLoad(arg: string) 16 var local = 1 17 buffers 18 echo 19 echo arg 20 echo local 21 echo &lines 22 echo v:version 23 echo s:scriptvar 24 echo g:globalvar 25 echo get(g:, "global") 26 echo g:auto#var 27 echo b:buffervar 28 echo get(b:, "buffer") 29 echo w:windowvar 30 echo get(w:, "window") 31 echo t:tabpagevar 32 echo get(t:, "tab") 33 echo &tabstop 34 echo $ENVVAR 35 echo @z 36enddef 37 38def Test_disassemble_load() 39 assert_fails('disass NoFunc', 'E1061:') 40 assert_fails('disass NotCompiled', 'E1091:') 41 assert_fails('disass', 'E471:') 42 assert_fails('disass [', 'E475:') 43 assert_fails('disass 234', 'E129:') 44 assert_fails('disass <XX>foo', 'E129:') 45 46 var res = execute('disass s:ScriptFuncLoad') 47 assert_match('<SNR>\d*_ScriptFuncLoad.*' .. 48 'buffers\_s*' .. 49 '\d\+ EXEC \+buffers\_s*' .. 50 'echo\_s*' .. 51 'echo arg\_s*' .. 52 '\d\+ LOAD arg\[-1\]\_s*' .. 53 '\d\+ ECHO 1\_s*' .. 54 'echo local\_s*' .. 55 '\d\+ LOAD $0\_s*' .. 56 '\d\+ ECHO 1\_s*' .. 57 'echo &lines\_s*' .. 58 '\d\+ LOADOPT &lines\_s*' .. 59 '\d\+ ECHO 1\_s*' .. 60 'echo v:version\_s*' .. 61 '\d\+ LOADV v:version\_s*' .. 62 '\d\+ ECHO 1\_s*' .. 63 'echo s:scriptvar\_s*' .. 64 '\d\+ LOADS s:scriptvar from .*test_vim9_disassemble.vim\_s*' .. 65 '\d\+ ECHO 1\_s*' .. 66 'echo g:globalvar\_s*' .. 67 '\d\+ LOADG g:globalvar\_s*' .. 68 '\d\+ ECHO 1\_s*' .. 69 'echo get(g:, "global")\_s*' .. 70 '\d\+ LOAD g:\_s*' .. 71 '\d\+ PUSHS "global"\_s*' .. 72 '\d\+ BCALL get(argc 2)\_s*' .. 73 '\d\+ ECHO 1\_s*' .. 74 'echo g:auto#var\_s*' .. 75 '\d\+ LOADAUTO g:auto#var\_s*' .. 76 '\d\+ ECHO 1\_s*' .. 77 'echo b:buffervar\_s*' .. 78 '\d\+ LOADB b:buffervar\_s*' .. 79 '\d\+ ECHO 1\_s*' .. 80 'echo get(b:, "buffer")\_s*' .. 81 '\d\+ LOAD b:\_s*' .. 82 '\d\+ PUSHS "buffer"\_s*' .. 83 '\d\+ BCALL get(argc 2).*' .. 84 ' LOADW w:windowvar.*' .. 85 'echo get(w:, "window")\_s*' .. 86 '\d\+ LOAD w:\_s*' .. 87 '\d\+ PUSHS "window"\_s*' .. 88 '\d\+ BCALL get(argc 2).*' .. 89 ' LOADT t:tabpagevar.*' .. 90 'echo get(t:, "tab")\_s*' .. 91 '\d\+ LOAD t:\_s*' .. 92 '\d\+ PUSHS "tab"\_s*' .. 93 '\d\+ BCALL get(argc 2).*' .. 94 ' LOADENV $ENVVAR.*' .. 95 ' LOADREG @z.*', 96 res) 97enddef 98 99def s:EditExpand() 100 var filename = "file" 101 var filenr = 123 102 edit the`=filename``=filenr`.txt 103enddef 104 105def Test_disassemble_exec_expr() 106 var res = execute('disass s:EditExpand') 107 assert_match('<SNR>\d*_EditExpand\_s*' .. 108 ' var filename = "file"\_s*' .. 109 '\d PUSHS "file"\_s*' .. 110 '\d STORE $0\_s*' .. 111 ' var filenr = 123\_s*' .. 112 '\d STORE 123 in $1\_s*' .. 113 ' edit the`=filename``=filenr`.txt\_s*' .. 114 '\d PUSHS "edit the"\_s*' .. 115 '\d LOAD $0\_s*' .. 116 '\d LOAD $1\_s*' .. 117 '\d 2STRING stack\[-1\]\_s*' .. 118 '\d\+ PUSHS ".txt"\_s*' .. 119 '\d\+ EXECCONCAT 4\_s*' .. 120 '\d\+ RETURN 0', 121 res) 122enddef 123 124def s:YankRange() 125 norm! m[jjm] 126 :'[,']yank 127enddef 128 129def Test_disassemble_yank_range() 130 var res = execute('disass s:YankRange') 131 assert_match('<SNR>\d*_YankRange.*' .. 132 ' norm! m\[jjm\]\_s*' .. 133 '\d EXEC norm! m\[jjm\]\_s*' .. 134 ' :''\[,''\]yank\_s*' .. 135 '\d EXEC :''\[,''\]yank\_s*' .. 136 '\d RETURN 0', 137 res) 138enddef 139 140def s:PutExpr() 141 :3put ="text" 142enddef 143 144def Test_disassemble_put_expr() 145 var res = execute('disass s:PutExpr') 146 assert_match('<SNR>\d*_PutExpr.*' .. 147 ' :3put ="text"\_s*' .. 148 '\d PUSHS "text"\_s*' .. 149 '\d PUT = 3\_s*' .. 150 '\d RETURN 0', 151 res) 152enddef 153 154def s:PutRange() 155 :$-2put a 156enddef 157 158def Test_disassemble_put_range() 159 var res = execute('disass s:PutRange') 160 assert_match('<SNR>\d*_PutRange.*' .. 161 ' :$-2put a\_s*' .. 162 '\d RANGE $-2\_s*' .. 163 '\d PUT a range\_s*' .. 164 '\d RETURN 0', 165 res) 166enddef 167 168def s:ScriptFuncPush() 169 var localbool = true 170 var localspec = v:none 171 var localblob = 0z1234 172 if has('float') 173 var localfloat = 1.234 174 endif 175enddef 176 177def Test_disassemble_push() 178 var res = execute('disass s:ScriptFuncPush') 179 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 180 'localbool = true.*' .. 181 ' PUSH true.*' .. 182 'localspec = v:none.*' .. 183 ' PUSH v:none.*' .. 184 'localblob = 0z1234.*' .. 185 ' PUSHBLOB 0z1234.*', 186 res) 187 if has('float') 188 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 189 'localfloat = 1.234.*' .. 190 ' PUSHF 1.234.*', 191 res) 192 endif 193enddef 194 195def s:ScriptFuncStore() 196 var localnr = 1 197 localnr = 2 198 var localstr = 'abc' 199 localstr = 'xyz' 200 v:char = 'abc' 201 s:scriptvar = 'sv' 202 g:globalvar = 'gv' 203 g:auto#var = 'av' 204 b:buffervar = 'bv' 205 w:windowvar = 'wv' 206 t:tabpagevar = 'tv' 207 &tabstop = 8 208 $ENVVAR = 'ev' 209 @z = 'rv' 210enddef 211 212def Test_disassemble_store() 213 var res = execute('disass s:ScriptFuncStore') 214 assert_match('<SNR>\d*_ScriptFuncStore.*' .. 215 'var localnr = 1.*' .. 216 'localnr = 2.*' .. 217 ' STORE 2 in $0.*' .. 218 'var localstr = ''abc''.*' .. 219 'localstr = ''xyz''.*' .. 220 ' STORE $1.*' .. 221 'v:char = ''abc''.*' .. 222 'STOREV v:char.*' .. 223 's:scriptvar = ''sv''.*' .. 224 ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' .. 225 'g:globalvar = ''gv''.*' .. 226 ' STOREG g:globalvar.*' .. 227 'g:auto#var = ''av''.*' .. 228 ' STOREAUTO g:auto#var.*' .. 229 'b:buffervar = ''bv''.*' .. 230 ' STOREB b:buffervar.*' .. 231 'w:windowvar = ''wv''.*' .. 232 ' STOREW w:windowvar.*' .. 233 't:tabpagevar = ''tv''.*' .. 234 ' STORET t:tabpagevar.*' .. 235 '&tabstop = 8.*' .. 236 ' STOREOPT &tabstop.*' .. 237 '$ENVVAR = ''ev''.*' .. 238 ' STOREENV $ENVVAR.*' .. 239 '@z = ''rv''.*' .. 240 ' STOREREG @z.*', 241 res) 242enddef 243 244def s:ScriptFuncStoreMember() 245 var locallist: list<number> = [] 246 locallist[0] = 123 247 var localdict: dict<number> = {} 248 localdict["a"] = 456 249enddef 250 251def Test_disassemble_store_member() 252 var res = execute('disass s:ScriptFuncStoreMember') 253 assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' .. 254 'var locallist: list<number> = []\_s*' .. 255 '\d NEWLIST size 0\_s*' .. 256 '\d SETTYPE list<number>\_s*' .. 257 '\d STORE $0\_s*' .. 258 'locallist\[0\] = 123\_s*' .. 259 '\d PUSHNR 123\_s*' .. 260 '\d PUSHNR 0\_s*' .. 261 '\d LOAD $0\_s*' .. 262 '\d STORELIST\_s*' .. 263 'var localdict: dict<number> = {}\_s*' .. 264 '\d NEWDICT size 0\_s*' .. 265 '\d SETTYPE dict<number>\_s*' .. 266 '\d STORE $1\_s*' .. 267 'localdict\["a"\] = 456\_s*' .. 268 '\d\+ PUSHNR 456\_s*' .. 269 '\d\+ PUSHS "a"\_s*' .. 270 '\d\+ LOAD $1\_s*' .. 271 '\d\+ STOREDICT\_s*' .. 272 '\d\+ RETURN 0', 273 res) 274enddef 275 276def s:ScriptFuncStoreIndex() 277 var d = {dd: {}} 278 d.dd[0] = 0 279enddef 280 281def Test_disassemble_store_index() 282 var res = execute('disass s:ScriptFuncStoreIndex') 283 assert_match('<SNR>\d*_ScriptFuncStoreIndex\_s*' .. 284 'var d = {dd: {}}\_s*' .. 285 '\d PUSHS "dd"\_s*' .. 286 '\d NEWDICT size 0\_s*' .. 287 '\d NEWDICT size 1\_s*' .. 288 '\d STORE $0\_s*' .. 289 'd.dd\[0\] = 0\_s*' .. 290 '\d PUSHNR 0\_s*' .. 291 '\d PUSHNR 0\_s*' .. 292 '\d LOAD $0\_s*' .. 293 '\d MEMBER dd\_s*' .. 294 '\d STOREINDEX\_s*' .. 295 '\d\+ RETURN 0', 296 res) 297enddef 298 299def s:ListAssign() 300 var x: string 301 var y: string 302 var l: list<any> 303 [x, y; l] = g:stringlist 304enddef 305 306def Test_disassemble_list_assign() 307 var res = execute('disass s:ListAssign') 308 assert_match('<SNR>\d*_ListAssign\_s*' .. 309 'var x: string\_s*' .. 310 '\d PUSHS "\[NULL\]"\_s*' .. 311 '\d STORE $0\_s*' .. 312 'var y: string\_s*' .. 313 '\d PUSHS "\[NULL\]"\_s*' .. 314 '\d STORE $1\_s*' .. 315 'var l: list<any>\_s*' .. 316 '\d NEWLIST size 0\_s*' .. 317 '\d STORE $2\_s*' .. 318 '\[x, y; l\] = g:stringlist\_s*' .. 319 '\d LOADG g:stringlist\_s*' .. 320 '\d CHECKTYPE list<any> stack\[-1\]\_s*' .. 321 '\d CHECKLEN >= 2\_s*' .. 322 '\d\+ ITEM 0\_s*' .. 323 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 324 '\d\+ STORE $0\_s*' .. 325 '\d\+ ITEM 1\_s*' .. 326 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 327 '\d\+ STORE $1\_s*' .. 328 '\d\+ SLICE 2\_s*' .. 329 '\d\+ STORE $2\_s*' .. 330 '\d\+ RETURN 0', 331 res) 332enddef 333 334def s:ListAdd() 335 var l: list<number> = [] 336 add(l, 123) 337 add(l, g:aNumber) 338enddef 339 340def Test_disassemble_list_add() 341 var res = execute('disass s:ListAdd') 342 assert_match('<SNR>\d*_ListAdd\_s*' .. 343 'var l: list<number> = []\_s*' .. 344 '\d NEWLIST size 0\_s*' .. 345 '\d SETTYPE list<number>\_s*' .. 346 '\d STORE $0\_s*' .. 347 'add(l, 123)\_s*' .. 348 '\d LOAD $0\_s*' .. 349 '\d PUSHNR 123\_s*' .. 350 '\d LISTAPPEND\_s*' .. 351 '\d DROP\_s*' .. 352 'add(l, g:aNumber)\_s*' .. 353 '\d LOAD $0\_s*' .. 354 '\d\+ LOADG g:aNumber\_s*' .. 355 '\d\+ CHECKTYPE number stack\[-1\]\_s*' .. 356 '\d\+ LISTAPPEND\_s*' .. 357 '\d\+ DROP\_s*' .. 358 '\d\+ RETURN 0', 359 res) 360enddef 361 362def s:BlobAdd() 363 var b: blob = 0z 364 add(b, 123) 365 add(b, g:aNumber) 366enddef 367 368def Test_disassemble_blob_add() 369 var res = execute('disass s:BlobAdd') 370 assert_match('<SNR>\d*_BlobAdd\_s*' .. 371 'var b: blob = 0z\_s*' .. 372 '\d PUSHBLOB 0z\_s*' .. 373 '\d STORE $0\_s*' .. 374 'add(b, 123)\_s*' .. 375 '\d LOAD $0\_s*' .. 376 '\d PUSHNR 123\_s*' .. 377 '\d BLOBAPPEND\_s*' .. 378 '\d DROP\_s*' .. 379 'add(b, g:aNumber)\_s*' .. 380 '\d LOAD $0\_s*' .. 381 '\d\+ LOADG g:aNumber\_s*' .. 382 '\d\+ CHECKTYPE number stack\[-1\]\_s*' .. 383 '\d\+ BLOBAPPEND\_s*' .. 384 '\d\+ DROP\_s*' .. 385 '\d\+ RETURN 0', 386 res) 387enddef 388 389def s:ScriptFuncUnlet() 390 g:somevar = "value" 391 unlet g:somevar 392 unlet! g:somevar 393 unlet $SOMEVAR 394enddef 395 396def Test_disassemble_unlet() 397 var res = execute('disass s:ScriptFuncUnlet') 398 assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' .. 399 'g:somevar = "value"\_s*' .. 400 '\d PUSHS "value"\_s*' .. 401 '\d STOREG g:somevar\_s*' .. 402 'unlet g:somevar\_s*' .. 403 '\d UNLET g:somevar\_s*' .. 404 'unlet! g:somevar\_s*' .. 405 '\d UNLET! g:somevar\_s*' .. 406 'unlet $SOMEVAR\_s*' .. 407 '\d UNLETENV $SOMEVAR\_s*', 408 res) 409enddef 410 411def s:ScriptFuncTry() 412 try 413 echo "yes" 414 catch /fail/ 415 echo "no" 416 finally 417 throw "end" 418 endtry 419enddef 420 421def Test_disassemble_try() 422 var res = execute('disass s:ScriptFuncTry') 423 assert_match('<SNR>\d*_ScriptFuncTry\_s*' .. 424 'try\_s*' .. 425 '\d TRY catch -> \d\+, finally -> \d\+, endtry -> \d\+\_s*' .. 426 'echo "yes"\_s*' .. 427 '\d PUSHS "yes"\_s*' .. 428 '\d ECHO 1\_s*' .. 429 'catch /fail/\_s*' .. 430 '\d JUMP -> \d\+\_s*' .. 431 '\d PUSH v:exception\_s*' .. 432 '\d PUSHS "fail"\_s*' .. 433 '\d COMPARESTRING =\~\_s*' .. 434 '\d JUMP_IF_FALSE -> \d\+\_s*' .. 435 '\d CATCH\_s*' .. 436 'echo "no"\_s*' .. 437 '\d\+ PUSHS "no"\_s*' .. 438 '\d\+ ECHO 1\_s*' .. 439 'finally\_s*' .. 440 '\d\+ FINALLY\_s*' .. 441 'throw "end"\_s*' .. 442 '\d\+ PUSHS "end"\_s*' .. 443 '\d\+ THROW\_s*' .. 444 'endtry\_s*' .. 445 '\d\+ ENDTRY', 446 res) 447enddef 448 449def s:ScriptFuncNew() 450 var ll = [1, "two", 333] 451 var dd = {one: 1, two: "val"} 452enddef 453 454def Test_disassemble_new() 455 var res = execute('disass s:ScriptFuncNew') 456 assert_match('<SNR>\d*_ScriptFuncNew\_s*' .. 457 'var ll = \[1, "two", 333\]\_s*' .. 458 '\d PUSHNR 1\_s*' .. 459 '\d PUSHS "two"\_s*' .. 460 '\d PUSHNR 333\_s*' .. 461 '\d NEWLIST size 3\_s*' .. 462 '\d STORE $0\_s*' .. 463 'var dd = {one: 1, two: "val"}\_s*' .. 464 '\d PUSHS "one"\_s*' .. 465 '\d PUSHNR 1\_s*' .. 466 '\d PUSHS "two"\_s*' .. 467 '\d PUSHS "val"\_s*' .. 468 '\d NEWDICT size 2\_s*', 469 res) 470enddef 471 472def FuncWithArg(arg: any) 473 echo arg 474enddef 475 476func UserFunc() 477 echo 'nothing' 478endfunc 479 480func UserFuncWithArg(arg) 481 echo a:arg 482endfunc 483 484def s:ScriptFuncCall(): string 485 changenr() 486 char2nr("abc") 487 Test_disassemble_new() 488 FuncWithArg(343) 489 ScriptFuncNew() 490 s:ScriptFuncNew() 491 UserFunc() 492 UserFuncWithArg("foo") 493 var FuncRef = function("UserFunc") 494 FuncRef() 495 var FuncRefWithArg = function("UserFuncWithArg") 496 FuncRefWithArg("bar") 497 return "yes" 498enddef 499 500def Test_disassemble_call() 501 var res = execute('disass s:ScriptFuncCall') 502 assert_match('<SNR>\d\+_ScriptFuncCall\_s*' .. 503 'changenr()\_s*' .. 504 '\d BCALL changenr(argc 0)\_s*' .. 505 '\d DROP\_s*' .. 506 'char2nr("abc")\_s*' .. 507 '\d PUSHS "abc"\_s*' .. 508 '\d BCALL char2nr(argc 1)\_s*' .. 509 '\d DROP\_s*' .. 510 'Test_disassemble_new()\_s*' .. 511 '\d DCALL Test_disassemble_new(argc 0)\_s*' .. 512 '\d DROP\_s*' .. 513 'FuncWithArg(343)\_s*' .. 514 '\d\+ PUSHNR 343\_s*' .. 515 '\d\+ DCALL FuncWithArg(argc 1)\_s*' .. 516 '\d\+ DROP\_s*' .. 517 'ScriptFuncNew()\_s*' .. 518 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 519 '\d\+ DROP\_s*' .. 520 's:ScriptFuncNew()\_s*' .. 521 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 522 '\d\+ DROP\_s*' .. 523 'UserFunc()\_s*' .. 524 '\d\+ UCALL UserFunc(argc 0)\_s*' .. 525 '\d\+ DROP\_s*' .. 526 'UserFuncWithArg("foo")\_s*' .. 527 '\d\+ PUSHS "foo"\_s*' .. 528 '\d\+ UCALL UserFuncWithArg(argc 1)\_s*' .. 529 '\d\+ DROP\_s*' .. 530 'var FuncRef = function("UserFunc")\_s*' .. 531 '\d\+ PUSHS "UserFunc"\_s*' .. 532 '\d\+ BCALL function(argc 1)\_s*' .. 533 '\d\+ STORE $0\_s*' .. 534 'FuncRef()\_s*' .. 535 '\d\+ LOAD $\d\_s*' .. 536 '\d\+ PCALL (argc 0)\_s*' .. 537 '\d\+ DROP\_s*' .. 538 'var FuncRefWithArg = function("UserFuncWithArg")\_s*' .. 539 '\d\+ PUSHS "UserFuncWithArg"\_s*' .. 540 '\d\+ BCALL function(argc 1)\_s*' .. 541 '\d\+ STORE $1\_s*' .. 542 'FuncRefWithArg("bar")\_s*' .. 543 '\d\+ PUSHS "bar"\_s*' .. 544 '\d\+ LOAD $\d\_s*' .. 545 '\d\+ PCALL (argc 1)\_s*' .. 546 '\d\+ DROP\_s*' .. 547 'return "yes"\_s*' .. 548 '\d\+ PUSHS "yes"\_s*' .. 549 '\d\+ RETURN', 550 res) 551enddef 552 553 554def s:CreateRefs() 555 var local = 'a' 556 def Append(arg: string) 557 local ..= arg 558 enddef 559 g:Append = Append 560 def Get(): string 561 return local 562 enddef 563 g:Get = Get 564enddef 565 566def Test_disassemble_closure() 567 CreateRefs() 568 var res = execute('disass g:Append') 569 assert_match('<lambda>\d\_s*' .. 570 'local ..= arg\_s*' .. 571 '\d LOADOUTER level 1 $0\_s*' .. 572 '\d LOAD arg\[-1\]\_s*' .. 573 '\d CONCAT\_s*' .. 574 '\d STOREOUTER level 1 $0\_s*' .. 575 '\d RETURN 0', 576 res) 577 578 res = execute('disass g:Get') 579 assert_match('<lambda>\d\_s*' .. 580 'return local\_s*' .. 581 '\d LOADOUTER level 1 $0\_s*' .. 582 '\d RETURN', 583 res) 584 585 unlet g:Append 586 unlet g:Get 587enddef 588 589 590def EchoArg(arg: string): string 591 return arg 592enddef 593def RefThis(): func 594 return function('EchoArg') 595enddef 596def s:ScriptPCall() 597 RefThis()("text") 598enddef 599 600def Test_disassemble_pcall() 601 var res = execute('disass s:ScriptPCall') 602 assert_match('<SNR>\d\+_ScriptPCall\_s*' .. 603 'RefThis()("text")\_s*' .. 604 '\d DCALL RefThis(argc 0)\_s*' .. 605 '\d PUSHS "text"\_s*' .. 606 '\d PCALL top (argc 1)\_s*' .. 607 '\d PCALL end\_s*' .. 608 '\d DROP\_s*' .. 609 '\d RETURN 0', 610 res) 611enddef 612 613 614def s:FuncWithForwardCall(): string 615 return g:DefinedLater("yes") 616enddef 617 618def DefinedLater(arg: string): string 619 return arg 620enddef 621 622def Test_disassemble_update_instr() 623 var res = execute('disass s:FuncWithForwardCall') 624 assert_match('FuncWithForwardCall\_s*' .. 625 'return g:DefinedLater("yes")\_s*' .. 626 '\d PUSHS "yes"\_s*' .. 627 '\d DCALL DefinedLater(argc 1)\_s*' .. 628 '\d RETURN', 629 res) 630 631 # Calling the function will change UCALL into the faster DCALL 632 assert_equal('yes', FuncWithForwardCall()) 633 634 res = execute('disass s:FuncWithForwardCall') 635 assert_match('FuncWithForwardCall\_s*' .. 636 'return g:DefinedLater("yes")\_s*' .. 637 '\d PUSHS "yes"\_s*' .. 638 '\d DCALL DefinedLater(argc 1)\_s*' .. 639 '\d RETURN', 640 res) 641enddef 642 643 644def FuncWithDefault(arg: string = 'default'): string 645 return arg 646enddef 647 648def Test_disassemble_call_default() 649 var res = execute('disass FuncWithDefault') 650 assert_match('FuncWithDefault\_s*' .. 651 '\d PUSHS "default"\_s*' .. 652 '\d STORE arg\[-1]\_s*' .. 653 'return arg\_s*' .. 654 '\d LOAD arg\[-1]\_s*' .. 655 '\d RETURN', 656 res) 657enddef 658 659 660def HasEval() 661 if has("eval") 662 echo "yes" 663 else 664 echo "no" 665 endif 666enddef 667 668def HasNothing() 669 if has("nothing") 670 echo "yes" 671 else 672 echo "no" 673 endif 674enddef 675 676def HasSomething() 677 if has("nothing") 678 echo "nothing" 679 elseif has("something") 680 echo "something" 681 elseif has("eval") 682 echo "eval" 683 elseif has("less") 684 echo "less" 685 endif 686enddef 687 688def HasGuiRunning() 689 if has("gui_running") 690 echo "yes" 691 else 692 echo "no" 693 endif 694enddef 695 696def Test_disassemble_const_expr() 697 assert_equal("\nyes", execute('HasEval()')) 698 var instr = execute('disassemble HasEval') 699 assert_match('HasEval\_s*' .. 700 'if has("eval")\_s*' .. 701 'echo "yes"\_s*' .. 702 '\d PUSHS "yes"\_s*' .. 703 '\d ECHO 1\_s*' .. 704 'else\_s*' .. 705 'echo "no"\_s*' .. 706 'endif\_s*', 707 instr) 708 assert_notmatch('JUMP', instr) 709 710 assert_equal("\nno", execute('HasNothing()')) 711 instr = execute('disassemble HasNothing') 712 assert_match('HasNothing\_s*' .. 713 'if has("nothing")\_s*' .. 714 'echo "yes"\_s*' .. 715 'else\_s*' .. 716 'echo "no"\_s*' .. 717 '\d PUSHS "no"\_s*' .. 718 '\d ECHO 1\_s*' .. 719 'endif', 720 instr) 721 assert_notmatch('PUSHS "yes"', instr) 722 assert_notmatch('JUMP', instr) 723 724 assert_equal("\neval", execute('HasSomething()')) 725 instr = execute('disassemble HasSomething') 726 assert_match('HasSomething.*' .. 727 'if has("nothing")\_s*' .. 728 'echo "nothing"\_s*' .. 729 'elseif has("something")\_s*' .. 730 'echo "something"\_s*' .. 731 'elseif has("eval")\_s*' .. 732 'echo "eval"\_s*' .. 733 '\d PUSHS "eval"\_s*' .. 734 '\d ECHO 1\_s*' .. 735 'elseif has("less").*' .. 736 'echo "less"\_s*' .. 737 'endif', 738 instr) 739 assert_notmatch('PUSHS "nothing"', instr) 740 assert_notmatch('PUSHS "something"', instr) 741 assert_notmatch('PUSHS "less"', instr) 742 assert_notmatch('JUMP', instr) 743 744 var result: string 745 var instr_expected: string 746 if has('gui') 747 if has('gui_running') 748 # GUI already running, always returns "yes" 749 result = "\nyes" 750 instr_expected = 'HasGuiRunning.*' .. 751 'if has("gui_running")\_s*' .. 752 ' echo "yes"\_s*' .. 753 '\d PUSHS "yes"\_s*' .. 754 '\d ECHO 1\_s*' .. 755 'else\_s*' .. 756 ' echo "no"\_s*' .. 757 'endif' 758 else 759 result = "\nno" 760 if has('unix') 761 # GUI not running but can start later, call has() 762 instr_expected = 'HasGuiRunning.*' .. 763 'if has("gui_running")\_s*' .. 764 '\d PUSHS "gui_running"\_s*' .. 765 '\d BCALL has(argc 1)\_s*' .. 766 '\d 2BOOL (!!val)\_s*' .. 767 '\d JUMP_IF_FALSE -> \d\_s*' .. 768 ' echo "yes"\_s*' .. 769 '\d PUSHS "yes"\_s*' .. 770 '\d ECHO 1\_s*' .. 771 'else\_s*' .. 772 '\d JUMP -> \d\_s*' .. 773 ' echo "no"\_s*' .. 774 '\d PUSHS "no"\_s*' .. 775 '\d ECHO 1\_s*' .. 776 'endif' 777 else 778 # GUI not running, always return "no" 779 instr_expected = 'HasGuiRunning.*' .. 780 'if has("gui_running")\_s*' .. 781 ' echo "yes"\_s*' .. 782 'else\_s*' .. 783 ' echo "no"\_s*' .. 784 '\d PUSHS "no"\_s*' .. 785 '\d ECHO 1\_s*' .. 786 'endif' 787 endif 788 endif 789 else 790 # GUI not supported, always return "no" 791 result = "\nno" 792 instr_expected = 'HasGuiRunning.*' .. 793 'if has("gui_running")\_s*' .. 794 ' echo "yes"\_s*' .. 795 'else\_s*' .. 796 ' echo "no"\_s*' .. 797 '\d PUSHS "no"\_s*' .. 798 '\d ECHO 1\_s*' .. 799 'endif' 800 endif 801 802 assert_equal(result, execute('HasGuiRunning()')) 803 instr = execute('disassemble HasGuiRunning') 804 assert_match(instr_expected, instr) 805enddef 806 807def ReturnInIf(): string 808 if 1 < 0 809 return "maybe" 810 endif 811 if g:cond 812 return "yes" 813 else 814 return "no" 815 endif 816enddef 817 818def Test_disassemble_return_in_if() 819 var instr = execute('disassemble ReturnInIf') 820 assert_match('ReturnInIf\_s*' .. 821 'if 1 < 0\_s*' .. 822 ' return "maybe"\_s*' .. 823 'endif\_s*' .. 824 'if g:cond\_s*' .. 825 '0 LOADG g:cond\_s*' .. 826 '1 COND2BOOL\_s*' .. 827 '2 JUMP_IF_FALSE -> 5\_s*' .. 828 'return "yes"\_s*' .. 829 '3 PUSHS "yes"\_s*' .. 830 '4 RETURN\_s*' .. 831 'else\_s*' .. 832 ' return "no"\_s*' .. 833 '5 PUSHS "no"\_s*' .. 834 '6 RETURN$', 835 instr) 836enddef 837 838def WithFunc() 839 var Funky1: func 840 var Funky2: func = function("len") 841 var Party2: func = funcref("UserFunc") 842enddef 843 844def Test_disassemble_function() 845 var instr = execute('disassemble WithFunc') 846 assert_match('WithFunc\_s*' .. 847 'var Funky1: func\_s*' .. 848 '0 PUSHFUNC "\[none]"\_s*' .. 849 '1 STORE $0\_s*' .. 850 'var Funky2: func = function("len")\_s*' .. 851 '2 PUSHS "len"\_s*' .. 852 '3 BCALL function(argc 1)\_s*' .. 853 '4 STORE $1\_s*' .. 854 'var Party2: func = funcref("UserFunc")\_s*' .. 855 '\d PUSHS "UserFunc"\_s*' .. 856 '\d BCALL funcref(argc 1)\_s*' .. 857 '\d STORE $2\_s*' .. 858 '\d RETURN 0', 859 instr) 860enddef 861 862if has('channel') 863 def WithChannel() 864 var job1: job 865 var job2: job = job_start("donothing") 866 var chan1: channel 867 enddef 868endif 869 870def Test_disassemble_channel() 871 CheckFeature channel 872 873 var instr = execute('disassemble WithChannel') 874 assert_match('WithChannel\_s*' .. 875 'var job1: job\_s*' .. 876 '\d PUSHJOB "no process"\_s*' .. 877 '\d STORE $0\_s*' .. 878 'var job2: job = job_start("donothing")\_s*' .. 879 '\d PUSHS "donothing"\_s*' .. 880 '\d BCALL job_start(argc 1)\_s*' .. 881 '\d STORE $1\_s*' .. 882 'var chan1: channel\_s*' .. 883 '\d PUSHCHANNEL 0\_s*' .. 884 '\d STORE $2\_s*' .. 885 '\d RETURN 0', 886 instr) 887enddef 888 889def WithLambda(): string 890 var F = (a) => "X" .. a .. "X" 891 return F("x") 892enddef 893 894def Test_disassemble_lambda() 895 assert_equal("XxX", WithLambda()) 896 var instr = execute('disassemble WithLambda') 897 assert_match('WithLambda\_s*' .. 898 'var F = (a) => "X" .. a .. "X"\_s*' .. 899 '\d FUNCREF <lambda>\d\+\_s*' .. 900 '\d STORE $0\_s*' .. 901 'return F("x")\_s*' .. 902 '\d PUSHS "x"\_s*' .. 903 '\d LOAD $0\_s*' .. 904 '\d PCALL (argc 1)\_s*' .. 905 '\d RETURN', 906 instr) 907 908 var name = substitute(instr, '.*\(<lambda>\d\+\).*', '\1', '') 909 instr = execute('disassemble ' .. name) 910 assert_match('<lambda>\d\+\_s*' .. 911 'return "X" .. a .. "X"\_s*' .. 912 '\d PUSHS "X"\_s*' .. 913 '\d LOAD arg\[-1\]\_s*' .. 914 '\d 2STRING_ANY stack\[-1\]\_s*' .. 915 '\d CONCAT\_s*' .. 916 '\d PUSHS "X"\_s*' .. 917 '\d CONCAT\_s*' .. 918 '\d RETURN', 919 instr) 920enddef 921 922def LambdaWithType(): number 923 var Ref = (a: number) => a + 10 924 return Ref(g:value) 925enddef 926 927def Test_disassemble_lambda_with_type() 928 g:value = 5 929 assert_equal(15, LambdaWithType()) 930 var instr = execute('disassemble LambdaWithType') 931 assert_match('LambdaWithType\_s*' .. 932 'var Ref = (a: number) => a + 10\_s*' .. 933 '\d FUNCREF <lambda>\d\+\_s*' .. 934 '\d STORE $0\_s*' .. 935 'return Ref(g:value)\_s*' .. 936 '\d LOADG g:value\_s*' .. 937 '\d LOAD $0\_s*' .. 938 '\d CHECKTYPE number stack\[-2\] arg 1\_s*' .. 939 '\d PCALL (argc 1)\_s*' .. 940 '\d RETURN', 941 instr) 942enddef 943 944def NestedOuter() 945 def g:Inner() 946 echomsg "inner" 947 enddef 948enddef 949 950def Test_nested_func() 951 var instr = execute('disassemble NestedOuter') 952 assert_match('NestedOuter\_s*' .. 953 'def g:Inner()\_s*' .. 954 'echomsg "inner"\_s*' .. 955 'enddef\_s*' .. 956 '\d NEWFUNC <lambda>\d\+ Inner\_s*' .. 957 '\d RETURN 0', 958 instr) 959enddef 960 961def NestedDefList() 962 def 963 def Info 964 def /Info 965 def /Info/ 966enddef 967 968def Test_nested_def_list() 969 var instr = execute('disassemble NestedDefList') 970 assert_match('NestedDefList\_s*' .. 971 'def\_s*' .. 972 '\d DEF \_s*' .. 973 'def Info\_s*' .. 974 '\d DEF Info\_s*' .. 975 'def /Info\_s*' .. 976 '\d DEF /Info\_s*' .. 977 'def /Info/\_s*' .. 978 '\d DEF /Info/\_s*' .. 979 '\d RETURN 0', 980 instr) 981enddef 982 983def AndOr(arg: any): string 984 if arg == 1 && arg != 2 || arg == 4 985 return 'yes' 986 endif 987 return 'no' 988enddef 989 990def Test_disassemble_and_or() 991 assert_equal("yes", AndOr(1)) 992 assert_equal("no", AndOr(2)) 993 assert_equal("yes", AndOr(4)) 994 var instr = execute('disassemble AndOr') 995 assert_match('AndOr\_s*' .. 996 'if arg == 1 && arg != 2 || arg == 4\_s*' .. 997 '\d LOAD arg\[-1]\_s*' .. 998 '\d PUSHNR 1\_s*' .. 999 '\d COMPAREANY ==\_s*' .. 1000 '\d JUMP_IF_COND_FALSE -> \d\+\_s*' .. 1001 '\d LOAD arg\[-1]\_s*' .. 1002 '\d PUSHNR 2\_s*' .. 1003 '\d COMPAREANY !=\_s*' .. 1004 '\d JUMP_IF_COND_TRUE -> \d\+\_s*' .. 1005 '\d LOAD arg\[-1]\_s*' .. 1006 '\d\+ PUSHNR 4\_s*' .. 1007 '\d\+ COMPAREANY ==\_s*' .. 1008 '\d\+ JUMP_IF_FALSE -> \d\+', 1009 instr) 1010enddef 1011 1012def ForLoop(): list<number> 1013 var res: list<number> 1014 for i in range(3) 1015 res->add(i) 1016 endfor 1017 return res 1018enddef 1019 1020def Test_disassemble_for_loop() 1021 assert_equal([0, 1, 2], ForLoop()) 1022 var instr = execute('disassemble ForLoop') 1023 assert_match('ForLoop\_s*' .. 1024 'var res: list<number>\_s*' .. 1025 '\d NEWLIST size 0\_s*' .. 1026 '\d SETTYPE list<number>\_s*' .. 1027 '\d STORE $0\_s*' .. 1028 'for i in range(3)\_s*' .. 1029 '\d STORE -1 in $1\_s*' .. 1030 '\d PUSHNR 3\_s*' .. 1031 '\d BCALL range(argc 1)\_s*' .. 1032 '\d FOR $1 -> \d\+\_s*' .. 1033 '\d STORE $2\_s*' .. 1034 'res->add(i)\_s*' .. 1035 '\d LOAD $0\_s*' .. 1036 '\d LOAD $2\_s*' .. 1037 '\d\+ LISTAPPEND\_s*' .. 1038 '\d\+ DROP\_s*' .. 1039 'endfor\_s*' .. 1040 '\d\+ JUMP -> \d\+\_s*' .. 1041 '\d\+ DROP', 1042 instr) 1043enddef 1044 1045def ForLoopEval(): string 1046 var res = "" 1047 for str in eval('["one", "two"]') 1048 res ..= str 1049 endfor 1050 return res 1051enddef 1052 1053def Test_disassemble_for_loop_eval() 1054 assert_equal('onetwo', ForLoopEval()) 1055 var instr = execute('disassemble ForLoopEval') 1056 assert_match('ForLoopEval\_s*' .. 1057 'var res = ""\_s*' .. 1058 '\d PUSHS ""\_s*' .. 1059 '\d STORE $0\_s*' .. 1060 'for str in eval(''\["one", "two"\]'')\_s*' .. 1061 '\d STORE -1 in $1\_s*' .. 1062 '\d PUSHS "\["one", "two"\]"\_s*' .. 1063 '\d BCALL eval(argc 1)\_s*' .. 1064 '\d CHECKTYPE list<any> stack\[-1\]\_s*' .. 1065 '\d FOR $1 -> \d\+\_s*' .. 1066 '\d STORE $2\_s*' .. 1067 'res ..= str\_s*' .. 1068 '\d\+ LOAD $0\_s*' .. 1069 '\d\+ LOAD $2\_s*' .. 1070 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 1071 '\d\+ CONCAT\_s*' .. 1072 '\d\+ STORE $0\_s*' .. 1073 'endfor\_s*' .. 1074 '\d\+ JUMP -> 6\_s*' .. 1075 '\d\+ DROP\_s*' .. 1076 'return res\_s*' .. 1077 '\d\+ LOAD $0\_s*' .. 1078 '\d\+ RETURN', 1079 instr) 1080enddef 1081 1082def ForLoopUnpack() 1083 for [x1, x2] in [[1, 2], [3, 4]] 1084 echo x1 x2 1085 endfor 1086enddef 1087 1088def Test_disassemble_for_loop_unpack() 1089 var instr = execute('disassemble ForLoopUnpack') 1090 assert_match('ForLoopUnpack\_s*' .. 1091 'for \[x1, x2\] in \[\[1, 2\], \[3, 4\]\]\_s*' .. 1092 '\d\+ STORE -1 in $0\_s*' .. 1093 '\d\+ PUSHNR 1\_s*' .. 1094 '\d\+ PUSHNR 2\_s*' .. 1095 '\d\+ NEWLIST size 2\_s*' .. 1096 '\d\+ PUSHNR 3\_s*' .. 1097 '\d\+ PUSHNR 4\_s*' .. 1098 '\d\+ NEWLIST size 2\_s*' .. 1099 '\d\+ NEWLIST size 2\_s*' .. 1100 '\d\+ FOR $0 -> 16\_s*' .. 1101 '\d\+ UNPACK 2\_s*' .. 1102 '\d\+ STORE $1\_s*' .. 1103 '\d\+ STORE $2\_s*' .. 1104 'echo x1 x2\_s*' .. 1105 '\d\+ LOAD $1\_s*' .. 1106 '\d\+ LOAD $2\_s*' .. 1107 '\d\+ ECHO 2\_s*' .. 1108 'endfor\_s*' .. 1109 '\d\+ JUMP -> 8\_s*' .. 1110 '\d\+ DROP\_s*' .. 1111 '\d\+ RETURN 0', 1112 instr) 1113enddef 1114 1115def ForLoopContinue() 1116 for nr in [1, 2] 1117 try 1118 echo "ok" 1119 try 1120 echo "deeper" 1121 catch 1122 continue 1123 endtry 1124 catch 1125 echo "not ok" 1126 endtry 1127 endfor 1128enddef 1129 1130def Test_disassemble_for_loop_continue() 1131 var instr = execute('disassemble ForLoopContinue') 1132 assert_match('ForLoopContinue\_s*' .. 1133 'for nr in \[1, 2]\_s*' .. 1134 '0 STORE -1 in $0\_s*' .. 1135 '1 PUSHNR 1\_s*' .. 1136 '2 PUSHNR 2\_s*' .. 1137 '3 NEWLIST size 2\_s*' .. 1138 '4 FOR $0 -> 22\_s*' .. 1139 '5 STORE $1\_s*' .. 1140 'try\_s*' .. 1141 '6 TRY catch -> 17, endtry -> 20\_s*' .. 1142 'echo "ok"\_s*' .. 1143 '7 PUSHS "ok"\_s*' .. 1144 '8 ECHO 1\_s*' .. 1145 'try\_s*' .. 1146 '9 TRY catch -> 13, endtry -> 15\_s*' .. 1147 'echo "deeper"\_s*' .. 1148 '10 PUSHS "deeper"\_s*' .. 1149 '11 ECHO 1\_s*' .. 1150 'catch\_s*' .. 1151 '12 JUMP -> 15\_s*' .. 1152 '13 CATCH\_s*' .. 1153 'continue\_s*' .. 1154 '14 TRY-CONTINUE 2 levels -> 4\_s*' .. 1155 'endtry\_s*' .. 1156 '15 ENDTRY\_s*' .. 1157 'catch\_s*' .. 1158 '16 JUMP -> 20\_s*' .. 1159 '17 CATCH\_s*' .. 1160 'echo "not ok"\_s*' .. 1161 '18 PUSHS "not ok"\_s*' .. 1162 '19 ECHO 1\_s*' .. 1163 'endtry\_s*' .. 1164 '20 ENDTRY\_s*' .. 1165 'endfor\_s*' .. 1166 '21 JUMP -> 4\_s*' .. 1167 '\d\+ DROP\_s*' .. 1168 '\d\+ RETURN 0', 1169 instr) 1170enddef 1171 1172let g:number = 42 1173 1174def TypeCast() 1175 var l: list<number> = [23, <number>g:number] 1176enddef 1177 1178def Test_disassemble_typecast() 1179 var instr = execute('disassemble TypeCast') 1180 assert_match('TypeCast.*' .. 1181 'var l: list<number> = \[23, <number>g:number\].*' .. 1182 '\d PUSHNR 23\_s*' .. 1183 '\d LOADG g:number\_s*' .. 1184 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1185 '\d NEWLIST size 2\_s*' .. 1186 '\d SETTYPE list<number>\_s*' .. 1187 '\d STORE $0\_s*' .. 1188 '\d RETURN 0\_s*', 1189 instr) 1190enddef 1191 1192def Computing() 1193 var nr = 3 1194 var nrres = nr + 7 1195 nrres = nr - 7 1196 nrres = nr * 7 1197 nrres = nr / 7 1198 nrres = nr % 7 1199 1200 var anyres = g:number + 7 1201 anyres = g:number - 7 1202 anyres = g:number * 7 1203 anyres = g:number / 7 1204 anyres = g:number % 7 1205 1206 if has('float') 1207 var fl = 3.0 1208 var flres = fl + 7.0 1209 flres = fl - 7.0 1210 flres = fl * 7.0 1211 flres = fl / 7.0 1212 endif 1213enddef 1214 1215def Test_disassemble_computing() 1216 var instr = execute('disassemble Computing') 1217 assert_match('Computing.*' .. 1218 'var nr = 3.*' .. 1219 '\d STORE 3 in $0.*' .. 1220 'var nrres = nr + 7.*' .. 1221 '\d LOAD $0.*' .. 1222 '\d PUSHNR 7.*' .. 1223 '\d OPNR +.*' .. 1224 '\d STORE $1.*' .. 1225 'nrres = nr - 7.*' .. 1226 '\d OPNR -.*' .. 1227 'nrres = nr \* 7.*' .. 1228 '\d OPNR \*.*' .. 1229 'nrres = nr / 7.*' .. 1230 '\d OPNR /.*' .. 1231 'nrres = nr % 7.*' .. 1232 '\d OPNR %.*' .. 1233 'var anyres = g:number + 7.*' .. 1234 '\d LOADG g:number.*' .. 1235 '\d PUSHNR 7.*' .. 1236 '\d OPANY +.*' .. 1237 '\d STORE $2.*' .. 1238 'anyres = g:number - 7.*' .. 1239 '\d OPANY -.*' .. 1240 'anyres = g:number \* 7.*' .. 1241 '\d OPANY \*.*' .. 1242 'anyres = g:number / 7.*' .. 1243 '\d OPANY /.*' .. 1244 'anyres = g:number % 7.*' .. 1245 '\d OPANY %.*', 1246 instr) 1247 if has('float') 1248 assert_match('Computing.*' .. 1249 'var fl = 3.0.*' .. 1250 '\d PUSHF 3.0.*' .. 1251 '\d STORE $3.*' .. 1252 'var flres = fl + 7.0.*' .. 1253 '\d LOAD $3.*' .. 1254 '\d PUSHF 7.0.*' .. 1255 '\d OPFLOAT +.*' .. 1256 '\d STORE $4.*' .. 1257 'flres = fl - 7.0.*' .. 1258 '\d OPFLOAT -.*' .. 1259 'flres = fl \* 7.0.*' .. 1260 '\d OPFLOAT \*.*' .. 1261 'flres = fl / 7.0.*' .. 1262 '\d OPFLOAT /.*', 1263 instr) 1264 endif 1265enddef 1266 1267def AddListBlob() 1268 var reslist = [1, 2] + [3, 4] 1269 var resblob = 0z1122 + 0z3344 1270enddef 1271 1272def Test_disassemble_add_list_blob() 1273 var instr = execute('disassemble AddListBlob') 1274 assert_match('AddListBlob.*' .. 1275 'var reslist = \[1, 2] + \[3, 4].*' .. 1276 '\d PUSHNR 1.*' .. 1277 '\d PUSHNR 2.*' .. 1278 '\d NEWLIST size 2.*' .. 1279 '\d PUSHNR 3.*' .. 1280 '\d PUSHNR 4.*' .. 1281 '\d NEWLIST size 2.*' .. 1282 '\d ADDLIST.*' .. 1283 '\d STORE $.*.*' .. 1284 'var resblob = 0z1122 + 0z3344.*' .. 1285 '\d PUSHBLOB 0z1122.*' .. 1286 '\d PUSHBLOB 0z3344.*' .. 1287 '\d ADDBLOB.*' .. 1288 '\d STORE $.*', 1289 instr) 1290enddef 1291 1292let g:aa = 'aa' 1293def ConcatString(): string 1294 var res = g:aa .. "bb" 1295 return res 1296enddef 1297 1298def Test_disassemble_concat() 1299 var instr = execute('disassemble ConcatString') 1300 assert_match('ConcatString.*' .. 1301 'var res = g:aa .. "bb".*' .. 1302 '\d LOADG g:aa.*' .. 1303 '\d PUSHS "bb".*' .. 1304 '\d 2STRING_ANY stack\[-2].*' .. 1305 '\d CONCAT.*' .. 1306 '\d STORE $.*', 1307 instr) 1308 assert_equal('aabb', ConcatString()) 1309enddef 1310 1311def StringIndex(): string 1312 var s = "abcd" 1313 var res = s[1] 1314 return res 1315enddef 1316 1317def Test_disassemble_string_index() 1318 var instr = execute('disassemble StringIndex') 1319 assert_match('StringIndex\_s*' .. 1320 'var s = "abcd"\_s*' .. 1321 '\d PUSHS "abcd"\_s*' .. 1322 '\d STORE $0\_s*' .. 1323 'var res = s\[1]\_s*' .. 1324 '\d LOAD $0\_s*' .. 1325 '\d PUSHNR 1\_s*' .. 1326 '\d STRINDEX\_s*' .. 1327 '\d STORE $1\_s*', 1328 instr) 1329 assert_equal('b', StringIndex()) 1330enddef 1331 1332def StringSlice(): string 1333 var s = "abcd" 1334 var res = s[1 : 8] 1335 return res 1336enddef 1337 1338def Test_disassemble_string_slice() 1339 var instr = execute('disassemble StringSlice') 1340 assert_match('StringSlice\_s*' .. 1341 'var s = "abcd"\_s*' .. 1342 '\d PUSHS "abcd"\_s*' .. 1343 '\d STORE $0\_s*' .. 1344 'var res = s\[1 : 8]\_s*' .. 1345 '\d LOAD $0\_s*' .. 1346 '\d PUSHNR 1\_s*' .. 1347 '\d PUSHNR 8\_s*' .. 1348 '\d STRSLICE\_s*' .. 1349 '\d STORE $1\_s*', 1350 instr) 1351 assert_equal('bcd', StringSlice()) 1352enddef 1353 1354def ListIndex(): number 1355 var l = [1, 2, 3] 1356 var res = l[1] 1357 return res 1358enddef 1359 1360def Test_disassemble_list_index() 1361 var instr = execute('disassemble ListIndex') 1362 assert_match('ListIndex\_s*' .. 1363 'var l = \[1, 2, 3]\_s*' .. 1364 '\d PUSHNR 1\_s*' .. 1365 '\d PUSHNR 2\_s*' .. 1366 '\d PUSHNR 3\_s*' .. 1367 '\d NEWLIST size 3\_s*' .. 1368 '\d STORE $0\_s*' .. 1369 'var res = l\[1]\_s*' .. 1370 '\d LOAD $0\_s*' .. 1371 '\d PUSHNR 1\_s*' .. 1372 '\d LISTINDEX\_s*' .. 1373 '\d STORE $1\_s*', 1374 instr) 1375 assert_equal(2, ListIndex()) 1376enddef 1377 1378def ListSlice(): list<number> 1379 var l = [1, 2, 3] 1380 var res = l[1 : 8] 1381 return res 1382enddef 1383 1384def Test_disassemble_list_slice() 1385 var instr = execute('disassemble ListSlice') 1386 assert_match('ListSlice\_s*' .. 1387 'var l = \[1, 2, 3]\_s*' .. 1388 '\d PUSHNR 1\_s*' .. 1389 '\d PUSHNR 2\_s*' .. 1390 '\d PUSHNR 3\_s*' .. 1391 '\d NEWLIST size 3\_s*' .. 1392 '\d STORE $0\_s*' .. 1393 'var res = l\[1 : 8]\_s*' .. 1394 '\d LOAD $0\_s*' .. 1395 '\d PUSHNR 1\_s*' .. 1396 '\d PUSHNR 8\_s*' .. 1397 '\d LISTSLICE\_s*' .. 1398 '\d STORE $1\_s*', 1399 instr) 1400 assert_equal([2, 3], ListSlice()) 1401enddef 1402 1403def DictMember(): number 1404 var d = {item: 1} 1405 var res = d.item 1406 res = d["item"] 1407 return res 1408enddef 1409 1410def Test_disassemble_dict_member() 1411 var instr = execute('disassemble DictMember') 1412 assert_match('DictMember\_s*' .. 1413 'var d = {item: 1}\_s*' .. 1414 '\d PUSHS "item"\_s*' .. 1415 '\d PUSHNR 1\_s*' .. 1416 '\d NEWDICT size 1\_s*' .. 1417 '\d STORE $0\_s*' .. 1418 'var res = d.item\_s*' .. 1419 '\d\+ LOAD $0\_s*' .. 1420 '\d\+ MEMBER item\_s*' .. 1421 '\d\+ STORE $1\_s*' .. 1422 'res = d\["item"\]\_s*' .. 1423 '\d\+ LOAD $0\_s*' .. 1424 '\d\+ PUSHS "item"\_s*' .. 1425 '\d\+ MEMBER\_s*' .. 1426 '\d\+ STORE $1\_s*', 1427 instr) 1428 assert_equal(1, DictMember()) 1429enddef 1430 1431let somelist = [1, 2, 3, 4, 5] 1432def AnyIndex(): number 1433 var res = g:somelist[2] 1434 return res 1435enddef 1436 1437def Test_disassemble_any_index() 1438 var instr = execute('disassemble AnyIndex') 1439 assert_match('AnyIndex\_s*' .. 1440 'var res = g:somelist\[2\]\_s*' .. 1441 '\d LOADG g:somelist\_s*' .. 1442 '\d PUSHNR 2\_s*' .. 1443 '\d ANYINDEX\_s*' .. 1444 '\d STORE $0\_s*' .. 1445 'return res\_s*' .. 1446 '\d LOAD $0\_s*' .. 1447 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1448 '\d RETURN', 1449 instr) 1450 assert_equal(3, AnyIndex()) 1451enddef 1452 1453def AnySlice(): list<number> 1454 var res = g:somelist[1 : 3] 1455 return res 1456enddef 1457 1458def Test_disassemble_any_slice() 1459 var instr = execute('disassemble AnySlice') 1460 assert_match('AnySlice\_s*' .. 1461 'var res = g:somelist\[1 : 3\]\_s*' .. 1462 '\d LOADG g:somelist\_s*' .. 1463 '\d PUSHNR 1\_s*' .. 1464 '\d PUSHNR 3\_s*' .. 1465 '\d ANYSLICE\_s*' .. 1466 '\d STORE $0\_s*' .. 1467 'return res\_s*' .. 1468 '\d LOAD $0\_s*' .. 1469 '\d CHECKTYPE list<number> stack\[-1\]\_s*' .. 1470 '\d RETURN', 1471 instr) 1472 assert_equal([2, 3, 4], AnySlice()) 1473enddef 1474 1475def NegateNumber(): number 1476 var nr = 9 1477 var plus = +nr 1478 var res = -nr 1479 return res 1480enddef 1481 1482def Test_disassemble_negate_number() 1483 var instr = execute('disassemble NegateNumber') 1484 assert_match('NegateNumber\_s*' .. 1485 'var nr = 9\_s*' .. 1486 '\d STORE 9 in $0\_s*' .. 1487 'var plus = +nr\_s*' .. 1488 '\d LOAD $0\_s*' .. 1489 '\d CHECKNR\_s*' .. 1490 '\d STORE $1\_s*' .. 1491 'var res = -nr\_s*' .. 1492 '\d LOAD $0\_s*' .. 1493 '\d NEGATENR\_s*' .. 1494 '\d STORE $2\_s*', 1495 instr) 1496 assert_equal(-9, NegateNumber()) 1497enddef 1498 1499def InvertBool(): bool 1500 var flag = true 1501 var invert = !flag 1502 var res = !!flag 1503 return res 1504enddef 1505 1506def Test_disassemble_invert_bool() 1507 var instr = execute('disassemble InvertBool') 1508 assert_match('InvertBool\_s*' .. 1509 'var flag = true\_s*' .. 1510 '\d PUSH true\_s*' .. 1511 '\d STORE $0\_s*' .. 1512 'var invert = !flag\_s*' .. 1513 '\d LOAD $0\_s*' .. 1514 '\d INVERT (!val)\_s*' .. 1515 '\d STORE $1\_s*' .. 1516 'var res = !!flag\_s*' .. 1517 '\d LOAD $0\_s*' .. 1518 '\d 2BOOL (!!val)\_s*' .. 1519 '\d STORE $2\_s*', 1520 instr) 1521 assert_equal(true, InvertBool()) 1522enddef 1523 1524def ReturnBool(): bool 1525 var name: bool = 1 && 0 || 1 1526 return name 1527enddef 1528 1529def Test_disassemble_return_bool() 1530 var instr = execute('disassemble ReturnBool') 1531 assert_match('ReturnBool\_s*' .. 1532 'var name: bool = 1 && 0 || 1\_s*' .. 1533 '0 PUSHNR 1\_s*' .. 1534 '1 2BOOL (!!val)\_s*' .. 1535 '2 JUMP_IF_COND_FALSE -> 5\_s*' .. 1536 '3 PUSHNR 0\_s*' .. 1537 '4 2BOOL (!!val)\_s*' .. 1538 '5 JUMP_IF_COND_TRUE -> 8\_s*' .. 1539 '6 PUSHNR 1\_s*' .. 1540 '7 2BOOL (!!val)\_s*' .. 1541 '\d STORE $0\_s*' .. 1542 'return name\_s*' .. 1543 '\d\+ LOAD $0\_s*' .. 1544 '\d\+ RETURN', 1545 instr) 1546 assert_equal(true, InvertBool()) 1547enddef 1548 1549def Test_disassemble_compare() 1550 var cases = [ 1551 ['true == isFalse', 'COMPAREBOOL =='], 1552 ['true != isFalse', 'COMPAREBOOL !='], 1553 ['v:none == isNull', 'COMPARESPECIAL =='], 1554 ['v:none != isNull', 'COMPARESPECIAL !='], 1555 1556 ['111 == aNumber', 'COMPARENR =='], 1557 ['111 != aNumber', 'COMPARENR !='], 1558 ['111 > aNumber', 'COMPARENR >'], 1559 ['111 < aNumber', 'COMPARENR <'], 1560 ['111 >= aNumber', 'COMPARENR >='], 1561 ['111 <= aNumber', 'COMPARENR <='], 1562 ['111 =~ aNumber', 'COMPARENR =\~'], 1563 ['111 !~ aNumber', 'COMPARENR !\~'], 1564 1565 ['"xx" != aString', 'COMPARESTRING !='], 1566 ['"xx" > aString', 'COMPARESTRING >'], 1567 ['"xx" < aString', 'COMPARESTRING <'], 1568 ['"xx" >= aString', 'COMPARESTRING >='], 1569 ['"xx" <= aString', 'COMPARESTRING <='], 1570 ['"xx" =~ aString', 'COMPARESTRING =\~'], 1571 ['"xx" !~ aString', 'COMPARESTRING !\~'], 1572 ['"xx" is aString', 'COMPARESTRING is'], 1573 ['"xx" isnot aString', 'COMPARESTRING isnot'], 1574 1575 ['0z11 == aBlob', 'COMPAREBLOB =='], 1576 ['0z11 != aBlob', 'COMPAREBLOB !='], 1577 ['0z11 is aBlob', 'COMPAREBLOB is'], 1578 ['0z11 isnot aBlob', 'COMPAREBLOB isnot'], 1579 1580 ['[1, 2] == aList', 'COMPARELIST =='], 1581 ['[1, 2] != aList', 'COMPARELIST !='], 1582 ['[1, 2] is aList', 'COMPARELIST is'], 1583 ['[1, 2] isnot aList', 'COMPARELIST isnot'], 1584 1585 ['{a: 1} == aDict', 'COMPAREDICT =='], 1586 ['{a: 1} != aDict', 'COMPAREDICT !='], 1587 ['{a: 1} is aDict', 'COMPAREDICT is'], 1588 ['{a: 1} isnot aDict', 'COMPAREDICT isnot'], 1589 1590 ['(() => 33) == (() => 44)', 'COMPAREFUNC =='], 1591 ['(() => 33) != (() => 44)', 'COMPAREFUNC !='], 1592 ['(() => 33) is (() => 44)', 'COMPAREFUNC is'], 1593 ['(() => 33) isnot (() => 44)', 'COMPAREFUNC isnot'], 1594 1595 ['77 == g:xx', 'COMPAREANY =='], 1596 ['77 != g:xx', 'COMPAREANY !='], 1597 ['77 > g:xx', 'COMPAREANY >'], 1598 ['77 < g:xx', 'COMPAREANY <'], 1599 ['77 >= g:xx', 'COMPAREANY >='], 1600 ['77 <= g:xx', 'COMPAREANY <='], 1601 ['77 =~ g:xx', 'COMPAREANY =\~'], 1602 ['77 !~ g:xx', 'COMPAREANY !\~'], 1603 ['77 is g:xx', 'COMPAREANY is'], 1604 ['77 isnot g:xx', 'COMPAREANY isnot'], 1605 ] 1606 var floatDecl = '' 1607 if has('float') 1608 cases->extend([ 1609 ['1.1 == aFloat', 'COMPAREFLOAT =='], 1610 ['1.1 != aFloat', 'COMPAREFLOAT !='], 1611 ['1.1 > aFloat', 'COMPAREFLOAT >'], 1612 ['1.1 < aFloat', 'COMPAREFLOAT <'], 1613 ['1.1 >= aFloat', 'COMPAREFLOAT >='], 1614 ['1.1 <= aFloat', 'COMPAREFLOAT <='], 1615 ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'], 1616 ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'], 1617 ]) 1618 floatDecl = 'var aFloat = 2.2' 1619 endif 1620 1621 var nr = 1 1622 for case in cases 1623 # declare local variables to get a non-constant with the right type 1624 writefile(['def TestCase' .. nr .. '()', 1625 ' var isFalse = false', 1626 ' var isNull = v:null', 1627 ' var aNumber = 222', 1628 ' var aString = "yy"', 1629 ' var aBlob = 0z22', 1630 ' var aList = [3, 4]', 1631 ' var aDict = {x: 2}', 1632 floatDecl, 1633 ' if ' .. case[0], 1634 ' echo 42' 1635 ' endif', 1636 'enddef'], 'Xdisassemble') 1637 source Xdisassemble 1638 var instr = execute('disassemble TestCase' .. nr) 1639 assert_match('TestCase' .. nr .. '.*' .. 1640 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1641 '\d \(PUSH\|FUNCREF\).*' .. 1642 '\d \(PUSH\|FUNCREF\|LOAD\).*' .. 1643 '\d ' .. case[1] .. '.*' .. 1644 '\d JUMP_IF_FALSE -> \d\+.*', 1645 instr) 1646 1647 nr += 1 1648 endfor 1649 1650 delete('Xdisassemble') 1651enddef 1652 1653def s:FalsyOp() 1654 echo g:flag ?? "yes" 1655 echo [] ?? "empty list" 1656 echo "" ?? "empty string" 1657enddef 1658 1659def Test_dsassemble_falsy_op() 1660 var res = execute('disass s:FalsyOp') 1661 assert_match('\<SNR>\d*_FalsyOp\_s*' .. 1662 'echo g:flag ?? "yes"\_s*' .. 1663 '0 LOADG g:flag\_s*' .. 1664 '1 JUMP_AND_KEEP_IF_TRUE -> 3\_s*' .. 1665 '2 PUSHS "yes"\_s*' .. 1666 '3 ECHO 1\_s*' .. 1667 'echo \[\] ?? "empty list"\_s*' .. 1668 '4 NEWLIST size 0\_s*' .. 1669 '5 JUMP_AND_KEEP_IF_TRUE -> 7\_s*' .. 1670 '6 PUSHS "empty list"\_s*' .. 1671 '7 ECHO 1\_s*' .. 1672 'echo "" ?? "empty string"\_s*' .. 1673 '\d\+ PUSHS "empty string"\_s*' .. 1674 '\d\+ ECHO 1\_s*' .. 1675 '\d\+ RETURN 0', 1676 res) 1677enddef 1678 1679def Test_disassemble_compare_const() 1680 var cases = [ 1681 ['"xx" == "yy"', false], 1682 ['"aa" == "aa"', true], 1683 ['has("eval") ? true : false', true], 1684 ['has("asdf") ? true : false', false], 1685 ] 1686 1687 var nr = 1 1688 for case in cases 1689 writefile(['def TestCase' .. nr .. '()', 1690 ' if ' .. case[0], 1691 ' echo 42' 1692 ' endif', 1693 'enddef'], 'Xdisassemble') 1694 source Xdisassemble 1695 var instr = execute('disassemble TestCase' .. nr) 1696 if case[1] 1697 # condition true, "echo 42" executed 1698 assert_match('TestCase' .. nr .. '.*' .. 1699 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1700 '\d PUSHNR 42.*' .. 1701 '\d ECHO 1.*' .. 1702 '\d RETURN 0', 1703 instr) 1704 else 1705 # condition false, function just returns 1706 assert_match('TestCase' .. nr .. '.*' .. 1707 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' .. 1708 'echo 42[ \n]*' .. 1709 'endif[ \n]*' .. 1710 '\d RETURN 0', 1711 instr) 1712 endif 1713 1714 nr += 1 1715 endfor 1716 1717 delete('Xdisassemble') 1718enddef 1719 1720def s:Execute() 1721 execute 'help vim9.txt' 1722 var cmd = 'help vim9.txt' 1723 execute cmd 1724 var tag = 'vim9.txt' 1725 execute 'help ' .. tag 1726enddef 1727 1728def Test_disassemble_execute() 1729 var res = execute('disass s:Execute') 1730 assert_match('\<SNR>\d*_Execute\_s*' .. 1731 "execute 'help vim9.txt'\\_s*" .. 1732 '\d PUSHS "help vim9.txt"\_s*' .. 1733 '\d EXECUTE 1\_s*' .. 1734 "var cmd = 'help vim9.txt'\\_s*" .. 1735 '\d PUSHS "help vim9.txt"\_s*' .. 1736 '\d STORE $0\_s*' .. 1737 'execute cmd\_s*' .. 1738 '\d LOAD $0\_s*' .. 1739 '\d EXECUTE 1\_s*' .. 1740 "var tag = 'vim9.txt'\\_s*" .. 1741 '\d PUSHS "vim9.txt"\_s*' .. 1742 '\d STORE $1\_s*' .. 1743 "execute 'help ' .. tag\\_s*" .. 1744 '\d\+ PUSHS "help "\_s*' .. 1745 '\d\+ LOAD $1\_s*' .. 1746 '\d\+ CONCAT\_s*' .. 1747 '\d\+ EXECUTE 1\_s*' .. 1748 '\d\+ RETURN 0', 1749 res) 1750enddef 1751 1752def s:Echomsg() 1753 echomsg 'some' 'message' 1754 echoerr 'went' .. 'wrong' 1755enddef 1756 1757def Test_disassemble_echomsg() 1758 var res = execute('disass s:Echomsg') 1759 assert_match('\<SNR>\d*_Echomsg\_s*' .. 1760 "echomsg 'some' 'message'\\_s*" .. 1761 '\d PUSHS "some"\_s*' .. 1762 '\d PUSHS "message"\_s*' .. 1763 '\d ECHOMSG 2\_s*' .. 1764 "echoerr 'went' .. 'wrong'\\_s*" .. 1765 '\d PUSHS "wentwrong"\_s*' .. 1766 '\d ECHOERR 1\_s*' .. 1767 '\d RETURN 0', 1768 res) 1769enddef 1770 1771def SomeStringArg(arg: string) 1772 echo arg 1773enddef 1774 1775def SomeAnyArg(arg: any) 1776 echo arg 1777enddef 1778 1779def SomeStringArgAndReturn(arg: string): string 1780 return arg 1781enddef 1782 1783def Test_display_func() 1784 var res1 = execute('function SomeStringArg') 1785 assert_match('.* def SomeStringArg(arg: string)\_s*' .. 1786 '\d *echo arg.*' .. 1787 ' *enddef', 1788 res1) 1789 1790 var res2 = execute('function SomeAnyArg') 1791 assert_match('.* def SomeAnyArg(arg: any)\_s*' .. 1792 '\d *echo arg\_s*' .. 1793 ' *enddef', 1794 res2) 1795 1796 var res3 = execute('function SomeStringArgAndReturn') 1797 assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' .. 1798 '\d *return arg\_s*' .. 1799 ' *enddef', 1800 res3) 1801enddef 1802 1803def Test_vim9script_forward_func() 1804 var lines =<< trim END 1805 vim9script 1806 def FuncOne(): string 1807 return FuncTwo() 1808 enddef 1809 def FuncTwo(): string 1810 return 'two' 1811 enddef 1812 g:res_FuncOne = execute('disass FuncOne') 1813 END 1814 writefile(lines, 'Xdisassemble') 1815 source Xdisassemble 1816 1817 # check that the first function calls the second with DCALL 1818 assert_match('\<SNR>\d*_FuncOne\_s*' .. 1819 'return FuncTwo()\_s*' .. 1820 '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' .. 1821 '\d RETURN', 1822 g:res_FuncOne) 1823 1824 delete('Xdisassemble') 1825 unlet g:res_FuncOne 1826enddef 1827 1828def s:ConcatStrings(): string 1829 return 'one' .. 'two' .. 'three' 1830enddef 1831 1832def s:ComputeConst(): number 1833 return 2 + 3 * 4 / 6 + 7 1834enddef 1835 1836def s:ComputeConstParen(): number 1837 return ((2 + 4) * (8 / 2)) / (3 + 4) 1838enddef 1839 1840def Test_simplify_const_expr() 1841 var res = execute('disass s:ConcatStrings') 1842 assert_match('<SNR>\d*_ConcatStrings\_s*' .. 1843 "return 'one' .. 'two' .. 'three'\\_s*" .. 1844 '\d PUSHS "onetwothree"\_s*' .. 1845 '\d RETURN', 1846 res) 1847 1848 res = execute('disass s:ComputeConst') 1849 assert_match('<SNR>\d*_ComputeConst\_s*' .. 1850 'return 2 + 3 \* 4 / 6 + 7\_s*' .. 1851 '\d PUSHNR 11\_s*' .. 1852 '\d RETURN', 1853 res) 1854 1855 res = execute('disass s:ComputeConstParen') 1856 assert_match('<SNR>\d*_ComputeConstParen\_s*' .. 1857 'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' .. 1858 '\d PUSHNR 3\>\_s*' .. 1859 '\d RETURN', 1860 res) 1861enddef 1862 1863def s:CallAppend() 1864 eval "some text"->append(2) 1865enddef 1866 1867def Test_shuffle() 1868 var res = execute('disass s:CallAppend') 1869 assert_match('<SNR>\d*_CallAppend\_s*' .. 1870 'eval "some text"->append(2)\_s*' .. 1871 '\d PUSHS "some text"\_s*' .. 1872 '\d PUSHNR 2\_s*' .. 1873 '\d SHUFFLE 2 up 1\_s*' .. 1874 '\d BCALL append(argc 2)\_s*' .. 1875 '\d DROP\_s*' .. 1876 '\d RETURN 0', 1877 res) 1878enddef 1879 1880 1881def s:SilentMessage() 1882 silent echomsg "text" 1883 silent! echoerr "error" 1884enddef 1885 1886def Test_silent() 1887 var res = execute('disass s:SilentMessage') 1888 assert_match('<SNR>\d*_SilentMessage\_s*' .. 1889 'silent echomsg "text"\_s*' .. 1890 '\d CMDMOD silent\_s*' .. 1891 '\d PUSHS "text"\_s*' .. 1892 '\d ECHOMSG 1\_s*' .. 1893 '\d CMDMOD_REV\_s*' .. 1894 'silent! echoerr "error"\_s*' .. 1895 '\d CMDMOD silent!\_s*' .. 1896 '\d PUSHS "error"\_s*' .. 1897 '\d ECHOERR 1\_s*' .. 1898 '\d CMDMOD_REV\_s*' .. 1899 '\d RETURN 0', 1900 res) 1901enddef 1902 1903def s:Profiled(): string 1904 echo "profiled" 1905 return "done" 1906enddef 1907 1908def Test_profiled() 1909 if !has('profile') 1910 MissingFeature 'profile' 1911 endif 1912 var res = execute('disass! s:Profiled') 1913 assert_match('<SNR>\d*_Profiled\_s*' .. 1914 'echo "profiled"\_s*' .. 1915 '\d PROFILE START line 1\_s*' .. 1916 '\d PUSHS "profiled"\_s*' .. 1917 '\d ECHO 1\_s*' .. 1918 'return "done"\_s*' .. 1919 '\d PROFILE END\_s*' .. 1920 '\d PROFILE START line 2\_s*' .. 1921 '\d PUSHS "done"\_s*' .. 1922 '\d RETURN\_s*' .. 1923 '\d PROFILE END', 1924 res) 1925enddef 1926 1927def s:SilentReturn(): string 1928 silent return "done" 1929enddef 1930 1931def Test_silent_return() 1932 var res = execute('disass s:SilentReturn') 1933 assert_match('<SNR>\d*_SilentReturn\_s*' .. 1934 'silent return "done"\_s*' .. 1935 '\d CMDMOD silent\_s*' .. 1936 '\d PUSHS "done"\_s*' .. 1937 '\d CMDMOD_REV\_s*' .. 1938 '\d RETURN', 1939 res) 1940enddef 1941 1942" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 1943