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 let local = 1 17 buffers 18 echo arg 19 echo local 20 echo &lines 21 echo v:version 22 echo s:scriptvar 23 echo g:globalvar 24 echo get(g:, "global") 25 echo b:buffervar 26 echo get(b:, "buffer") 27 echo w:windowvar 28 echo get(w:, "window") 29 echo t:tabpagevar 30 echo get(t:, "tab") 31 echo &tabstop 32 echo $ENVVAR 33 echo @z 34enddef 35 36def Test_disassemble_load() 37 assert_fails('disass NoFunc', 'E1061:') 38 assert_fails('disass NotCompiled', 'E1062:') 39 assert_fails('disass', 'E471:') 40 assert_fails('disass [', 'E475:') 41 assert_fails('disass 234', 'E129:') 42 assert_fails('disass <XX>foo', 'E129:') 43 44 let res = execute('disass s:ScriptFuncLoad') 45 assert_match('<SNR>\d*_ScriptFuncLoad.*' .. 46 'buffers.*' .. 47 ' EXEC \+buffers.*' .. 48 ' LOAD arg\[-1\].*' .. 49 ' LOAD $0.*' .. 50 ' LOADOPT &lines.*' .. 51 ' LOADV v:version.*' .. 52 ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' .. 53 ' LOADG g:globalvar.*' .. 54 'echo get(g:, "global")\_s*' .. 55 '\d\+ LOAD g:\_s*' .. 56 '\d\+ PUSHS "global"\_s*' .. 57 '\d\+ BCALL get(argc 2).*' .. 58 ' LOADB b:buffervar.*' .. 59 'echo get(b:, "buffer")\_s*' .. 60 '\d\+ LOAD b:\_s*' .. 61 '\d\+ PUSHS "buffer"\_s*' .. 62 '\d\+ BCALL get(argc 2).*' .. 63 ' LOADW w:windowvar.*' .. 64 'echo get(w:, "window")\_s*' .. 65 '\d\+ LOAD w:\_s*' .. 66 '\d\+ PUSHS "window"\_s*' .. 67 '\d\+ BCALL get(argc 2).*' .. 68 ' LOADT t:tabpagevar.*' .. 69 'echo get(t:, "tab")\_s*' .. 70 '\d\+ LOAD t:\_s*' .. 71 '\d\+ PUSHS "tab"\_s*' .. 72 '\d\+ BCALL get(argc 2).*' .. 73 ' LOADENV $ENVVAR.*' .. 74 ' LOADREG @z.*', 75 res) 76enddef 77 78def s:EditExpand() 79 let filename = "file" 80 let filenr = 123 81 edit the`=filename``=filenr`.txt 82enddef 83 84def Test_disassemble_exec_expr() 85 let res = execute('disass s:EditExpand') 86 assert_match('<SNR>\d*_EditExpand.*' .. 87 ' let filename = "file".*' .. 88 '\d PUSHS "file".*' .. 89 '\d STORE $0.*' .. 90 ' let filenr = 123.*' .. 91 '\d STORE 123 in $1.*' .. 92 ' edit the`=filename``=filenr`.txt.*' .. 93 '\d PUSHS "edit the".*' .. 94 '\d LOAD $0.*' .. 95 '\d LOAD $1.*' .. 96 '\d 2STRING stack\[-1\].*' .. 97 '\d PUSHS ".txt".*' .. 98 '\d EXECCONCAT 4.*' .. 99 '\d PUSHNR 0.*' .. 100 '\d RETURN', 101 res) 102enddef 103 104def s:ScriptFuncPush() 105 let localbool = true 106 let localspec = v:none 107 let localblob = 0z1234 108 if has('float') 109 let localfloat = 1.234 110 endif 111enddef 112 113def Test_disassemble_push() 114 let res = execute('disass s:ScriptFuncPush') 115 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 116 'localbool = true.*' .. 117 ' PUSH v:true.*' .. 118 'localspec = v:none.*' .. 119 ' PUSH v:none.*' .. 120 'localblob = 0z1234.*' .. 121 ' PUSHBLOB 0z1234.*', 122 res) 123 if has('float') 124 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 125 'localfloat = 1.234.*' .. 126 ' PUSHF 1.234.*', 127 res) 128 endif 129enddef 130 131def s:ScriptFuncStore() 132 let localnr = 1 133 localnr = 2 134 let localstr = 'abc' 135 localstr = 'xyz' 136 v:char = 'abc' 137 s:scriptvar = 'sv' 138 g:globalvar = 'gv' 139 b:buffervar = 'bv' 140 w:windowvar = 'wv' 141 t:tabpagevar = 'tv' 142 &tabstop = 8 143 $ENVVAR = 'ev' 144 @z = 'rv' 145enddef 146 147def Test_disassemble_store() 148 let res = execute('disass s:ScriptFuncStore') 149 assert_match('<SNR>\d*_ScriptFuncStore.*' .. 150 'let localnr = 1.*' .. 151 'localnr = 2.*' .. 152 ' STORE 2 in $0.*' .. 153 'let localstr = ''abc''.*' .. 154 'localstr = ''xyz''.*' .. 155 ' STORE $1.*' .. 156 'v:char = ''abc''.*' .. 157 'STOREV v:char.*' .. 158 's:scriptvar = ''sv''.*' .. 159 ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' .. 160 'g:globalvar = ''gv''.*' .. 161 ' STOREG g:globalvar.*' .. 162 'b:buffervar = ''bv''.*' .. 163 ' STOREB b:buffervar.*' .. 164 'w:windowvar = ''wv''.*' .. 165 ' STOREW w:windowvar.*' .. 166 't:tabpagevar = ''tv''.*' .. 167 ' STORET t:tabpagevar.*' .. 168 '&tabstop = 8.*' .. 169 ' STOREOPT &tabstop.*' .. 170 '$ENVVAR = ''ev''.*' .. 171 ' STOREENV $ENVVAR.*' .. 172 '@z = ''rv''.*' .. 173 ' STOREREG @z.*', 174 res) 175enddef 176 177def s:ScriptFuncStoreMember() 178 let locallist: list<number> = [] 179 locallist[0] = 123 180 let localdict: dict<number> = {} 181 localdict["a"] = 456 182enddef 183 184def Test_disassemble_store_member() 185 let res = execute('disass s:ScriptFuncStoreMember') 186 assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' .. 187 'let locallist: list<number> = []\_s*' .. 188 '\d NEWLIST size 0\_s*' .. 189 '\d STORE $0\_s*' .. 190 'locallist\[0\] = 123\_s*' .. 191 '\d PUSHNR 123\_s*' .. 192 '\d PUSHNR 0\_s*' .. 193 '\d LOAD $0\_s*' .. 194 '\d STORELIST\_s*' .. 195 'let localdict: dict<number> = {}\_s*' .. 196 '\d NEWDICT size 0\_s*' .. 197 '\d STORE $1\_s*' .. 198 'localdict\["a"\] = 456\_s*' .. 199 '\d\+ PUSHNR 456\_s*' .. 200 '\d\+ PUSHS "a"\_s*' .. 201 '\d\+ LOAD $1\_s*' .. 202 '\d\+ STOREDICT\_s*' .. 203 '\d\+ PUSHNR 0\_s*' .. 204 '\d\+ RETURN', 205 res) 206enddef 207 208def s:ListAssign() 209 let x: string 210 let y: string 211 let l: list<any> 212 [x, y; l] = g:stringlist 213enddef 214 215def Test_disassemble_list_assign() 216 let res = execute('disass s:ListAssign') 217 assert_match('<SNR>\d*_ListAssign\_s*' .. 218 'let x: string\_s*' .. 219 '\d PUSHS "\[NULL\]"\_s*' .. 220 '\d STORE $0\_s*' .. 221 'let y: string\_s*' .. 222 '\d PUSHS "\[NULL\]"\_s*' .. 223 '\d STORE $1\_s*' .. 224 'let l: list<any>\_s*' .. 225 '\d NEWLIST size 0\_s*' .. 226 '\d STORE $2\_s*' .. 227 '\[x, y; l\] = g:stringlist\_s*' .. 228 '\d LOADG g:stringlist\_s*' .. 229 '\d CHECKTYPE list stack\[-1\]\_s*' .. 230 '\d CHECKLEN >= 2\_s*' .. 231 '\d\+ ITEM 0\_s*' .. 232 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 233 '\d\+ STORE $0\_s*' .. 234 '\d\+ ITEM 1\_s*' .. 235 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 236 '\d\+ STORE $1\_s*' .. 237 '\d\+ SLICE 2\_s*' .. 238 '\d\+ STORE $2\_s*' .. 239 '\d\+ PUSHNR 0\_s*' .. 240 '\d\+ RETURN', 241 res) 242enddef 243 244def s:ScriptFuncUnlet() 245 g:somevar = "value" 246 unlet g:somevar 247 unlet! g:somevar 248 unlet $SOMEVAR 249enddef 250 251def Test_disassemble_unlet() 252 let res = execute('disass s:ScriptFuncUnlet') 253 assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' .. 254 'g:somevar = "value"\_s*' .. 255 '\d PUSHS "value"\_s*' .. 256 '\d STOREG g:somevar\_s*' .. 257 'unlet g:somevar\_s*' .. 258 '\d UNLET g:somevar\_s*' .. 259 'unlet! g:somevar\_s*' .. 260 '\d UNLET! g:somevar\_s*' .. 261 'unlet $SOMEVAR\_s*' .. 262 '\d UNLETENV $SOMEVAR\_s*', 263 res) 264enddef 265 266def s:ScriptFuncTry() 267 try 268 echo "yes" 269 catch /fail/ 270 echo "no" 271 finally 272 throw "end" 273 endtry 274enddef 275 276def Test_disassemble_try() 277 let res = execute('disass s:ScriptFuncTry') 278 assert_match('<SNR>\d*_ScriptFuncTry\_s*' .. 279 'try\_s*' .. 280 '\d TRY catch -> \d\+, finally -> \d\+\_s*' .. 281 'echo "yes"\_s*' .. 282 '\d PUSHS "yes"\_s*' .. 283 '\d ECHO 1\_s*' .. 284 'catch /fail/\_s*' .. 285 '\d JUMP -> \d\+\_s*' .. 286 '\d PUSH v:exception\_s*' .. 287 '\d PUSHS "fail"\_s*' .. 288 '\d COMPARESTRING =\~\_s*' .. 289 '\d JUMP_IF_FALSE -> \d\+\_s*' .. 290 '\d CATCH\_s*' .. 291 'echo "no"\_s*' .. 292 '\d\+ PUSHS "no"\_s*' .. 293 '\d\+ ECHO 1\_s*' .. 294 'finally\_s*' .. 295 'throw "end"\_s*' .. 296 '\d\+ PUSHS "end"\_s*' .. 297 '\d\+ THROW\_s*' .. 298 'endtry\_s*' .. 299 '\d\+ ENDTRY', 300 res) 301enddef 302 303def s:ScriptFuncNew() 304 let ll = [1, "two", 333] 305 let dd = #{one: 1, two: "val"} 306enddef 307 308def Test_disassemble_new() 309 let res = execute('disass s:ScriptFuncNew') 310 assert_match('<SNR>\d*_ScriptFuncNew\_s*' .. 311 'let ll = \[1, "two", 333\]\_s*' .. 312 '\d PUSHNR 1\_s*' .. 313 '\d PUSHS "two"\_s*' .. 314 '\d PUSHNR 333\_s*' .. 315 '\d NEWLIST size 3\_s*' .. 316 '\d STORE $0\_s*' .. 317 'let dd = #{one: 1, two: "val"}\_s*' .. 318 '\d PUSHS "one"\_s*' .. 319 '\d PUSHNR 1\_s*' .. 320 '\d PUSHS "two"\_s*' .. 321 '\d PUSHS "val"\_s*' .. 322 '\d NEWDICT size 2\_s*', 323 res) 324enddef 325 326def FuncWithArg(arg: any) 327 echo arg 328enddef 329 330func UserFunc() 331 echo 'nothing' 332endfunc 333 334func UserFuncWithArg(arg) 335 echo a:arg 336endfunc 337 338def s:ScriptFuncCall(): string 339 changenr() 340 char2nr("abc") 341 Test_disassemble_new() 342 FuncWithArg(343) 343 ScriptFuncNew() 344 s:ScriptFuncNew() 345 UserFunc() 346 UserFuncWithArg("foo") 347 let FuncRef = function("UserFunc") 348 FuncRef() 349 let FuncRefWithArg = function("UserFuncWithArg") 350 FuncRefWithArg("bar") 351 return "yes" 352enddef 353 354def Test_disassemble_call() 355 let res = execute('disass s:ScriptFuncCall') 356 assert_match('<SNR>\d\+_ScriptFuncCall\_s*' .. 357 'changenr()\_s*' .. 358 '\d BCALL changenr(argc 0)\_s*' .. 359 '\d DROP\_s*' .. 360 'char2nr("abc")\_s*' .. 361 '\d PUSHS "abc"\_s*' .. 362 '\d BCALL char2nr(argc 1)\_s*' .. 363 '\d DROP\_s*' .. 364 'Test_disassemble_new()\_s*' .. 365 '\d DCALL Test_disassemble_new(argc 0)\_s*' .. 366 '\d DROP\_s*' .. 367 'FuncWithArg(343)\_s*' .. 368 '\d\+ PUSHNR 343\_s*' .. 369 '\d\+ DCALL FuncWithArg(argc 1)\_s*' .. 370 '\d\+ DROP\_s*' .. 371 'ScriptFuncNew()\_s*' .. 372 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 373 '\d\+ DROP\_s*' .. 374 's:ScriptFuncNew()\_s*' .. 375 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 376 '\d\+ DROP\_s*' .. 377 'UserFunc()\_s*' .. 378 '\d\+ UCALL UserFunc(argc 0)\_s*' .. 379 '\d\+ DROP\_s*' .. 380 'UserFuncWithArg("foo")\_s*' .. 381 '\d\+ PUSHS "foo"\_s*' .. 382 '\d\+ UCALL UserFuncWithArg(argc 1)\_s*' .. 383 '\d\+ DROP\_s*' .. 384 'let FuncRef = function("UserFunc")\_s*' .. 385 '\d\+ PUSHS "UserFunc"\_s*' .. 386 '\d\+ BCALL function(argc 1)\_s*' .. 387 '\d\+ STORE $0\_s*' .. 388 'FuncRef()\_s*' .. 389 '\d\+ LOAD $\d\_s*' .. 390 '\d\+ PCALL (argc 0)\_s*' .. 391 '\d\+ DROP\_s*' .. 392 'let FuncRefWithArg = function("UserFuncWithArg")\_s*' .. 393 '\d\+ PUSHS "UserFuncWithArg"\_s*' .. 394 '\d\+ BCALL function(argc 1)\_s*' .. 395 '\d\+ STORE $1\_s*' .. 396 'FuncRefWithArg("bar")\_s*' .. 397 '\d\+ PUSHS "bar"\_s*' .. 398 '\d\+ LOAD $\d\_s*' .. 399 '\d\+ PCALL (argc 1)\_s*' .. 400 '\d\+ DROP\_s*' .. 401 'return "yes"\_s*' .. 402 '\d\+ PUSHS "yes"\_s*' .. 403 '\d\+ RETURN', 404 res) 405enddef 406 407def s:CreateRefs() 408 let local = 'a' 409 def Append(arg: string) 410 local ..= arg 411 enddef 412 g:Append = Append 413 def Get(): string 414 return local 415 enddef 416 g:Get = Get 417enddef 418 419def Test_disassemble_closure() 420 CreateRefs() 421 let res = execute('disass g:Append') 422 assert_match('<lambda>\d\_s*' .. 423 'local ..= arg\_s*' .. 424 '\d LOADOUTER $0\_s*' .. 425 '\d LOAD arg\[-1\]\_s*' .. 426 '\d CONCAT\_s*' .. 427 '\d STOREOUTER $0\_s*' .. 428 '\d PUSHNR 0\_s*' .. 429 '\d RETURN', 430 res) 431 432 res = execute('disass g:Get') 433 assert_match('<lambda>\d\_s*' .. 434 'return local\_s*' .. 435 '\d LOADOUTER $0\_s*' .. 436 '\d RETURN', 437 res) 438 439 unlet g:Append 440 unlet g:Get 441enddef 442 443 444def EchoArg(arg: string): string 445 return arg 446enddef 447def RefThis(): func 448 return function('EchoArg') 449enddef 450def s:ScriptPCall() 451 RefThis()("text") 452enddef 453 454def Test_disassemble_pcall() 455 let res = execute('disass s:ScriptPCall') 456 assert_match('<SNR>\d\+_ScriptPCall\_s*' .. 457 'RefThis()("text")\_s*' .. 458 '\d DCALL RefThis(argc 0)\_s*' .. 459 '\d PUSHS "text"\_s*' .. 460 '\d PCALL top (argc 1)\_s*' .. 461 '\d PCALL end\_s*' .. 462 '\d DROP\_s*' .. 463 '\d PUSHNR 0\_s*' .. 464 '\d RETURN', 465 res) 466enddef 467 468 469def s:FuncWithForwardCall(): string 470 return g:DefinedLater("yes") 471enddef 472 473def DefinedLater(arg: string): string 474 return arg 475enddef 476 477def Test_disassemble_update_instr() 478 let res = execute('disass s:FuncWithForwardCall') 479 assert_match('FuncWithForwardCall\_s*' .. 480 'return g:DefinedLater("yes")\_s*' .. 481 '\d PUSHS "yes"\_s*' .. 482 '\d DCALL DefinedLater(argc 1)\_s*' .. 483 '\d RETURN', 484 res) 485 486 # Calling the function will change UCALL into the faster DCALL 487 assert_equal('yes', FuncWithForwardCall()) 488 489 res = execute('disass s:FuncWithForwardCall') 490 assert_match('FuncWithForwardCall\_s*' .. 491 'return g:DefinedLater("yes")\_s*' .. 492 '\d PUSHS "yes"\_s*' .. 493 '\d DCALL DefinedLater(argc 1)\_s*' .. 494 '\d RETURN', 495 res) 496enddef 497 498 499def FuncWithDefault(arg: string = 'default'): string 500 return arg 501enddef 502 503def Test_disassemble_call_default() 504 let res = execute('disass FuncWithDefault') 505 assert_match('FuncWithDefault\_s*' .. 506 '\d PUSHS "default"\_s*' .. 507 '\d STORE arg\[-1]\_s*' .. 508 'return arg\_s*' .. 509 '\d LOAD arg\[-1]\_s*' .. 510 '\d RETURN', 511 res) 512enddef 513 514 515def HasEval() 516 if has("eval") 517 echo "yes" 518 else 519 echo "no" 520 endif 521enddef 522 523def HasNothing() 524 if has("nothing") 525 echo "yes" 526 else 527 echo "no" 528 endif 529enddef 530 531def HasSomething() 532 if has("nothing") 533 echo "nothing" 534 elseif has("something") 535 echo "something" 536 elseif has("eval") 537 echo "eval" 538 elseif has("less") 539 echo "less" 540 endif 541enddef 542 543def Test_disassemble_const_expr() 544 assert_equal("\nyes", execute('call HasEval()')) 545 let instr = execute('disassemble HasEval') 546 assert_match('HasEval\_s*' .. 547 'if has("eval")\_s*' .. 548 'echo "yes"\_s*' .. 549 '\d PUSHS "yes"\_s*' .. 550 '\d ECHO 1\_s*' .. 551 'else\_s*' .. 552 'echo "no"\_s*' .. 553 'endif\_s*', 554 instr) 555 assert_notmatch('JUMP', instr) 556 557 assert_equal("\nno", execute('call HasNothing()')) 558 instr = execute('disassemble HasNothing') 559 assert_match('HasNothing\_s*' .. 560 'if has("nothing")\_s*' .. 561 'echo "yes"\_s*' .. 562 'else\_s*' .. 563 'echo "no"\_s*' .. 564 '\d PUSHS "no"\_s*' .. 565 '\d ECHO 1\_s*' .. 566 'endif', 567 instr) 568 assert_notmatch('PUSHS "yes"', instr) 569 assert_notmatch('JUMP', instr) 570 571 assert_equal("\neval", execute('call HasSomething()')) 572 instr = execute('disassemble HasSomething') 573 assert_match('HasSomething.*' .. 574 'if has("nothing")\_s*' .. 575 'echo "nothing"\_s*' .. 576 'elseif has("something")\_s*' .. 577 'echo "something"\_s*' .. 578 'elseif has("eval")\_s*' .. 579 'echo "eval"\_s*' .. 580 '\d PUSHS "eval"\_s*' .. 581 '\d ECHO 1\_s*' .. 582 'elseif has("less").*' .. 583 'echo "less"\_s*' .. 584 'endif', 585 instr) 586 assert_notmatch('PUSHS "nothing"', instr) 587 assert_notmatch('PUSHS "something"', instr) 588 assert_notmatch('PUSHS "less"', instr) 589 assert_notmatch('JUMP', instr) 590enddef 591 592def ReturnInIf(): string 593 if g:cond 594 return "yes" 595 else 596 return "no" 597 endif 598enddef 599 600def Test_disassemble_return_in_if() 601 let instr = execute('disassemble ReturnInIf') 602 assert_match('ReturnInIf\_s*' .. 603 'if g:cond\_s*' .. 604 '0 LOADG g:cond\_s*' .. 605 '1 JUMP_IF_FALSE -> 4\_s*' .. 606 'return "yes"\_s*' .. 607 '2 PUSHS "yes"\_s*' .. 608 '3 RETURN\_s*' .. 609 'else\_s*' .. 610 ' return "no"\_s*' .. 611 '4 PUSHS "no"\_s*' .. 612 '5 RETURN$', 613 instr) 614enddef 615 616def WithFunc() 617 let Funky1: func 618 let Funky2: func = function("len") 619 let Party2: func = funcref("UserFunc") 620enddef 621 622def Test_disassemble_function() 623 let instr = execute('disassemble WithFunc') 624 assert_match('WithFunc\_s*' .. 625 'let Funky1: func\_s*' .. 626 '0 PUSHFUNC "\[none]"\_s*' .. 627 '1 STORE $0\_s*' .. 628 'let Funky2: func = function("len")\_s*' .. 629 '2 PUSHS "len"\_s*' .. 630 '3 BCALL function(argc 1)\_s*' .. 631 '4 STORE $1\_s*' .. 632 'let Party2: func = funcref("UserFunc")\_s*' .. 633 '\d PUSHS "UserFunc"\_s*' .. 634 '\d BCALL funcref(argc 1)\_s*' .. 635 '\d STORE $2\_s*' .. 636 '\d PUSHNR 0\_s*' .. 637 '\d RETURN', 638 instr) 639enddef 640 641if has('channel') 642 def WithChannel() 643 let job1: job 644 let job2: job = job_start("donothing") 645 let chan1: channel 646 enddef 647endif 648 649def Test_disassemble_channel() 650 CheckFeature channel 651 652 let instr = execute('disassemble WithChannel') 653 assert_match('WithChannel\_s*' .. 654 'let job1: job\_s*' .. 655 '\d PUSHJOB "no process"\_s*' .. 656 '\d STORE $0\_s*' .. 657 'let job2: job = job_start("donothing")\_s*' .. 658 '\d PUSHS "donothing"\_s*' .. 659 '\d BCALL job_start(argc 1)\_s*' .. 660 '\d STORE $1\_s*' .. 661 'let chan1: channel\_s*' .. 662 '\d PUSHCHANNEL 0\_s*' .. 663 '\d STORE $2\_s*' .. 664 '\d PUSHNR 0\_s*' .. 665 '\d RETURN', 666 instr) 667enddef 668 669def WithLambda(): string 670 let F = {a -> "X" .. a .. "X"} 671 return F("x") 672enddef 673 674def Test_disassemble_lambda() 675 assert_equal("XxX", WithLambda()) 676 let instr = execute('disassemble WithLambda') 677 assert_match('WithLambda\_s*' .. 678 'let F = {a -> "X" .. a .. "X"}\_s*' .. 679 '\d FUNCREF <lambda>\d\+ $1\_s*' .. 680 '\d STORE $0\_s*' .. 681 'return F("x")\_s*' .. 682 '\d PUSHS "x"\_s*' .. 683 '\d LOAD $0\_s*' .. 684 '\d PCALL (argc 1)\_s*' .. 685 '\d RETURN', 686 instr) 687 688 let name = substitute(instr, '.*\(<lambda>\d\+\).*', '\1', '') 689 instr = execute('disassemble ' .. name) 690 assert_match('<lambda>\d\+\_s*' .. 691 'return "X" .. a .. "X"\_s*' .. 692 '\d PUSHS "X"\_s*' .. 693 '\d LOAD arg\[-1\]\_s*' .. 694 '\d 2STRING stack\[-1\]\_s*' .. 695 '\d CONCAT\_s*' .. 696 '\d PUSHS "X"\_s*' .. 697 '\d CONCAT\_s*' .. 698 '\d RETURN', 699 instr) 700enddef 701 702def NestedOuter() 703 def g:Inner() 704 echomsg "inner" 705 enddef 706enddef 707 708def Test_nested_func() 709 let instr = execute('disassemble NestedOuter') 710 assert_match('NestedOuter\_s*' .. 711 'def g:Inner()\_s*' .. 712 'echomsg "inner"\_s*' .. 713 'enddef\_s*' .. 714 '\d NEWFUNC <lambda>\d\+ Inner\_s*' .. 715 '\d PUSHNR 0\_s*' .. 716 '\d RETURN', 717 instr) 718enddef 719 720def AndOr(arg: any): string 721 if arg == 1 && arg != 2 || arg == 4 722 return 'yes' 723 endif 724 return 'no' 725enddef 726 727def Test_disassemble_and_or() 728 assert_equal("yes", AndOr(1)) 729 assert_equal("no", AndOr(2)) 730 assert_equal("yes", AndOr(4)) 731 let instr = execute('disassemble AndOr') 732 assert_match('AndOr\_s*' .. 733 'if arg == 1 && arg != 2 || arg == 4\_s*' .. 734 '\d LOAD arg\[-1]\_s*' .. 735 '\d PUSHNR 1\_s*' .. 736 '\d COMPAREANY ==\_s*' .. 737 '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' .. 738 '\d LOAD arg\[-1]\_s*' .. 739 '\d PUSHNR 2\_s*' .. 740 '\d COMPAREANY !=\_s*' .. 741 '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' .. 742 '\d LOAD arg\[-1]\_s*' .. 743 '\d\+ PUSHNR 4\_s*' .. 744 '\d\+ COMPAREANY ==\_s*' .. 745 '\d\+ JUMP_IF_FALSE -> \d\+', 746 instr) 747enddef 748 749def ForLoop(): list<number> 750 let res: list<number> 751 for i in range(3) 752 res->add(i) 753 endfor 754 return res 755enddef 756 757def Test_disassemble_for_loop() 758 assert_equal([0, 1, 2], ForLoop()) 759 let instr = execute('disassemble ForLoop') 760 assert_match('ForLoop\_s*' .. 761 'let res: list<number>\_s*' .. 762 '\d NEWLIST size 0\_s*' .. 763 '\d STORE $0\_s*' .. 764 'for i in range(3)\_s*' .. 765 '\d STORE -1 in $1\_s*' .. 766 '\d PUSHNR 3\_s*' .. 767 '\d BCALL range(argc 1)\_s*' .. 768 '\d FOR $1 -> \d\+\_s*' .. 769 '\d STORE $2\_s*' .. 770 'res->add(i)\_s*' .. 771 '\d LOAD $0\_s*' .. 772 '\d LOAD $2\_s*' .. 773 '\d\+ BCALL add(argc 2)\_s*' .. 774 '\d\+ DROP\_s*' .. 775 'endfor\_s*' .. 776 '\d\+ JUMP -> \d\+\_s*' .. 777 '\d\+ DROP', 778 instr) 779enddef 780 781def ForLoopEval(): string 782 let res = "" 783 for str in eval('["one", "two"]') 784 res ..= str 785 endfor 786 return res 787enddef 788 789def Test_disassemble_for_loop_eval() 790 assert_equal('onetwo', ForLoopEval()) 791 let instr = execute('disassemble ForLoopEval') 792 assert_match('ForLoopEval\_s*' .. 793 'let res = ""\_s*' .. 794 '\d PUSHS ""\_s*' .. 795 '\d STORE $0\_s*' .. 796 'for str in eval(''\["one", "two"\]'')\_s*' .. 797 '\d STORE -1 in $1\_s*' .. 798 '\d PUSHS "\["one", "two"\]"\_s*' .. 799 '\d BCALL eval(argc 1)\_s*' .. 800 '\d CHECKTYPE list stack\[-1\]\_s*' .. 801 '\d FOR $1 -> \d\+\_s*' .. 802 '\d STORE $2\_s*' .. 803 'res ..= str\_s*' .. 804 '\d\+ LOAD $0\_s*' .. 805 '\d\+ LOAD $2\_s*' .. 806 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 807 '\d\+ CONCAT\_s*' .. 808 '\d\+ STORE $0\_s*' .. 809 'endfor\_s*' .. 810 '\d\+ JUMP -> 6\_s*' .. 811 '\d\+ DROP\_s*' .. 812 'return res\_s*' .. 813 '\d\+ LOAD $0\_s*' .. 814 '\d\+ RETURN', 815 instr) 816enddef 817 818let g:number = 42 819 820def Computing() 821 let nr = 3 822 let nrres = nr + 7 823 nrres = nr - 7 824 nrres = nr * 7 825 nrres = nr / 7 826 nrres = nr % 7 827 828 let anyres = g:number + 7 829 anyres = g:number - 7 830 anyres = g:number * 7 831 anyres = g:number / 7 832 anyres = g:number % 7 833 834 if has('float') 835 let fl = 3.0 836 let flres = fl + 7.0 837 flres = fl - 7.0 838 flres = fl * 7.0 839 flres = fl / 7.0 840 endif 841enddef 842 843def Test_disassemble_computing() 844 let instr = execute('disassemble Computing') 845 assert_match('Computing.*' .. 846 'let nr = 3.*' .. 847 '\d STORE 3 in $0.*' .. 848 'let nrres = nr + 7.*' .. 849 '\d LOAD $0.*' .. 850 '\d PUSHNR 7.*' .. 851 '\d OPNR +.*' .. 852 '\d STORE $1.*' .. 853 'nrres = nr - 7.*' .. 854 '\d OPNR -.*' .. 855 'nrres = nr \* 7.*' .. 856 '\d OPNR \*.*' .. 857 'nrres = nr / 7.*' .. 858 '\d OPNR /.*' .. 859 'nrres = nr % 7.*' .. 860 '\d OPNR %.*' .. 861 'let anyres = g:number + 7.*' .. 862 '\d LOADG g:number.*' .. 863 '\d PUSHNR 7.*' .. 864 '\d OPANY +.*' .. 865 '\d STORE $2.*' .. 866 'anyres = g:number - 7.*' .. 867 '\d OPANY -.*' .. 868 'anyres = g:number \* 7.*' .. 869 '\d OPANY \*.*' .. 870 'anyres = g:number / 7.*' .. 871 '\d OPANY /.*' .. 872 'anyres = g:number % 7.*' .. 873 '\d OPANY %.*', 874 instr) 875 if has('float') 876 assert_match('Computing.*' .. 877 'let fl = 3.0.*' .. 878 '\d PUSHF 3.0.*' .. 879 '\d STORE $3.*' .. 880 'let flres = fl + 7.0.*' .. 881 '\d LOAD $3.*' .. 882 '\d PUSHF 7.0.*' .. 883 '\d OPFLOAT +.*' .. 884 '\d STORE $4.*' .. 885 'flres = fl - 7.0.*' .. 886 '\d OPFLOAT -.*' .. 887 'flres = fl \* 7.0.*' .. 888 '\d OPFLOAT \*.*' .. 889 'flres = fl / 7.0.*' .. 890 '\d OPFLOAT /.*', 891 instr) 892 endif 893enddef 894 895def AddListBlob() 896 let reslist = [1, 2] + [3, 4] 897 let resblob = 0z1122 + 0z3344 898enddef 899 900def Test_disassemble_add_list_blob() 901 let instr = execute('disassemble AddListBlob') 902 assert_match('AddListBlob.*' .. 903 'let reslist = \[1, 2] + \[3, 4].*' .. 904 '\d PUSHNR 1.*' .. 905 '\d PUSHNR 2.*' .. 906 '\d NEWLIST size 2.*' .. 907 '\d PUSHNR 3.*' .. 908 '\d PUSHNR 4.*' .. 909 '\d NEWLIST size 2.*' .. 910 '\d ADDLIST.*' .. 911 '\d STORE $.*.*' .. 912 'let resblob = 0z1122 + 0z3344.*' .. 913 '\d PUSHBLOB 0z1122.*' .. 914 '\d PUSHBLOB 0z3344.*' .. 915 '\d ADDBLOB.*' .. 916 '\d STORE $.*', 917 instr) 918enddef 919 920let g:aa = 'aa' 921def ConcatString(): string 922 let res = g:aa .. "bb" 923 return res 924enddef 925 926def Test_disassemble_concat() 927 let instr = execute('disassemble ConcatString') 928 assert_match('ConcatString.*' .. 929 'let res = g:aa .. "bb".*' .. 930 '\d LOADG g:aa.*' .. 931 '\d PUSHS "bb".*' .. 932 '\d 2STRING stack\[-2].*' .. 933 '\d CONCAT.*' .. 934 '\d STORE $.*', 935 instr) 936 assert_equal('aabb', ConcatString()) 937enddef 938 939def StringIndex(): number 940 let s = "abcd" 941 let res = s[1] 942 return res 943enddef 944 945def Test_disassemble_string_index() 946 let instr = execute('disassemble StringIndex') 947 assert_match('StringIndex\_s*' .. 948 'let s = "abcd"\_s*' .. 949 '\d PUSHS "abcd"\_s*' .. 950 '\d STORE $0\_s*' .. 951 'let res = s\[1]\_s*' .. 952 '\d LOAD $0\_s*' .. 953 '\d PUSHNR 1\_s*' .. 954 '\d STRINDEX\_s*' .. 955 '\d STORE $1\_s*', 956 instr) 957 assert_equal('b', StringIndex()) 958enddef 959 960def ListIndex(): number 961 let l = [1, 2, 3] 962 let res = l[1] 963 return res 964enddef 965 966def Test_disassemble_list_index() 967 let instr = execute('disassemble ListIndex') 968 assert_match('ListIndex\_s*' .. 969 'let l = \[1, 2, 3]\_s*' .. 970 '\d PUSHNR 1\_s*' .. 971 '\d PUSHNR 2\_s*' .. 972 '\d PUSHNR 3\_s*' .. 973 '\d NEWLIST size 3\_s*' .. 974 '\d STORE $0\_s*' .. 975 'let res = l\[1]\_s*' .. 976 '\d LOAD $0\_s*' .. 977 '\d PUSHNR 1\_s*' .. 978 '\d LISTINDEX\_s*' .. 979 '\d STORE $1\_s*', 980 instr) 981 assert_equal(2, ListIndex()) 982enddef 983 984def DictMember(): number 985 let d = #{item: 1} 986 let res = d.item 987 res = d["item"] 988 return res 989enddef 990 991def Test_disassemble_dict_member() 992 let instr = execute('disassemble DictMember') 993 assert_match('DictMember\_s*' .. 994 'let d = #{item: 1}\_s*' .. 995 '\d PUSHS "item"\_s*' .. 996 '\d PUSHNR 1\_s*' .. 997 '\d NEWDICT size 1\_s*' .. 998 '\d STORE $0\_s*' .. 999 'let res = d.item\_s*' .. 1000 '\d\+ LOAD $0\_s*' .. 1001 '\d\+ MEMBER item\_s*' .. 1002 '\d\+ STORE $1\_s*' .. 1003 'res = d\["item"\]\_s*' .. 1004 '\d\+ LOAD $0\_s*' .. 1005 '\d\+ PUSHS "item"\_s*' .. 1006 '\d\+ MEMBER\_s*' .. 1007 '\d\+ STORE $1\_s*', 1008 instr) 1009 call assert_equal(1, DictMember()) 1010enddef 1011 1012def NegateNumber(): number 1013 let nr = 9 1014 let plus = +nr 1015 let res = -nr 1016 return res 1017enddef 1018 1019def Test_disassemble_negate_number() 1020 let instr = execute('disassemble NegateNumber') 1021 assert_match('NegateNumber\_s*' .. 1022 'let nr = 9\_s*' .. 1023 '\d STORE 9 in $0\_s*' .. 1024 'let plus = +nr\_s*' .. 1025 '\d LOAD $0\_s*' .. 1026 '\d CHECKNR\_s*' .. 1027 '\d STORE $1\_s*' .. 1028 'let res = -nr\_s*' .. 1029 '\d LOAD $0\_s*' .. 1030 '\d NEGATENR\_s*' .. 1031 '\d STORE $2\_s*', 1032 instr) 1033 call assert_equal(-9, NegateNumber()) 1034enddef 1035 1036def InvertBool(): bool 1037 let flag = true 1038 let invert = !flag 1039 let res = !!flag 1040 return res 1041enddef 1042 1043def Test_disassemble_invert_bool() 1044 let instr = execute('disassemble InvertBool') 1045 assert_match('InvertBool\_s*' .. 1046 'let flag = true\_s*' .. 1047 '\d PUSH v:true\_s*' .. 1048 '\d STORE $0\_s*' .. 1049 'let invert = !flag\_s*' .. 1050 '\d LOAD $0\_s*' .. 1051 '\d INVERT (!val)\_s*' .. 1052 '\d STORE $1\_s*' .. 1053 'let res = !!flag\_s*' .. 1054 '\d LOAD $0\_s*' .. 1055 '\d 2BOOL (!!val)\_s*' .. 1056 '\d STORE $2\_s*', 1057 instr) 1058 call assert_equal(true, InvertBool()) 1059enddef 1060 1061def Test_disassemble_compare() 1062 let cases = [ 1063 ['true == isFalse', 'COMPAREBOOL =='], 1064 ['true != isFalse', 'COMPAREBOOL !='], 1065 ['v:none == isNull', 'COMPARESPECIAL =='], 1066 ['v:none != isNull', 'COMPARESPECIAL !='], 1067 1068 ['111 == aNumber', 'COMPARENR =='], 1069 ['111 != aNumber', 'COMPARENR !='], 1070 ['111 > aNumber', 'COMPARENR >'], 1071 ['111 < aNumber', 'COMPARENR <'], 1072 ['111 >= aNumber', 'COMPARENR >='], 1073 ['111 <= aNumber', 'COMPARENR <='], 1074 ['111 =~ aNumber', 'COMPARENR =\~'], 1075 ['111 !~ aNumber', 'COMPARENR !\~'], 1076 1077 ['"xx" != aString', 'COMPARESTRING !='], 1078 ['"xx" > aString', 'COMPARESTRING >'], 1079 ['"xx" < aString', 'COMPARESTRING <'], 1080 ['"xx" >= aString', 'COMPARESTRING >='], 1081 ['"xx" <= aString', 'COMPARESTRING <='], 1082 ['"xx" =~ aString', 'COMPARESTRING =\~'], 1083 ['"xx" !~ aString', 'COMPARESTRING !\~'], 1084 ['"xx" is aString', 'COMPARESTRING is'], 1085 ['"xx" isnot aString', 'COMPARESTRING isnot'], 1086 1087 ['0z11 == aBlob', 'COMPAREBLOB =='], 1088 ['0z11 != aBlob', 'COMPAREBLOB !='], 1089 ['0z11 is aBlob', 'COMPAREBLOB is'], 1090 ['0z11 isnot aBlob', 'COMPAREBLOB isnot'], 1091 1092 ['[1, 2] == aList', 'COMPARELIST =='], 1093 ['[1, 2] != aList', 'COMPARELIST !='], 1094 ['[1, 2] is aList', 'COMPARELIST is'], 1095 ['[1, 2] isnot aList', 'COMPARELIST isnot'], 1096 1097 ['#{a: 1} == aDict', 'COMPAREDICT =='], 1098 ['#{a: 1} != aDict', 'COMPAREDICT !='], 1099 ['#{a: 1} is aDict', 'COMPAREDICT is'], 1100 ['#{a: 1} isnot aDict', 'COMPAREDICT isnot'], 1101 1102 ['{->33} == {->44}', 'COMPAREFUNC =='], 1103 ['{->33} != {->44}', 'COMPAREFUNC !='], 1104 ['{->33} is {->44}', 'COMPAREFUNC is'], 1105 ['{->33} isnot {->44}', 'COMPAREFUNC isnot'], 1106 1107 ['77 == g:xx', 'COMPAREANY =='], 1108 ['77 != g:xx', 'COMPAREANY !='], 1109 ['77 > g:xx', 'COMPAREANY >'], 1110 ['77 < g:xx', 'COMPAREANY <'], 1111 ['77 >= g:xx', 'COMPAREANY >='], 1112 ['77 <= g:xx', 'COMPAREANY <='], 1113 ['77 =~ g:xx', 'COMPAREANY =\~'], 1114 ['77 !~ g:xx', 'COMPAREANY !\~'], 1115 ['77 is g:xx', 'COMPAREANY is'], 1116 ['77 isnot g:xx', 'COMPAREANY isnot'], 1117 ] 1118 let floatDecl = '' 1119 if has('float') 1120 cases->extend([ 1121 ['1.1 == aFloat', 'COMPAREFLOAT =='], 1122 ['1.1 != aFloat', 'COMPAREFLOAT !='], 1123 ['1.1 > aFloat', 'COMPAREFLOAT >'], 1124 ['1.1 < aFloat', 'COMPAREFLOAT <'], 1125 ['1.1 >= aFloat', 'COMPAREFLOAT >='], 1126 ['1.1 <= aFloat', 'COMPAREFLOAT <='], 1127 ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'], 1128 ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'], 1129 ]) 1130 floatDecl = 'let aFloat = 2.2' 1131 endif 1132 1133 let nr = 1 1134 for case in cases 1135 # declare local variables to get a non-constant with the right type 1136 writefile(['def TestCase' .. nr .. '()', 1137 ' let isFalse = false', 1138 ' let isNull = v:null', 1139 ' let aNumber = 222', 1140 ' let aString = "yy"', 1141 ' let aBlob = 0z22', 1142 ' let aList = [3, 4]', 1143 ' let aDict = #{x: 2}', 1144 floatDecl, 1145 ' if ' .. case[0], 1146 ' echo 42' 1147 ' endif', 1148 'enddef'], 'Xdisassemble') 1149 source Xdisassemble 1150 let instr = execute('disassemble TestCase' .. nr) 1151 assert_match('TestCase' .. nr .. '.*' .. 1152 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1153 '\d \(PUSH\|FUNCREF\).*' .. 1154 '\d \(PUSH\|FUNCREF\|LOAD\).*' .. 1155 '\d ' .. case[1] .. '.*' .. 1156 '\d JUMP_IF_FALSE -> \d\+.*', 1157 instr) 1158 1159 nr += 1 1160 endfor 1161 1162 delete('Xdisassemble') 1163enddef 1164 1165def Test_disassemble_compare_const() 1166 let cases = [ 1167 ['"xx" == "yy"', false], 1168 ['"aa" == "aa"', true], 1169 ['has("eval") ? true : false', true], 1170 ['has("asdf") ? true : false', false], 1171 ] 1172 1173 let nr = 1 1174 for case in cases 1175 writefile(['def TestCase' .. nr .. '()', 1176 ' if ' .. case[0], 1177 ' echo 42' 1178 ' endif', 1179 'enddef'], 'Xdisassemble') 1180 source Xdisassemble 1181 let instr = execute('disassemble TestCase' .. nr) 1182 if case[1] 1183 # condition true, "echo 42" executed 1184 assert_match('TestCase' .. nr .. '.*' .. 1185 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1186 '\d PUSHNR 42.*' .. 1187 '\d ECHO 1.*' .. 1188 '\d PUSHNR 0.*' .. 1189 '\d RETURN.*', 1190 instr) 1191 else 1192 # condition false, function just returns 1193 assert_match('TestCase' .. nr .. '.*' .. 1194 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' .. 1195 'echo 42[ \n]*' .. 1196 'endif[ \n]*' .. 1197 '\s*\d PUSHNR 0.*' .. 1198 '\d RETURN.*', 1199 instr) 1200 endif 1201 1202 nr += 1 1203 endfor 1204 1205 delete('Xdisassemble') 1206enddef 1207 1208def s:Execute() 1209 execute 'help vim9.txt' 1210 let cmd = 'help vim9.txt' 1211 execute cmd 1212 let tag = 'vim9.txt' 1213 execute 'help ' .. tag 1214enddef 1215 1216def Test_disassemble_execute() 1217 let res = execute('disass s:Execute') 1218 assert_match('\<SNR>\d*_Execute\_s*' .. 1219 "execute 'help vim9.txt'\\_s*" .. 1220 '\d PUSHS "help vim9.txt"\_s*' .. 1221 '\d EXECUTE 1\_s*' .. 1222 "let cmd = 'help vim9.txt'\\_s*" .. 1223 '\d PUSHS "help vim9.txt"\_s*' .. 1224 '\d STORE $0\_s*' .. 1225 'execute cmd\_s*' .. 1226 '\d LOAD $0\_s*' .. 1227 '\d EXECUTE 1\_s*' .. 1228 "let tag = 'vim9.txt'\\_s*" .. 1229 '\d PUSHS "vim9.txt"\_s*' .. 1230 '\d STORE $1\_s*' .. 1231 "execute 'help ' .. tag\\_s*" .. 1232 '\d\+ PUSHS "help "\_s*' .. 1233 '\d\+ LOAD $1\_s*' .. 1234 '\d\+ CONCAT\_s*' .. 1235 '\d\+ EXECUTE 1\_s*' .. 1236 '\d\+ PUSHNR 0\_s*' .. 1237 '\d\+ RETURN', 1238 res) 1239enddef 1240 1241def s:Echomsg() 1242 echomsg 'some' 'message' 1243 echoerr 'went' .. 'wrong' 1244enddef 1245 1246def Test_disassemble_echomsg() 1247 let res = execute('disass s:Echomsg') 1248 assert_match('\<SNR>\d*_Echomsg\_s*' .. 1249 "echomsg 'some' 'message'\\_s*" .. 1250 '\d PUSHS "some"\_s*' .. 1251 '\d PUSHS "message"\_s*' .. 1252 '\d ECHOMSG 2\_s*' .. 1253 "echoerr 'went' .. 'wrong'\\_s*" .. 1254 '\d PUSHS "wentwrong"\_s*' .. 1255 '\d ECHOERR 1\_s*' .. 1256 '\d PUSHNR 0\_s*' .. 1257 '\d RETURN', 1258 res) 1259enddef 1260 1261def SomeStringArg(arg: string) 1262 echo arg 1263enddef 1264 1265def SomeAnyArg(arg: any) 1266 echo arg 1267enddef 1268 1269def SomeStringArgAndReturn(arg: string): string 1270 return arg 1271enddef 1272 1273def Test_display_func() 1274 let res1 = execute('function SomeStringArg') 1275 assert_match('.* def SomeStringArg(arg: string)\_s*' .. 1276 '\d *echo arg.*' .. 1277 ' *enddef', 1278 res1) 1279 1280 let res2 = execute('function SomeAnyArg') 1281 assert_match('.* def SomeAnyArg(arg: any)\_s*' .. 1282 '\d *echo arg\_s*' .. 1283 ' *enddef', 1284 res2) 1285 1286 let res3 = execute('function SomeStringArgAndReturn') 1287 assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' .. 1288 '\d *return arg\_s*' .. 1289 ' *enddef', 1290 res3) 1291enddef 1292 1293def Test_vim9script_forward_func() 1294 let lines =<< trim END 1295 vim9script 1296 def FuncOne(): string 1297 return FuncTwo() 1298 enddef 1299 def FuncTwo(): string 1300 return 'two' 1301 enddef 1302 g:res_FuncOne = execute('disass FuncOne') 1303 END 1304 writefile(lines, 'Xdisassemble') 1305 source Xdisassemble 1306 1307 # check that the first function calls the second with DCALL 1308 assert_match('\<SNR>\d*_FuncOne\_s*' .. 1309 'return FuncTwo()\_s*' .. 1310 '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' .. 1311 '\d RETURN', 1312 g:res_FuncOne) 1313 1314 delete('Xdisassemble') 1315 unlet g:res_FuncOne 1316enddef 1317 1318def s:ConcatStrings(): string 1319 return 'one' .. 'two' .. 'three' 1320enddef 1321 1322def s:ComputeConst(): number 1323 return 2 + 3 * 4 / 6 + 7 1324enddef 1325 1326def s:ComputeConstParen(): number 1327 return ((2 + 4) * (8 / 2)) / (3 + 4) 1328enddef 1329 1330def Test_simplify_const_expr() 1331 let res = execute('disass s:ConcatStrings') 1332 assert_match('<SNR>\d*_ConcatStrings\_s*' .. 1333 "return 'one' .. 'two' .. 'three'\\_s*" .. 1334 '\d PUSHS "onetwothree"\_s*' .. 1335 '\d RETURN', 1336 res) 1337 1338 res = execute('disass s:ComputeConst') 1339 assert_match('<SNR>\d*_ComputeConst\_s*' .. 1340 'return 2 + 3 \* 4 / 6 + 7\_s*' .. 1341 '\d PUSHNR 11\_s*' .. 1342 '\d RETURN', 1343 res) 1344 1345 res = execute('disass s:ComputeConstParen') 1346 assert_match('<SNR>\d*_ComputeConstParen\_s*' .. 1347 'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' .. 1348 '\d PUSHNR 3\>\_s*' .. 1349 '\d RETURN', 1350 res) 1351enddef 1352 1353def s:CallAppend() 1354 eval "some text"->append(2) 1355enddef 1356 1357def Test_shuffle() 1358 let res = execute('disass s:CallAppend') 1359 assert_match('<SNR>\d*_CallAppend\_s*' .. 1360 'eval "some text"->append(2)\_s*' .. 1361 '\d PUSHS "some text"\_s*' .. 1362 '\d PUSHNR 2\_s*' .. 1363 '\d SHUFFLE 2 up 1\_s*' .. 1364 '\d BCALL append(argc 2)\_s*' .. 1365 '\d DROP\_s*' .. 1366 '\d PUSHNR 0\_s*' .. 1367 '\d RETURN', 1368 res) 1369enddef 1370 1371" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 1372