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 AndOr(arg: any): string 703 if arg == 1 && arg != 2 || arg == 4 704 return 'yes' 705 endif 706 return 'no' 707enddef 708 709def Test_disassemble_and_or() 710 assert_equal("yes", AndOr(1)) 711 assert_equal("no", AndOr(2)) 712 assert_equal("yes", AndOr(4)) 713 let instr = execute('disassemble AndOr') 714 assert_match('AndOr\_s*' .. 715 'if arg == 1 && arg != 2 || arg == 4\_s*' .. 716 '\d LOAD arg\[-1]\_s*' .. 717 '\d PUSHNR 1\_s*' .. 718 '\d COMPAREANY ==\_s*' .. 719 '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' .. 720 '\d LOAD arg\[-1]\_s*' .. 721 '\d PUSHNR 2\_s*' .. 722 '\d COMPAREANY !=\_s*' .. 723 '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' .. 724 '\d LOAD arg\[-1]\_s*' .. 725 '\d\+ PUSHNR 4\_s*' .. 726 '\d\+ COMPAREANY ==\_s*' .. 727 '\d\+ JUMP_IF_FALSE -> \d\+', 728 instr) 729enddef 730 731def ForLoop(): list<number> 732 let res: list<number> 733 for i in range(3) 734 res->add(i) 735 endfor 736 return res 737enddef 738 739def Test_disassemble_for_loop() 740 assert_equal([0, 1, 2], ForLoop()) 741 let instr = execute('disassemble ForLoop') 742 assert_match('ForLoop\_s*' .. 743 'let res: list<number>\_s*' .. 744 '\d NEWLIST size 0\_s*' .. 745 '\d STORE $0\_s*' .. 746 'for i in range(3)\_s*' .. 747 '\d STORE -1 in $1\_s*' .. 748 '\d PUSHNR 3\_s*' .. 749 '\d BCALL range(argc 1)\_s*' .. 750 '\d FOR $1 -> \d\+\_s*' .. 751 '\d STORE $2\_s*' .. 752 'res->add(i)\_s*' .. 753 '\d LOAD $0\_s*' .. 754 '\d LOAD $2\_s*' .. 755 '\d\+ BCALL add(argc 2)\_s*' .. 756 '\d\+ DROP\_s*' .. 757 'endfor\_s*' .. 758 '\d\+ JUMP -> \d\+\_s*' .. 759 '\d\+ DROP', 760 instr) 761enddef 762 763def ForLoopEval(): string 764 let res = "" 765 for str in eval('["one", "two"]') 766 res ..= str 767 endfor 768 return res 769enddef 770 771def Test_disassemble_for_loop_eval() 772 assert_equal('onetwo', ForLoopEval()) 773 let instr = execute('disassemble ForLoopEval') 774 assert_match('ForLoopEval\_s*' .. 775 'let res = ""\_s*' .. 776 '\d PUSHS ""\_s*' .. 777 '\d STORE $0\_s*' .. 778 'for str in eval(''\["one", "two"\]'')\_s*' .. 779 '\d STORE -1 in $1\_s*' .. 780 '\d PUSHS "\["one", "two"\]"\_s*' .. 781 '\d BCALL eval(argc 1)\_s*' .. 782 '\d CHECKTYPE list stack\[-1\]\_s*' .. 783 '\d FOR $1 -> \d\+\_s*' .. 784 '\d STORE $2\_s*' .. 785 'res ..= str\_s*' .. 786 '\d\+ LOAD $0\_s*' .. 787 '\d\+ LOAD $2\_s*' .. 788 '\d\+ CHECKTYPE string stack\[-1\]\_s*' .. 789 '\d\+ CONCAT\_s*' .. 790 '\d\+ STORE $0\_s*' .. 791 'endfor\_s*' .. 792 '\d\+ JUMP -> 6\_s*' .. 793 '\d\+ DROP\_s*' .. 794 'return res\_s*' .. 795 '\d\+ LOAD $0\_s*' .. 796 '\d\+ RETURN', 797 instr) 798enddef 799 800let g:number = 42 801 802def Computing() 803 let nr = 3 804 let nrres = nr + 7 805 nrres = nr - 7 806 nrres = nr * 7 807 nrres = nr / 7 808 nrres = nr % 7 809 810 let anyres = g:number + 7 811 anyres = g:number - 7 812 anyres = g:number * 7 813 anyres = g:number / 7 814 anyres = g:number % 7 815 816 if has('float') 817 let fl = 3.0 818 let flres = fl + 7.0 819 flres = fl - 7.0 820 flres = fl * 7.0 821 flres = fl / 7.0 822 endif 823enddef 824 825def Test_disassemble_computing() 826 let instr = execute('disassemble Computing') 827 assert_match('Computing.*' .. 828 'let nr = 3.*' .. 829 '\d STORE 3 in $0.*' .. 830 'let nrres = nr + 7.*' .. 831 '\d LOAD $0.*' .. 832 '\d PUSHNR 7.*' .. 833 '\d OPNR +.*' .. 834 '\d STORE $1.*' .. 835 'nrres = nr - 7.*' .. 836 '\d OPNR -.*' .. 837 'nrres = nr \* 7.*' .. 838 '\d OPNR \*.*' .. 839 'nrres = nr / 7.*' .. 840 '\d OPNR /.*' .. 841 'nrres = nr % 7.*' .. 842 '\d OPNR %.*' .. 843 'let anyres = g:number + 7.*' .. 844 '\d LOADG g:number.*' .. 845 '\d PUSHNR 7.*' .. 846 '\d OPANY +.*' .. 847 '\d STORE $2.*' .. 848 'anyres = g:number - 7.*' .. 849 '\d OPANY -.*' .. 850 'anyres = g:number \* 7.*' .. 851 '\d OPANY \*.*' .. 852 'anyres = g:number / 7.*' .. 853 '\d OPANY /.*' .. 854 'anyres = g:number % 7.*' .. 855 '\d OPANY %.*', 856 instr) 857 if has('float') 858 assert_match('Computing.*' .. 859 'let fl = 3.0.*' .. 860 '\d PUSHF 3.0.*' .. 861 '\d STORE $3.*' .. 862 'let flres = fl + 7.0.*' .. 863 '\d LOAD $3.*' .. 864 '\d PUSHF 7.0.*' .. 865 '\d OPFLOAT +.*' .. 866 '\d STORE $4.*' .. 867 'flres = fl - 7.0.*' .. 868 '\d OPFLOAT -.*' .. 869 'flres = fl \* 7.0.*' .. 870 '\d OPFLOAT \*.*' .. 871 'flres = fl / 7.0.*' .. 872 '\d OPFLOAT /.*', 873 instr) 874 endif 875enddef 876 877def AddListBlob() 878 let reslist = [1, 2] + [3, 4] 879 let resblob = 0z1122 + 0z3344 880enddef 881 882def Test_disassemble_add_list_blob() 883 let instr = execute('disassemble AddListBlob') 884 assert_match('AddListBlob.*' .. 885 'let reslist = \[1, 2] + \[3, 4].*' .. 886 '\d PUSHNR 1.*' .. 887 '\d PUSHNR 2.*' .. 888 '\d NEWLIST size 2.*' .. 889 '\d PUSHNR 3.*' .. 890 '\d PUSHNR 4.*' .. 891 '\d NEWLIST size 2.*' .. 892 '\d ADDLIST.*' .. 893 '\d STORE $.*.*' .. 894 'let resblob = 0z1122 + 0z3344.*' .. 895 '\d PUSHBLOB 0z1122.*' .. 896 '\d PUSHBLOB 0z3344.*' .. 897 '\d ADDBLOB.*' .. 898 '\d STORE $.*', 899 instr) 900enddef 901 902let g:aa = 'aa' 903def ConcatString(): string 904 let res = g:aa .. "bb" 905 return res 906enddef 907 908def Test_disassemble_concat() 909 let instr = execute('disassemble ConcatString') 910 assert_match('ConcatString.*' .. 911 'let res = g:aa .. "bb".*' .. 912 '\d LOADG g:aa.*' .. 913 '\d PUSHS "bb".*' .. 914 '\d 2STRING stack\[-2].*' .. 915 '\d CONCAT.*' .. 916 '\d STORE $.*', 917 instr) 918 assert_equal('aabb', ConcatString()) 919enddef 920 921def StringIndex(): number 922 let s = "abcd" 923 let res = s[1] 924 return res 925enddef 926 927def Test_disassemble_string_index() 928 let instr = execute('disassemble StringIndex') 929 assert_match('StringIndex\_s*' .. 930 'let s = "abcd"\_s*' .. 931 '\d PUSHS "abcd"\_s*' .. 932 '\d STORE $0\_s*' .. 933 'let res = s\[1]\_s*' .. 934 '\d LOAD $0\_s*' .. 935 '\d PUSHNR 1\_s*' .. 936 '\d STRINDEX\_s*' .. 937 '\d STORE $1\_s*', 938 instr) 939 assert_equal('b', StringIndex()) 940enddef 941 942def ListIndex(): number 943 let l = [1, 2, 3] 944 let res = l[1] 945 return res 946enddef 947 948def Test_disassemble_list_index() 949 let instr = execute('disassemble ListIndex') 950 assert_match('ListIndex\_s*' .. 951 'let l = \[1, 2, 3]\_s*' .. 952 '\d PUSHNR 1\_s*' .. 953 '\d PUSHNR 2\_s*' .. 954 '\d PUSHNR 3\_s*' .. 955 '\d NEWLIST size 3\_s*' .. 956 '\d STORE $0\_s*' .. 957 'let res = l\[1]\_s*' .. 958 '\d LOAD $0\_s*' .. 959 '\d PUSHNR 1\_s*' .. 960 '\d LISTINDEX\_s*' .. 961 '\d STORE $1\_s*', 962 instr) 963 assert_equal(2, ListIndex()) 964enddef 965 966def DictMember(): number 967 let d = #{item: 1} 968 let res = d.item 969 res = d["item"] 970 return res 971enddef 972 973def Test_disassemble_dict_member() 974 let instr = execute('disassemble DictMember') 975 assert_match('DictMember\_s*' .. 976 'let d = #{item: 1}\_s*' .. 977 '\d PUSHS "item"\_s*' .. 978 '\d PUSHNR 1\_s*' .. 979 '\d NEWDICT size 1\_s*' .. 980 '\d STORE $0\_s*' .. 981 'let res = d.item\_s*' .. 982 '\d\+ LOAD $0\_s*' .. 983 '\d\+ MEMBER item\_s*' .. 984 '\d\+ STORE $1\_s*' .. 985 'res = d\["item"\]\_s*' .. 986 '\d\+ LOAD $0\_s*' .. 987 '\d\+ PUSHS "item"\_s*' .. 988 '\d\+ MEMBER\_s*' .. 989 '\d\+ STORE $1\_s*', 990 instr) 991 call assert_equal(1, DictMember()) 992enddef 993 994def NegateNumber(): number 995 let nr = 9 996 let plus = +nr 997 let res = -nr 998 return res 999enddef 1000 1001def Test_disassemble_negate_number() 1002 let instr = execute('disassemble NegateNumber') 1003 assert_match('NegateNumber\_s*' .. 1004 'let nr = 9\_s*' .. 1005 '\d STORE 9 in $0\_s*' .. 1006 'let plus = +nr\_s*' .. 1007 '\d LOAD $0\_s*' .. 1008 '\d CHECKNR\_s*' .. 1009 '\d STORE $1\_s*' .. 1010 'let res = -nr\_s*' .. 1011 '\d LOAD $0\_s*' .. 1012 '\d NEGATENR\_s*' .. 1013 '\d STORE $2\_s*', 1014 instr) 1015 call assert_equal(-9, NegateNumber()) 1016enddef 1017 1018def InvertBool(): bool 1019 let flag = true 1020 let invert = !flag 1021 let res = !!flag 1022 return res 1023enddef 1024 1025def Test_disassemble_invert_bool() 1026 let instr = execute('disassemble InvertBool') 1027 assert_match('InvertBool\_s*' .. 1028 'let flag = true\_s*' .. 1029 '\d PUSH v:true\_s*' .. 1030 '\d STORE $0\_s*' .. 1031 'let invert = !flag\_s*' .. 1032 '\d LOAD $0\_s*' .. 1033 '\d INVERT (!val)\_s*' .. 1034 '\d STORE $1\_s*' .. 1035 'let res = !!flag\_s*' .. 1036 '\d LOAD $0\_s*' .. 1037 '\d 2BOOL (!!val)\_s*' .. 1038 '\d STORE $2\_s*', 1039 instr) 1040 call assert_equal(true, InvertBool()) 1041enddef 1042 1043def Test_disassemble_compare() 1044 let cases = [ 1045 ['true == isFalse', 'COMPAREBOOL =='], 1046 ['true != isFalse', 'COMPAREBOOL !='], 1047 ['v:none == isNull', 'COMPARESPECIAL =='], 1048 ['v:none != isNull', 'COMPARESPECIAL !='], 1049 1050 ['111 == aNumber', 'COMPARENR =='], 1051 ['111 != aNumber', 'COMPARENR !='], 1052 ['111 > aNumber', 'COMPARENR >'], 1053 ['111 < aNumber', 'COMPARENR <'], 1054 ['111 >= aNumber', 'COMPARENR >='], 1055 ['111 <= aNumber', 'COMPARENR <='], 1056 ['111 =~ aNumber', 'COMPARENR =\~'], 1057 ['111 !~ aNumber', 'COMPARENR !\~'], 1058 1059 ['"xx" != aString', 'COMPARESTRING !='], 1060 ['"xx" > aString', 'COMPARESTRING >'], 1061 ['"xx" < aString', 'COMPARESTRING <'], 1062 ['"xx" >= aString', 'COMPARESTRING >='], 1063 ['"xx" <= aString', 'COMPARESTRING <='], 1064 ['"xx" =~ aString', 'COMPARESTRING =\~'], 1065 ['"xx" !~ aString', 'COMPARESTRING !\~'], 1066 ['"xx" is aString', 'COMPARESTRING is'], 1067 ['"xx" isnot aString', 'COMPARESTRING isnot'], 1068 1069 ['0z11 == aBlob', 'COMPAREBLOB =='], 1070 ['0z11 != aBlob', 'COMPAREBLOB !='], 1071 ['0z11 is aBlob', 'COMPAREBLOB is'], 1072 ['0z11 isnot aBlob', 'COMPAREBLOB isnot'], 1073 1074 ['[1, 2] == aList', 'COMPARELIST =='], 1075 ['[1, 2] != aList', 'COMPARELIST !='], 1076 ['[1, 2] is aList', 'COMPARELIST is'], 1077 ['[1, 2] isnot aList', 'COMPARELIST isnot'], 1078 1079 ['#{a: 1} == aDict', 'COMPAREDICT =='], 1080 ['#{a: 1} != aDict', 'COMPAREDICT !='], 1081 ['#{a: 1} is aDict', 'COMPAREDICT is'], 1082 ['#{a: 1} isnot aDict', 'COMPAREDICT isnot'], 1083 1084 ['{->33} == {->44}', 'COMPAREFUNC =='], 1085 ['{->33} != {->44}', 'COMPAREFUNC !='], 1086 ['{->33} is {->44}', 'COMPAREFUNC is'], 1087 ['{->33} isnot {->44}', 'COMPAREFUNC isnot'], 1088 1089 ['77 == g:xx', 'COMPAREANY =='], 1090 ['77 != g:xx', 'COMPAREANY !='], 1091 ['77 > g:xx', 'COMPAREANY >'], 1092 ['77 < g:xx', 'COMPAREANY <'], 1093 ['77 >= g:xx', 'COMPAREANY >='], 1094 ['77 <= g:xx', 'COMPAREANY <='], 1095 ['77 =~ g:xx', 'COMPAREANY =\~'], 1096 ['77 !~ g:xx', 'COMPAREANY !\~'], 1097 ['77 is g:xx', 'COMPAREANY is'], 1098 ['77 isnot g:xx', 'COMPAREANY isnot'], 1099 ] 1100 let floatDecl = '' 1101 if has('float') 1102 cases->extend([ 1103 ['1.1 == aFloat', 'COMPAREFLOAT =='], 1104 ['1.1 != aFloat', 'COMPAREFLOAT !='], 1105 ['1.1 > aFloat', 'COMPAREFLOAT >'], 1106 ['1.1 < aFloat', 'COMPAREFLOAT <'], 1107 ['1.1 >= aFloat', 'COMPAREFLOAT >='], 1108 ['1.1 <= aFloat', 'COMPAREFLOAT <='], 1109 ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'], 1110 ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'], 1111 ]) 1112 floatDecl = 'let aFloat = 2.2' 1113 endif 1114 1115 let nr = 1 1116 for case in cases 1117 # declare local variables to get a non-constant with the right type 1118 writefile(['def TestCase' .. nr .. '()', 1119 ' let isFalse = false', 1120 ' let isNull = v:null', 1121 ' let aNumber = 222', 1122 ' let aString = "yy"', 1123 ' let aBlob = 0z22', 1124 ' let aList = [3, 4]', 1125 ' let aDict = #{x: 2}', 1126 floatDecl, 1127 ' if ' .. case[0], 1128 ' echo 42' 1129 ' endif', 1130 'enddef'], 'Xdisassemble') 1131 source Xdisassemble 1132 let instr = execute('disassemble TestCase' .. nr) 1133 assert_match('TestCase' .. nr .. '.*' .. 1134 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1135 '\d \(PUSH\|FUNCREF\).*' .. 1136 '\d \(PUSH\|FUNCREF\|LOAD\).*' .. 1137 '\d ' .. case[1] .. '.*' .. 1138 '\d JUMP_IF_FALSE -> \d\+.*', 1139 instr) 1140 1141 nr += 1 1142 endfor 1143 1144 delete('Xdisassemble') 1145enddef 1146 1147def Test_disassemble_compare_const() 1148 let cases = [ 1149 ['"xx" == "yy"', false], 1150 ['"aa" == "aa"', true], 1151 ['has("eval") ? true : false', true], 1152 ['has("asdf") ? true : false', false], 1153 ] 1154 1155 let nr = 1 1156 for case in cases 1157 writefile(['def TestCase' .. nr .. '()', 1158 ' if ' .. case[0], 1159 ' echo 42' 1160 ' endif', 1161 'enddef'], 'Xdisassemble') 1162 source Xdisassemble 1163 let instr = execute('disassemble TestCase' .. nr) 1164 if case[1] 1165 # condition true, "echo 42" executed 1166 assert_match('TestCase' .. nr .. '.*' .. 1167 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1168 '\d PUSHNR 42.*' .. 1169 '\d ECHO 1.*' .. 1170 '\d PUSHNR 0.*' .. 1171 '\d RETURN.*', 1172 instr) 1173 else 1174 # condition false, function just returns 1175 assert_match('TestCase' .. nr .. '.*' .. 1176 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' .. 1177 'echo 42[ \n]*' .. 1178 'endif[ \n]*' .. 1179 '\s*\d PUSHNR 0.*' .. 1180 '\d RETURN.*', 1181 instr) 1182 endif 1183 1184 nr += 1 1185 endfor 1186 1187 delete('Xdisassemble') 1188enddef 1189 1190def s:Execute() 1191 execute 'help vim9.txt' 1192 let cmd = 'help vim9.txt' 1193 execute cmd 1194 let tag = 'vim9.txt' 1195 execute 'help ' .. tag 1196enddef 1197 1198def Test_disassemble_execute() 1199 let res = execute('disass s:Execute') 1200 assert_match('\<SNR>\d*_Execute\_s*' .. 1201 "execute 'help vim9.txt'\\_s*" .. 1202 '\d PUSHS "help vim9.txt"\_s*' .. 1203 '\d EXECUTE 1\_s*' .. 1204 "let cmd = 'help vim9.txt'\\_s*" .. 1205 '\d PUSHS "help vim9.txt"\_s*' .. 1206 '\d STORE $0\_s*' .. 1207 'execute cmd\_s*' .. 1208 '\d LOAD $0\_s*' .. 1209 '\d EXECUTE 1\_s*' .. 1210 "let tag = 'vim9.txt'\\_s*" .. 1211 '\d PUSHS "vim9.txt"\_s*' .. 1212 '\d STORE $1\_s*' .. 1213 "execute 'help ' .. tag\\_s*" .. 1214 '\d\+ PUSHS "help "\_s*' .. 1215 '\d\+ LOAD $1\_s*' .. 1216 '\d\+ CONCAT\_s*' .. 1217 '\d\+ EXECUTE 1\_s*' .. 1218 '\d\+ PUSHNR 0\_s*' .. 1219 '\d\+ RETURN', 1220 res) 1221enddef 1222 1223def s:Echomsg() 1224 echomsg 'some' 'message' 1225 echoerr 'went' .. 'wrong' 1226enddef 1227 1228def Test_disassemble_echomsg() 1229 let res = execute('disass s:Echomsg') 1230 assert_match('\<SNR>\d*_Echomsg\_s*' .. 1231 "echomsg 'some' 'message'\\_s*" .. 1232 '\d PUSHS "some"\_s*' .. 1233 '\d PUSHS "message"\_s*' .. 1234 '\d ECHOMSG 2\_s*' .. 1235 "echoerr 'went' .. 'wrong'\\_s*" .. 1236 '\d PUSHS "wentwrong"\_s*' .. 1237 '\d ECHOERR 1\_s*' .. 1238 '\d PUSHNR 0\_s*' .. 1239 '\d RETURN', 1240 res) 1241enddef 1242 1243def SomeStringArg(arg: string) 1244 echo arg 1245enddef 1246 1247def SomeAnyArg(arg: any) 1248 echo arg 1249enddef 1250 1251def SomeStringArgAndReturn(arg: string): string 1252 return arg 1253enddef 1254 1255def Test_display_func() 1256 let res1 = execute('function SomeStringArg') 1257 assert_match('.* def SomeStringArg(arg: string)\_s*' .. 1258 '\d *echo arg.*' .. 1259 ' *enddef', 1260 res1) 1261 1262 let res2 = execute('function SomeAnyArg') 1263 assert_match('.* def SomeAnyArg(arg: any)\_s*' .. 1264 '\d *echo arg\_s*' .. 1265 ' *enddef', 1266 res2) 1267 1268 let res3 = execute('function SomeStringArgAndReturn') 1269 assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' .. 1270 '\d *return arg\_s*' .. 1271 ' *enddef', 1272 res3) 1273enddef 1274 1275def Test_vim9script_forward_func() 1276 let lines =<< trim END 1277 vim9script 1278 def FuncOne(): string 1279 return FuncTwo() 1280 enddef 1281 def FuncTwo(): string 1282 return 'two' 1283 enddef 1284 g:res_FuncOne = execute('disass FuncOne') 1285 END 1286 writefile(lines, 'Xdisassemble') 1287 source Xdisassemble 1288 1289 # check that the first function calls the second with DCALL 1290 assert_match('\<SNR>\d*_FuncOne\_s*' .. 1291 'return FuncTwo()\_s*' .. 1292 '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' .. 1293 '\d RETURN', 1294 g:res_FuncOne) 1295 1296 delete('Xdisassemble') 1297 unlet g:res_FuncOne 1298enddef 1299 1300def s:ConcatStrings(): string 1301 return 'one' .. 'two' .. 'three' 1302enddef 1303 1304def s:ComputeConst(): number 1305 return 2 + 3 * 4 / 6 + 7 1306enddef 1307 1308def s:ComputeConstParen(): number 1309 return ((2 + 4) * (8 / 2)) / (3 + 4) 1310enddef 1311 1312def Test_simplify_const_expr() 1313 let res = execute('disass s:ConcatStrings') 1314 assert_match('<SNR>\d*_ConcatStrings\_s*' .. 1315 "return 'one' .. 'two' .. 'three'\\_s*" .. 1316 '\d PUSHS "onetwothree"\_s*' .. 1317 '\d RETURN', 1318 res) 1319 1320 res = execute('disass s:ComputeConst') 1321 assert_match('<SNR>\d*_ComputeConst\_s*' .. 1322 'return 2 + 3 \* 4 / 6 + 7\_s*' .. 1323 '\d PUSHNR 11\_s*' .. 1324 '\d RETURN', 1325 res) 1326 1327 res = execute('disass s:ComputeConstParen') 1328 assert_match('<SNR>\d*_ComputeConstParen\_s*' .. 1329 'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' .. 1330 '\d PUSHNR 3\>\_s*' .. 1331 '\d RETURN', 1332 res) 1333enddef 1334 1335def s:CallAppend() 1336 eval "some text"->append(2) 1337enddef 1338 1339def Test_shuffle() 1340 let res = execute('disass s:CallAppend') 1341 assert_match('<SNR>\d*_CallAppend\_s*' .. 1342 'eval "some text"->append(2)\_s*' .. 1343 '\d PUSHS "some text"\_s*' .. 1344 '\d PUSHNR 2\_s*' .. 1345 '\d SHUFFLE 2 up 1\_s*' .. 1346 '\d BCALL append(argc 2)\_s*' .. 1347 '\d DROP\_s*' .. 1348 '\d PUSHNR 0\_s*' .. 1349 '\d RETURN', 1350 res) 1351enddef 1352 1353" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 1354