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 void', 121 res) 122enddef 123 124if has('python3') 125 def s:PyHeredoc() 126 python3 << EOF 127 print('hello') 128EOF 129 enddef 130 131 def Test_disassemble_python_heredoc() 132 var res = execute('disass s:PyHeredoc') 133 assert_match('<SNR>\d*_PyHeredoc.*' .. 134 " python3 << EOF^@ print('hello')^@EOF\\_s*" .. 135 '\d EXEC_SPLIT python3 << EOF^@ print(''hello'')^@EOF\_s*' .. 136 '\d RETURN void', 137 res) 138 enddef 139endif 140 141def s:Substitute() 142 var expr = "abc" 143 :%s/a/\=expr/&g#c 144enddef 145 146def Test_disassemble_substitute() 147 var res = execute('disass s:Substitute') 148 assert_match('<SNR>\d*_Substitute.*' .. 149 ' var expr = "abc"\_s*' .. 150 '\d PUSHS "abc"\_s*' .. 151 '\d STORE $0\_s*' .. 152 ' :%s/a/\\=expr/&g#c\_s*' .. 153 '\d SUBSTITUTE :%s/a/\\=expr/&g#c\_s*' .. 154 ' 0 LOAD $0\_s*' .. 155 ' -------------\_s*' .. 156 '\d RETURN void', 157 res) 158enddef 159 160 161def s:SearchPair() 162 var col = 8 163 searchpair("{", "", "}", "", "col('.') > col") 164enddef 165 166def Test_disassemble_seachpair() 167 var res = execute('disass s:SearchPair') 168 assert_match('<SNR>\d*_SearchPair.*' .. 169 ' var col = 8\_s*' .. 170 '\d STORE 8 in $0\_s*' .. 171 ' searchpair("{", "", "}", "", "col(''.'') > col")\_s*' .. 172 '\d PUSHS "{"\_s*' .. 173 '\d PUSHS ""\_s*' .. 174 '\d PUSHS "}"\_s*' .. 175 '\d PUSHS ""\_s*' .. 176 '\d INSTR\_s*' .. 177 ' 0 PUSHS "."\_s*' .. 178 ' 1 BCALL col(argc 1)\_s*' .. 179 ' 2 LOAD $0\_s*' .. 180 ' 3 COMPARENR >\_s*' .. 181 ' -------------\_s*' .. 182 '\d BCALL searchpair(argc 5)\_s*' .. 183 '\d DROP\_s*' .. 184 '\d RETURN void', 185 res) 186enddef 187 188 189def s:RedirVar() 190 var result: string 191 redir =>> result 192 echo "text" 193 redir END 194enddef 195 196def Test_disassemble_redir_var() 197 var res = execute('disass s:RedirVar') 198 assert_match('<SNR>\d*_RedirVar.*' .. 199 ' var result: string\_s*' .. 200 '\d PUSHS "\[NULL\]"\_s*' .. 201 '\d STORE $0\_s*' .. 202 ' redir =>> result\_s*' .. 203 '\d REDIR\_s*' .. 204 ' echo "text"\_s*' .. 205 '\d PUSHS "text"\_s*' .. 206 '\d ECHO 1\_s*' .. 207 ' redir END\_s*' .. 208 '\d LOAD $0\_s*' .. 209 '\d REDIR END\_s*' .. 210 '\d CONCAT\_s*' .. 211 '\d STORE $0\_s*' .. 212 '\d RETURN void', 213 res) 214enddef 215 216def s:Cexpr() 217 var errors = "list of errors" 218 cexpr errors 219enddef 220 221def Test_disassemble_cexpr() 222 var res = execute('disass s:Cexpr') 223 assert_match('<SNR>\d*_Cexpr.*' .. 224 ' var errors = "list of errors"\_s*' .. 225 '\d PUSHS "list of errors"\_s*' .. 226 '\d STORE $0\_s*' .. 227 ' cexpr errors\_s*' .. 228 '\d CEXPR pre cexpr\_s*' .. 229 '\d LOAD $0\_s*' .. 230 '\d CEXPR core cexpr "cexpr errors"\_s*' .. 231 '\d RETURN void', 232 res) 233enddef 234 235def s:YankRange() 236 norm! m[jjm] 237 :'[,']yank 238enddef 239 240def Test_disassemble_yank_range() 241 var res = execute('disass s:YankRange') 242 assert_match('<SNR>\d*_YankRange.*' .. 243 ' norm! m\[jjm\]\_s*' .. 244 '\d EXEC norm! m\[jjm\]\_s*' .. 245 ' :''\[,''\]yank\_s*' .. 246 '\d EXEC :''\[,''\]yank\_s*' .. 247 '\d RETURN void', 248 res) 249enddef 250 251def s:PutExpr() 252 :3put ="text" 253enddef 254 255def Test_disassemble_put_expr() 256 var res = execute('disass s:PutExpr') 257 assert_match('<SNR>\d*_PutExpr.*' .. 258 ' :3put ="text"\_s*' .. 259 '\d PUSHS "text"\_s*' .. 260 '\d PUT = 3\_s*' .. 261 '\d RETURN void', 262 res) 263enddef 264 265def s:PutRange() 266 :$-2put a 267enddef 268 269def Test_disassemble_put_range() 270 var res = execute('disass s:PutRange') 271 assert_match('<SNR>\d*_PutRange.*' .. 272 ' :$-2put a\_s*' .. 273 '\d RANGE $-2\_s*' .. 274 '\d PUT a range\_s*' .. 275 '\d RETURN void', 276 res) 277enddef 278 279def s:ScriptFuncPush() 280 var localbool = true 281 var localspec = v:none 282 var localblob = 0z1234 283 if has('float') 284 var localfloat = 1.234 285 endif 286enddef 287 288def Test_disassemble_push() 289 var res = execute('disass s:ScriptFuncPush') 290 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 291 'localbool = true.*' .. 292 ' PUSH true.*' .. 293 'localspec = v:none.*' .. 294 ' PUSH v:none.*' .. 295 'localblob = 0z1234.*' .. 296 ' PUSHBLOB 0z1234.*', 297 res) 298 if has('float') 299 assert_match('<SNR>\d*_ScriptFuncPush.*' .. 300 'localfloat = 1.234.*' .. 301 ' PUSHF 1.234.*', 302 res) 303 endif 304enddef 305 306def s:ScriptFuncStore() 307 var localnr = 1 308 localnr = 2 309 var localstr = 'abc' 310 localstr = 'xyz' 311 v:char = 'abc' 312 s:scriptvar = 'sv' 313 g:globalvar = 'gv' 314 g:auto#var = 'av' 315 b:buffervar = 'bv' 316 w:windowvar = 'wv' 317 t:tabpagevar = 'tv' 318 &tabstop = 8 319 $ENVVAR = 'ev' 320 @z = 'rv' 321enddef 322 323def Test_disassemble_store() 324 var res = execute('disass s:ScriptFuncStore') 325 assert_match('<SNR>\d*_ScriptFuncStore.*' .. 326 'var localnr = 1.*' .. 327 'localnr = 2.*' .. 328 ' STORE 2 in $0.*' .. 329 'var localstr = ''abc''.*' .. 330 'localstr = ''xyz''.*' .. 331 ' STORE $1.*' .. 332 'v:char = ''abc''.*' .. 333 'STOREV v:char.*' .. 334 's:scriptvar = ''sv''.*' .. 335 ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' .. 336 'g:globalvar = ''gv''.*' .. 337 ' STOREG g:globalvar.*' .. 338 'g:auto#var = ''av''.*' .. 339 ' STOREAUTO g:auto#var.*' .. 340 'b:buffervar = ''bv''.*' .. 341 ' STOREB b:buffervar.*' .. 342 'w:windowvar = ''wv''.*' .. 343 ' STOREW w:windowvar.*' .. 344 't:tabpagevar = ''tv''.*' .. 345 ' STORET t:tabpagevar.*' .. 346 '&tabstop = 8.*' .. 347 ' STOREOPT &tabstop.*' .. 348 '$ENVVAR = ''ev''.*' .. 349 ' STOREENV $ENVVAR.*' .. 350 '@z = ''rv''.*' .. 351 ' STOREREG @z.*', 352 res) 353enddef 354 355def s:ScriptFuncStoreMember() 356 var locallist: list<number> = [] 357 locallist[0] = 123 358 var localdict: dict<number> = {} 359 localdict["a"] = 456 360 var localblob: blob = 0z1122 361 localblob[1] = 33 362enddef 363 364def Test_disassemble_store_member() 365 var res = execute('disass s:ScriptFuncStoreMember') 366 assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' .. 367 'var locallist: list<number> = []\_s*' .. 368 '\d NEWLIST size 0\_s*' .. 369 '\d SETTYPE list<number>\_s*' .. 370 '\d STORE $0\_s*' .. 371 'locallist\[0\] = 123\_s*' .. 372 '\d PUSHNR 123\_s*' .. 373 '\d PUSHNR 0\_s*' .. 374 '\d LOAD $0\_s*' .. 375 '\d STOREINDEX list\_s*' .. 376 'var localdict: dict<number> = {}\_s*' .. 377 '\d NEWDICT size 0\_s*' .. 378 '\d SETTYPE dict<number>\_s*' .. 379 '\d STORE $1\_s*' .. 380 'localdict\["a"\] = 456\_s*' .. 381 '\d\+ PUSHNR 456\_s*' .. 382 '\d\+ PUSHS "a"\_s*' .. 383 '\d\+ LOAD $1\_s*' .. 384 '\d\+ STOREINDEX dict\_s*' .. 385 'var localblob: blob = 0z1122\_s*' .. 386 '\d\+ PUSHBLOB 0z1122\_s*' .. 387 '\d\+ STORE $2\_s*' .. 388 'localblob\[1\] = 33\_s*' .. 389 '\d\+ PUSHNR 33\_s*' .. 390 '\d\+ PUSHNR 1\_s*' .. 391 '\d\+ LOAD $2\_s*' .. 392 '\d\+ STOREINDEX blob\_s*' .. 393 '\d\+ RETURN void', 394 res) 395enddef 396 397def s:ScriptFuncStoreIndex() 398 var d = {dd: {}} 399 d.dd[0] = 0 400enddef 401 402def Test_disassemble_store_index() 403 var res = execute('disass s:ScriptFuncStoreIndex') 404 assert_match('<SNR>\d*_ScriptFuncStoreIndex\_s*' .. 405 'var d = {dd: {}}\_s*' .. 406 '\d PUSHS "dd"\_s*' .. 407 '\d NEWDICT size 0\_s*' .. 408 '\d NEWDICT size 1\_s*' .. 409 '\d STORE $0\_s*' .. 410 'd.dd\[0\] = 0\_s*' .. 411 '\d PUSHNR 0\_s*' .. 412 '\d PUSHNR 0\_s*' .. 413 '\d LOAD $0\_s*' .. 414 '\d MEMBER dd\_s*' .. 415 '\d\+ USEDICT\_s*' .. 416 '\d\+ STOREINDEX any\_s*' .. 417 '\d\+ RETURN void', 418 res) 419enddef 420 421def s:ListAssign() 422 var x: string 423 var y: string 424 var l: list<any> 425 [x, y; l] = g:stringlist 426enddef 427 428def Test_disassemble_list_assign() 429 var res = execute('disass s:ListAssign') 430 assert_match('<SNR>\d*_ListAssign\_s*' .. 431 'var x: string\_s*' .. 432 '\d PUSHS "\[NULL\]"\_s*' .. 433 '\d STORE $0\_s*' .. 434 'var y: string\_s*' .. 435 '\d PUSHS "\[NULL\]"\_s*' .. 436 '\d STORE $1\_s*' .. 437 'var l: list<any>\_s*' .. 438 '\d NEWLIST size 0\_s*' .. 439 '\d SETTYPE list<any>\_s*' .. 440 '\d STORE $2\_s*' .. 441 '\[x, y; l\] = g:stringlist\_s*' .. 442 '\d LOADG g:stringlist\_s*' .. 443 '\d CHECKTYPE list<any> stack\[-1\]\_s*' .. 444 '\d CHECKLEN >= 2\_s*' .. 445 '\d\+ ITEM 0\_s*' .. 446 '\d\+ CHECKTYPE string stack\[-1\] arg 1\_s*' .. 447 '\d\+ STORE $0\_s*' .. 448 '\d\+ ITEM 1\_s*' .. 449 '\d\+ CHECKTYPE string stack\[-1\] arg 2\_s*' .. 450 '\d\+ STORE $1\_s*' .. 451 '\d\+ SLICE 2\_s*' .. 452 '\d\+ STORE $2\_s*' .. 453 '\d\+ RETURN void', 454 res) 455enddef 456 457def s:ListAssignWithOp() 458 var a = 2 459 var b = 3 460 [a, b] += [4, 5] 461enddef 462 463def Test_disassemble_list_assign_with_op() 464 var res = execute('disass s:ListAssignWithOp') 465 assert_match('<SNR>\d*_ListAssignWithOp\_s*' .. 466 'var a = 2\_s*' .. 467 '\d STORE 2 in $0\_s*' .. 468 'var b = 3\_s*' .. 469 '\d STORE 3 in $1\_s*' .. 470 '\[a, b\] += \[4, 5\]\_s*' .. 471 '\d\+ PUSHNR 4\_s*' .. 472 '\d\+ PUSHNR 5\_s*' .. 473 '\d\+ NEWLIST size 2\_s*' .. 474 '\d\+ CHECKLEN 2\_s*' .. 475 '\d\+ LOAD $0\_s*' .. 476 '\d\+ ITEM 0 with op\_s*' .. 477 '\d\+ OPNR +\_s*' .. 478 '\d\+ STORE $0\_s*' .. 479 '\d\+ LOAD $1\_s*' .. 480 '\d\+ ITEM 1 with op\_s*' .. 481 '\d\+ OPNR +\_s*' .. 482 '\d\+ STORE $1\_s*' .. 483 '\d\+ DROP\_s*' .. 484 '\d\+ RETURN void', 485 res) 486enddef 487 488def s:ListAdd() 489 var l: list<number> = [] 490 add(l, 123) 491 add(l, g:aNumber) 492enddef 493 494def Test_disassemble_list_add() 495 var res = execute('disass s:ListAdd') 496 assert_match('<SNR>\d*_ListAdd\_s*' .. 497 'var l: list<number> = []\_s*' .. 498 '\d NEWLIST size 0\_s*' .. 499 '\d SETTYPE list<number>\_s*' .. 500 '\d STORE $0\_s*' .. 501 'add(l, 123)\_s*' .. 502 '\d LOAD $0\_s*' .. 503 '\d PUSHNR 123\_s*' .. 504 '\d LISTAPPEND\_s*' .. 505 '\d DROP\_s*' .. 506 'add(l, g:aNumber)\_s*' .. 507 '\d LOAD $0\_s*' .. 508 '\d\+ LOADG g:aNumber\_s*' .. 509 '\d\+ CHECKTYPE number stack\[-1\]\_s*' .. 510 '\d\+ LISTAPPEND\_s*' .. 511 '\d\+ DROP\_s*' .. 512 '\d\+ RETURN void', 513 res) 514enddef 515 516def s:BlobAdd() 517 var b: blob = 0z 518 add(b, 123) 519 add(b, g:aNumber) 520enddef 521 522def Test_disassemble_blob_add() 523 var res = execute('disass s:BlobAdd') 524 assert_match('<SNR>\d*_BlobAdd\_s*' .. 525 'var b: blob = 0z\_s*' .. 526 '\d PUSHBLOB 0z\_s*' .. 527 '\d STORE $0\_s*' .. 528 'add(b, 123)\_s*' .. 529 '\d LOAD $0\_s*' .. 530 '\d PUSHNR 123\_s*' .. 531 '\d BLOBAPPEND\_s*' .. 532 '\d DROP\_s*' .. 533 'add(b, g:aNumber)\_s*' .. 534 '\d LOAD $0\_s*' .. 535 '\d\+ LOADG g:aNumber\_s*' .. 536 '\d\+ CHECKTYPE number stack\[-1\]\_s*' .. 537 '\d\+ BLOBAPPEND\_s*' .. 538 '\d\+ DROP\_s*' .. 539 '\d\+ RETURN void', 540 res) 541enddef 542 543def s:BlobIndexSlice() 544 var b: blob = 0z112233 545 echo b[1] 546 echo b[1 : 2] 547enddef 548 549def Test_disassemble_blob_index_slice() 550 var res = execute('disass s:BlobIndexSlice') 551 assert_match('<SNR>\d*_BlobIndexSlice\_s*' .. 552 'var b: blob = 0z112233\_s*' .. 553 '\d PUSHBLOB 0z112233\_s*' .. 554 '\d STORE $0\_s*' .. 555 'echo b\[1\]\_s*' .. 556 '\d LOAD $0\_s*' .. 557 '\d PUSHNR 1\_s*' .. 558 '\d BLOBINDEX\_s*' .. 559 '\d ECHO 1\_s*' .. 560 'echo b\[1 : 2\]\_s*' .. 561 '\d LOAD $0\_s*' .. 562 '\d PUSHNR 1\_s*' .. 563 '\d\+ PUSHNR 2\_s*' .. 564 '\d\+ BLOBSLICE\_s*' .. 565 '\d\+ ECHO 1\_s*' .. 566 '\d\+ RETURN void', 567 res) 568enddef 569 570def s:ScriptFuncUnlet() 571 g:somevar = "value" 572 unlet g:somevar 573 unlet! g:somevar 574 unlet $SOMEVAR 575enddef 576 577def Test_disassemble_unlet() 578 var res = execute('disass s:ScriptFuncUnlet') 579 assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' .. 580 'g:somevar = "value"\_s*' .. 581 '\d PUSHS "value"\_s*' .. 582 '\d STOREG g:somevar\_s*' .. 583 'unlet g:somevar\_s*' .. 584 '\d UNLET g:somevar\_s*' .. 585 'unlet! g:somevar\_s*' .. 586 '\d UNLET! g:somevar\_s*' .. 587 'unlet $SOMEVAR\_s*' .. 588 '\d UNLETENV $SOMEVAR\_s*', 589 res) 590enddef 591 592def s:LockLocal() 593 var d = {a: 1} 594 lockvar d.a 595enddef 596 597def Test_disassemble_locl_local() 598 var res = execute('disass s:LockLocal') 599 assert_match('<SNR>\d*_LockLocal\_s*' .. 600 'var d = {a: 1}\_s*' .. 601 '\d PUSHS "a"\_s*' .. 602 '\d PUSHNR 1\_s*' .. 603 '\d NEWDICT size 1\_s*' .. 604 '\d STORE $0\_s*' .. 605 'lockvar d.a\_s*' .. 606 '\d LOAD $0\_s*' .. 607 '\d LOCKUNLOCK lockvar d.a\_s*', 608 res) 609enddef 610 611def s:ScriptFuncTry() 612 try 613 echo "yes" 614 catch /fail/ 615 echo "no" 616 finally 617 throw "end" 618 endtry 619enddef 620 621def Test_disassemble_try() 622 var res = execute('disass s:ScriptFuncTry') 623 assert_match('<SNR>\d*_ScriptFuncTry\_s*' .. 624 'try\_s*' .. 625 '\d TRY catch -> \d\+, finally -> \d\+, endtry -> \d\+\_s*' .. 626 'echo "yes"\_s*' .. 627 '\d PUSHS "yes"\_s*' .. 628 '\d ECHO 1\_s*' .. 629 'catch /fail/\_s*' .. 630 '\d JUMP -> \d\+\_s*' .. 631 '\d PUSH v:exception\_s*' .. 632 '\d PUSHS "fail"\_s*' .. 633 '\d COMPARESTRING =\~\_s*' .. 634 '\d JUMP_IF_FALSE -> \d\+\_s*' .. 635 '\d CATCH\_s*' .. 636 'echo "no"\_s*' .. 637 '\d\+ PUSHS "no"\_s*' .. 638 '\d\+ ECHO 1\_s*' .. 639 'finally\_s*' .. 640 '\d\+ FINALLY\_s*' .. 641 'throw "end"\_s*' .. 642 '\d\+ PUSHS "end"\_s*' .. 643 '\d\+ THROW\_s*' .. 644 'endtry\_s*' .. 645 '\d\+ ENDTRY', 646 res) 647enddef 648 649def s:ScriptFuncNew() 650 var ll = [1, "two", 333] 651 var dd = {one: 1, two: "val"} 652enddef 653 654def Test_disassemble_new() 655 var res = execute('disass s:ScriptFuncNew') 656 assert_match('<SNR>\d*_ScriptFuncNew\_s*' .. 657 'var ll = \[1, "two", 333\]\_s*' .. 658 '\d PUSHNR 1\_s*' .. 659 '\d PUSHS "two"\_s*' .. 660 '\d PUSHNR 333\_s*' .. 661 '\d NEWLIST size 3\_s*' .. 662 '\d STORE $0\_s*' .. 663 'var dd = {one: 1, two: "val"}\_s*' .. 664 '\d PUSHS "one"\_s*' .. 665 '\d PUSHNR 1\_s*' .. 666 '\d PUSHS "two"\_s*' .. 667 '\d PUSHS "val"\_s*' .. 668 '\d NEWDICT size 2\_s*', 669 res) 670enddef 671 672def FuncWithArg(arg: any) 673 echo arg 674enddef 675 676func UserFunc() 677 echo 'nothing' 678endfunc 679 680func UserFuncWithArg(arg) 681 echo a:arg 682endfunc 683 684def s:ScriptFuncCall(): string 685 changenr() 686 char2nr("abc") 687 Test_disassemble_new() 688 FuncWithArg(343) 689 ScriptFuncNew() 690 s:ScriptFuncNew() 691 UserFunc() 692 UserFuncWithArg("foo") 693 var FuncRef = function("UserFunc") 694 FuncRef() 695 var FuncRefWithArg = function("UserFuncWithArg") 696 FuncRefWithArg("bar") 697 return "yes" 698enddef 699 700def Test_disassemble_call() 701 var res = execute('disass s:ScriptFuncCall') 702 assert_match('<SNR>\d\+_ScriptFuncCall\_s*' .. 703 'changenr()\_s*' .. 704 '\d BCALL changenr(argc 0)\_s*' .. 705 '\d DROP\_s*' .. 706 'char2nr("abc")\_s*' .. 707 '\d PUSHS "abc"\_s*' .. 708 '\d BCALL char2nr(argc 1)\_s*' .. 709 '\d DROP\_s*' .. 710 'Test_disassemble_new()\_s*' .. 711 '\d DCALL Test_disassemble_new(argc 0)\_s*' .. 712 '\d DROP\_s*' .. 713 'FuncWithArg(343)\_s*' .. 714 '\d\+ PUSHNR 343\_s*' .. 715 '\d\+ DCALL FuncWithArg(argc 1)\_s*' .. 716 '\d\+ DROP\_s*' .. 717 'ScriptFuncNew()\_s*' .. 718 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 719 '\d\+ DROP\_s*' .. 720 's:ScriptFuncNew()\_s*' .. 721 '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. 722 '\d\+ DROP\_s*' .. 723 'UserFunc()\_s*' .. 724 '\d\+ UCALL UserFunc(argc 0)\_s*' .. 725 '\d\+ DROP\_s*' .. 726 'UserFuncWithArg("foo")\_s*' .. 727 '\d\+ PUSHS "foo"\_s*' .. 728 '\d\+ UCALL UserFuncWithArg(argc 1)\_s*' .. 729 '\d\+ DROP\_s*' .. 730 'var FuncRef = function("UserFunc")\_s*' .. 731 '\d\+ PUSHS "UserFunc"\_s*' .. 732 '\d\+ BCALL function(argc 1)\_s*' .. 733 '\d\+ STORE $0\_s*' .. 734 'FuncRef()\_s*' .. 735 '\d\+ LOAD $\d\_s*' .. 736 '\d\+ PCALL (argc 0)\_s*' .. 737 '\d\+ DROP\_s*' .. 738 'var FuncRefWithArg = function("UserFuncWithArg")\_s*' .. 739 '\d\+ PUSHS "UserFuncWithArg"\_s*' .. 740 '\d\+ BCALL function(argc 1)\_s*' .. 741 '\d\+ STORE $1\_s*' .. 742 'FuncRefWithArg("bar")\_s*' .. 743 '\d\+ PUSHS "bar"\_s*' .. 744 '\d\+ LOAD $\d\_s*' .. 745 '\d\+ PCALL (argc 1)\_s*' .. 746 '\d\+ DROP\_s*' .. 747 'return "yes"\_s*' .. 748 '\d\+ PUSHS "yes"\_s*' .. 749 '\d\+ RETURN', 750 res) 751enddef 752 753 754def s:CreateRefs() 755 var local = 'a' 756 def Append(arg: string) 757 local ..= arg 758 enddef 759 g:Append = Append 760 def Get(): string 761 return local 762 enddef 763 g:Get = Get 764enddef 765 766def Test_disassemble_closure() 767 CreateRefs() 768 var res = execute('disass g:Append') 769 assert_match('<lambda>\d\_s*' .. 770 'local ..= arg\_s*' .. 771 '\d LOADOUTER level 1 $0\_s*' .. 772 '\d LOAD arg\[-1\]\_s*' .. 773 '\d CONCAT\_s*' .. 774 '\d STOREOUTER level 1 $0\_s*' .. 775 '\d RETURN void', 776 res) 777 778 res = execute('disass g:Get') 779 assert_match('<lambda>\d\_s*' .. 780 'return local\_s*' .. 781 '\d LOADOUTER level 1 $0\_s*' .. 782 '\d RETURN', 783 res) 784 785 unlet g:Append 786 unlet g:Get 787enddef 788 789 790def EchoArg(arg: string): string 791 return arg 792enddef 793def RefThis(): func 794 return function('EchoArg') 795enddef 796def s:ScriptPCall() 797 RefThis()("text") 798enddef 799 800def Test_disassemble_pcall() 801 var res = execute('disass s:ScriptPCall') 802 assert_match('<SNR>\d\+_ScriptPCall\_s*' .. 803 'RefThis()("text")\_s*' .. 804 '\d DCALL RefThis(argc 0)\_s*' .. 805 '\d PUSHS "text"\_s*' .. 806 '\d PCALL top (argc 1)\_s*' .. 807 '\d PCALL end\_s*' .. 808 '\d DROP\_s*' .. 809 '\d RETURN void', 810 res) 811enddef 812 813 814def s:FuncWithForwardCall(): string 815 return g:DefinedLater("yes") 816enddef 817 818def DefinedLater(arg: string): string 819 return arg 820enddef 821 822def Test_disassemble_update_instr() 823 var res = execute('disass s:FuncWithForwardCall') 824 assert_match('FuncWithForwardCall\_s*' .. 825 'return g:DefinedLater("yes")\_s*' .. 826 '\d PUSHS "yes"\_s*' .. 827 '\d DCALL DefinedLater(argc 1)\_s*' .. 828 '\d RETURN', 829 res) 830 831 # Calling the function will change UCALL into the faster DCALL 832 assert_equal('yes', FuncWithForwardCall()) 833 834 res = execute('disass s:FuncWithForwardCall') 835 assert_match('FuncWithForwardCall\_s*' .. 836 'return g:DefinedLater("yes")\_s*' .. 837 '\d PUSHS "yes"\_s*' .. 838 '\d DCALL DefinedLater(argc 1)\_s*' .. 839 '\d RETURN', 840 res) 841enddef 842 843 844def FuncWithDefault(l: number, arg: string = "default", nr = 77): string 845 return arg .. nr 846enddef 847 848def Test_disassemble_call_default() 849 var res = execute('disass FuncWithDefault') 850 assert_match('FuncWithDefault\_s*' .. 851 ' arg = "default"\_s*' .. 852 '\d JUMP_IF_ARG_SET arg\[-2\] -> 3\_s*' .. 853 '\d PUSHS "default"\_s*' .. 854 '\d STORE arg\[-2]\_s*' .. 855 ' nr = 77\_s*' .. 856 '3 JUMP_IF_ARG_SET arg\[-1\] -> 6\_s*' .. 857 '\d PUSHNR 77\_s*' .. 858 '\d STORE arg\[-1]\_s*' .. 859 ' return arg .. nr\_s*' .. 860 '6 LOAD arg\[-2]\_s*' .. 861 '\d LOAD arg\[-1]\_s*' .. 862 '\d 2STRING stack\[-1]\_s*' .. 863 '\d\+ CONCAT\_s*' .. 864 '\d\+ RETURN', 865 res) 866enddef 867 868 869def HasEval() 870 if has("eval") 871 echo "yes" 872 else 873 echo "no" 874 endif 875enddef 876 877def HasNothing() 878 if has("nothing") 879 echo "yes" 880 else 881 echo "no" 882 endif 883enddef 884 885def HasSomething() 886 if has("nothing") 887 echo "nothing" 888 elseif has("something") 889 echo "something" 890 elseif has("eval") 891 echo "eval" 892 elseif has("less") 893 echo "less" 894 endif 895enddef 896 897def HasGuiRunning() 898 if has("gui_running") 899 echo "yes" 900 else 901 echo "no" 902 endif 903enddef 904 905def Test_disassemble_const_expr() 906 assert_equal("\nyes", execute('HasEval()')) 907 var instr = execute('disassemble HasEval') 908 assert_match('HasEval\_s*' .. 909 'if has("eval")\_s*' .. 910 'echo "yes"\_s*' .. 911 '\d PUSHS "yes"\_s*' .. 912 '\d ECHO 1\_s*' .. 913 'else\_s*' .. 914 'echo "no"\_s*' .. 915 'endif\_s*', 916 instr) 917 assert_notmatch('JUMP', instr) 918 919 assert_equal("\nno", execute('HasNothing()')) 920 instr = execute('disassemble HasNothing') 921 assert_match('HasNothing\_s*' .. 922 'if has("nothing")\_s*' .. 923 'echo "yes"\_s*' .. 924 'else\_s*' .. 925 'echo "no"\_s*' .. 926 '\d PUSHS "no"\_s*' .. 927 '\d ECHO 1\_s*' .. 928 'endif', 929 instr) 930 assert_notmatch('PUSHS "yes"', instr) 931 assert_notmatch('JUMP', instr) 932 933 assert_equal("\neval", execute('HasSomething()')) 934 instr = execute('disassemble HasSomething') 935 assert_match('HasSomething.*' .. 936 'if has("nothing")\_s*' .. 937 'echo "nothing"\_s*' .. 938 'elseif has("something")\_s*' .. 939 'echo "something"\_s*' .. 940 'elseif has("eval")\_s*' .. 941 'echo "eval"\_s*' .. 942 '\d PUSHS "eval"\_s*' .. 943 '\d ECHO 1\_s*' .. 944 'elseif has("less").*' .. 945 'echo "less"\_s*' .. 946 'endif', 947 instr) 948 assert_notmatch('PUSHS "nothing"', instr) 949 assert_notmatch('PUSHS "something"', instr) 950 assert_notmatch('PUSHS "less"', instr) 951 assert_notmatch('JUMP', instr) 952 953 var result: string 954 var instr_expected: string 955 if has('gui') 956 if has('gui_running') 957 # GUI already running, always returns "yes" 958 result = "\nyes" 959 instr_expected = 'HasGuiRunning.*' .. 960 'if has("gui_running")\_s*' .. 961 ' echo "yes"\_s*' .. 962 '\d PUSHS "yes"\_s*' .. 963 '\d ECHO 1\_s*' .. 964 'else\_s*' .. 965 ' echo "no"\_s*' .. 966 'endif' 967 else 968 result = "\nno" 969 if has('unix') 970 # GUI not running but can start later, call has() 971 instr_expected = 'HasGuiRunning.*' .. 972 'if has("gui_running")\_s*' .. 973 '\d PUSHS "gui_running"\_s*' .. 974 '\d BCALL has(argc 1)\_s*' .. 975 '\d COND2BOOL\_s*' .. 976 '\d JUMP_IF_FALSE -> \d\_s*' .. 977 ' echo "yes"\_s*' .. 978 '\d PUSHS "yes"\_s*' .. 979 '\d ECHO 1\_s*' .. 980 'else\_s*' .. 981 '\d JUMP -> \d\_s*' .. 982 ' echo "no"\_s*' .. 983 '\d PUSHS "no"\_s*' .. 984 '\d ECHO 1\_s*' .. 985 'endif' 986 else 987 # GUI not running, always return "no" 988 instr_expected = 'HasGuiRunning.*' .. 989 'if has("gui_running")\_s*' .. 990 ' echo "yes"\_s*' .. 991 'else\_s*' .. 992 ' echo "no"\_s*' .. 993 '\d PUSHS "no"\_s*' .. 994 '\d ECHO 1\_s*' .. 995 'endif' 996 endif 997 endif 998 else 999 # GUI not supported, always return "no" 1000 result = "\nno" 1001 instr_expected = 'HasGuiRunning.*' .. 1002 'if has("gui_running")\_s*' .. 1003 ' echo "yes"\_s*' .. 1004 'else\_s*' .. 1005 ' echo "no"\_s*' .. 1006 '\d PUSHS "no"\_s*' .. 1007 '\d ECHO 1\_s*' .. 1008 'endif' 1009 endif 1010 1011 assert_equal(result, execute('HasGuiRunning()')) 1012 instr = execute('disassemble HasGuiRunning') 1013 assert_match(instr_expected, instr) 1014enddef 1015 1016def ReturnInIf(): string 1017 if 1 < 0 1018 return "maybe" 1019 endif 1020 if g:cond 1021 return "yes" 1022 else 1023 return "no" 1024 endif 1025enddef 1026 1027def Test_disassemble_return_in_if() 1028 var instr = execute('disassemble ReturnInIf') 1029 assert_match('ReturnInIf\_s*' .. 1030 'if 1 < 0\_s*' .. 1031 ' return "maybe"\_s*' .. 1032 'endif\_s*' .. 1033 'if g:cond\_s*' .. 1034 '0 LOADG g:cond\_s*' .. 1035 '1 COND2BOOL\_s*' .. 1036 '2 JUMP_IF_FALSE -> 5\_s*' .. 1037 'return "yes"\_s*' .. 1038 '3 PUSHS "yes"\_s*' .. 1039 '4 RETURN\_s*' .. 1040 'else\_s*' .. 1041 ' return "no"\_s*' .. 1042 '5 PUSHS "no"\_s*' .. 1043 '6 RETURN$', 1044 instr) 1045enddef 1046 1047def WithFunc() 1048 var Funky1: func 1049 var Funky2: func = function("len") 1050 var Party2: func = funcref("UserFunc") 1051enddef 1052 1053def Test_disassemble_function() 1054 var instr = execute('disassemble WithFunc') 1055 assert_match('WithFunc\_s*' .. 1056 'var Funky1: func\_s*' .. 1057 '0 PUSHFUNC "\[none]"\_s*' .. 1058 '1 STORE $0\_s*' .. 1059 'var Funky2: func = function("len")\_s*' .. 1060 '2 PUSHS "len"\_s*' .. 1061 '3 BCALL function(argc 1)\_s*' .. 1062 '4 STORE $1\_s*' .. 1063 'var Party2: func = funcref("UserFunc")\_s*' .. 1064 '\d PUSHS "UserFunc"\_s*' .. 1065 '\d BCALL funcref(argc 1)\_s*' .. 1066 '\d STORE $2\_s*' .. 1067 '\d RETURN void', 1068 instr) 1069enddef 1070 1071if has('channel') 1072 def WithChannel() 1073 var job1: job 1074 var job2: job = job_start("donothing") 1075 var chan1: channel 1076 enddef 1077endif 1078 1079def Test_disassemble_channel() 1080 CheckFeature channel 1081 1082 var instr = execute('disassemble WithChannel') 1083 assert_match('WithChannel\_s*' .. 1084 'var job1: job\_s*' .. 1085 '\d PUSHJOB "no process"\_s*' .. 1086 '\d STORE $0\_s*' .. 1087 'var job2: job = job_start("donothing")\_s*' .. 1088 '\d PUSHS "donothing"\_s*' .. 1089 '\d BCALL job_start(argc 1)\_s*' .. 1090 '\d STORE $1\_s*' .. 1091 'var chan1: channel\_s*' .. 1092 '\d PUSHCHANNEL 0\_s*' .. 1093 '\d STORE $2\_s*' .. 1094 '\d RETURN void', 1095 instr) 1096enddef 1097 1098def WithLambda(): string 1099 var F = (a) => "X" .. a .. "X" 1100 return F("x") 1101enddef 1102 1103def Test_disassemble_lambda() 1104 assert_equal("XxX", WithLambda()) 1105 var instr = execute('disassemble WithLambda') 1106 assert_match('WithLambda\_s*' .. 1107 'var F = (a) => "X" .. a .. "X"\_s*' .. 1108 '\d FUNCREF <lambda>\d\+\_s*' .. 1109 '\d STORE $0\_s*' .. 1110 'return F("x")\_s*' .. 1111 '\d PUSHS "x"\_s*' .. 1112 '\d LOAD $0\_s*' .. 1113 '\d PCALL (argc 1)\_s*' .. 1114 '\d RETURN', 1115 instr) 1116 1117 var name = substitute(instr, '.*\(<lambda>\d\+\).*', '\1', '') 1118 instr = execute('disassemble ' .. name) 1119 assert_match('<lambda>\d\+\_s*' .. 1120 'return "X" .. a .. "X"\_s*' .. 1121 '\d PUSHS "X"\_s*' .. 1122 '\d LOAD arg\[-1\]\_s*' .. 1123 '\d 2STRING_ANY stack\[-1\]\_s*' .. 1124 '\d CONCAT\_s*' .. 1125 '\d PUSHS "X"\_s*' .. 1126 '\d CONCAT\_s*' .. 1127 '\d RETURN', 1128 instr) 1129enddef 1130 1131def LambdaWithType(): number 1132 var Ref = (a: number) => a + 10 1133 return Ref(g:value) 1134enddef 1135 1136def Test_disassemble_lambda_with_type() 1137 g:value = 5 1138 assert_equal(15, LambdaWithType()) 1139 var instr = execute('disassemble LambdaWithType') 1140 assert_match('LambdaWithType\_s*' .. 1141 'var Ref = (a: number) => a + 10\_s*' .. 1142 '\d FUNCREF <lambda>\d\+\_s*' .. 1143 '\d STORE $0\_s*' .. 1144 'return Ref(g:value)\_s*' .. 1145 '\d LOADG g:value\_s*' .. 1146 '\d LOAD $0\_s*' .. 1147 '\d CHECKTYPE number stack\[-2\] arg 1\_s*' .. 1148 '\d PCALL (argc 1)\_s*' .. 1149 '\d RETURN', 1150 instr) 1151enddef 1152 1153def NestedOuter() 1154 def g:Inner() 1155 echomsg "inner" 1156 enddef 1157enddef 1158 1159def Test_disassemble_nested_func() 1160 var instr = execute('disassemble NestedOuter') 1161 assert_match('NestedOuter\_s*' .. 1162 'def g:Inner()\_s*' .. 1163 'echomsg "inner"\_s*' .. 1164 'enddef\_s*' .. 1165 '\d NEWFUNC <lambda>\d\+ Inner\_s*' .. 1166 '\d RETURN void', 1167 instr) 1168enddef 1169 1170def NestedDefList() 1171 def 1172 def Info 1173 def /Info 1174 def /Info/ 1175enddef 1176 1177def Test_disassemble_nested_def_list() 1178 var instr = execute('disassemble NestedDefList') 1179 assert_match('NestedDefList\_s*' .. 1180 'def\_s*' .. 1181 '\d DEF \_s*' .. 1182 'def Info\_s*' .. 1183 '\d DEF Info\_s*' .. 1184 'def /Info\_s*' .. 1185 '\d DEF /Info\_s*' .. 1186 'def /Info/\_s*' .. 1187 '\d DEF /Info/\_s*' .. 1188 '\d RETURN void', 1189 instr) 1190enddef 1191 1192def AndOr(arg: any): string 1193 if arg == 1 && arg != 2 || arg == 4 1194 return 'yes' 1195 endif 1196 return 'no' 1197enddef 1198 1199def Test_disassemble_and_or() 1200 assert_equal("yes", AndOr(1)) 1201 assert_equal("no", AndOr(2)) 1202 assert_equal("yes", AndOr(4)) 1203 var instr = execute('disassemble AndOr') 1204 assert_match('AndOr\_s*' .. 1205 'if arg == 1 && arg != 2 || arg == 4\_s*' .. 1206 '\d LOAD arg\[-1]\_s*' .. 1207 '\d PUSHNR 1\_s*' .. 1208 '\d COMPAREANY ==\_s*' .. 1209 '\d JUMP_IF_COND_FALSE -> \d\+\_s*' .. 1210 '\d LOAD arg\[-1]\_s*' .. 1211 '\d PUSHNR 2\_s*' .. 1212 '\d COMPAREANY !=\_s*' .. 1213 '\d JUMP_IF_COND_TRUE -> \d\+\_s*' .. 1214 '\d LOAD arg\[-1]\_s*' .. 1215 '\d\+ PUSHNR 4\_s*' .. 1216 '\d\+ COMPAREANY ==\_s*' .. 1217 '\d\+ JUMP_IF_FALSE -> \d\+', 1218 instr) 1219enddef 1220 1221def AndConstant(arg: any): string 1222 if true && arg 1223 return "yes" 1224 endif 1225 if false && arg 1226 return "never" 1227 endif 1228 return "no" 1229enddef 1230 1231def Test_disassemble_and_constant() 1232 assert_equal("yes", AndConstant(1)) 1233 assert_equal("no", AndConstant(false)) 1234 var instr = execute('disassemble AndConstant') 1235 assert_match('AndConstant\_s*' .. 1236 'if true && arg\_s*' .. 1237 '0 LOAD arg\[-1\]\_s*' .. 1238 '1 COND2BOOL\_s*' .. 1239 '2 JUMP_IF_FALSE -> 5\_s*' .. 1240 'return "yes"\_s*' .. 1241 '3 PUSHS "yes"\_s*' .. 1242 '4 RETURN\_s*' .. 1243 'endif\_s*' .. 1244 'if false && arg\_s*' .. 1245 'return "never"\_s*' .. 1246 'endif\_s*' .. 1247 'return "no"\_s*' .. 1248 '5 PUSHS "no"\_s*' .. 1249 '6 RETURN', 1250 instr) 1251enddef 1252 1253def ForLoop(): list<number> 1254 var res: list<number> 1255 for i in range(3) 1256 res->add(i) 1257 endfor 1258 return res 1259enddef 1260 1261def Test_disassemble_for_loop() 1262 assert_equal([0, 1, 2], ForLoop()) 1263 var instr = execute('disassemble ForLoop') 1264 assert_match('ForLoop\_s*' .. 1265 'var res: list<number>\_s*' .. 1266 '\d NEWLIST size 0\_s*' .. 1267 '\d SETTYPE list<number>\_s*' .. 1268 '\d STORE $0\_s*' .. 1269 'for i in range(3)\_s*' .. 1270 '\d STORE -1 in $1\_s*' .. 1271 '\d PUSHNR 3\_s*' .. 1272 '\d BCALL range(argc 1)\_s*' .. 1273 '\d FOR $1 -> \d\+\_s*' .. 1274 '\d STORE $2\_s*' .. 1275 'res->add(i)\_s*' .. 1276 '\d LOAD $0\_s*' .. 1277 '\d LOAD $2\_s*' .. 1278 '\d\+ LISTAPPEND\_s*' .. 1279 '\d\+ DROP\_s*' .. 1280 'endfor\_s*' .. 1281 '\d\+ JUMP -> \d\+\_s*' .. 1282 '\d\+ DROP', 1283 instr) 1284enddef 1285 1286def ForLoopEval(): string 1287 var res = "" 1288 for str in eval('["one", "two"]') 1289 res ..= str 1290 endfor 1291 return res 1292enddef 1293 1294def Test_disassemble_for_loop_eval() 1295 assert_equal('onetwo', ForLoopEval()) 1296 var instr = execute('disassemble ForLoopEval') 1297 assert_match('ForLoopEval\_s*' .. 1298 'var res = ""\_s*' .. 1299 '\d PUSHS ""\_s*' .. 1300 '\d STORE $0\_s*' .. 1301 'for str in eval(''\["one", "two"\]'')\_s*' .. 1302 '\d STORE -1 in $1\_s*' .. 1303 '\d PUSHS "\["one", "two"\]"\_s*' .. 1304 '\d BCALL eval(argc 1)\_s*' .. 1305 '\d FOR $1 -> \d\+\_s*' .. 1306 '\d STORE $2\_s*' .. 1307 'res ..= str\_s*' .. 1308 '\d\+ LOAD $0\_s*' .. 1309 '\d\+ LOAD $2\_s*' .. 1310 '\d 2STRING_ANY stack\[-1\]\_s*' .. 1311 '\d\+ CONCAT\_s*' .. 1312 '\d\+ STORE $0\_s*' .. 1313 'endfor\_s*' .. 1314 '\d\+ JUMP -> 5\_s*' .. 1315 '\d\+ DROP\_s*' .. 1316 'return res\_s*' .. 1317 '\d\+ LOAD $0\_s*' .. 1318 '\d\+ RETURN', 1319 instr) 1320enddef 1321 1322def ForLoopUnpack() 1323 for [x1, x2] in [[1, 2], [3, 4]] 1324 echo x1 x2 1325 endfor 1326enddef 1327 1328def Test_disassemble_for_loop_unpack() 1329 var instr = execute('disassemble ForLoopUnpack') 1330 assert_match('ForLoopUnpack\_s*' .. 1331 'for \[x1, x2\] in \[\[1, 2\], \[3, 4\]\]\_s*' .. 1332 '\d\+ STORE -1 in $0\_s*' .. 1333 '\d\+ PUSHNR 1\_s*' .. 1334 '\d\+ PUSHNR 2\_s*' .. 1335 '\d\+ NEWLIST size 2\_s*' .. 1336 '\d\+ PUSHNR 3\_s*' .. 1337 '\d\+ PUSHNR 4\_s*' .. 1338 '\d\+ NEWLIST size 2\_s*' .. 1339 '\d\+ NEWLIST size 2\_s*' .. 1340 '\d\+ FOR $0 -> 16\_s*' .. 1341 '\d\+ UNPACK 2\_s*' .. 1342 '\d\+ STORE $1\_s*' .. 1343 '\d\+ STORE $2\_s*' .. 1344 'echo x1 x2\_s*' .. 1345 '\d\+ LOAD $1\_s*' .. 1346 '\d\+ LOAD $2\_s*' .. 1347 '\d\+ ECHO 2\_s*' .. 1348 'endfor\_s*' .. 1349 '\d\+ JUMP -> 8\_s*' .. 1350 '\d\+ DROP\_s*' .. 1351 '\d\+ RETURN void', 1352 instr) 1353enddef 1354 1355def ForLoopContinue() 1356 for nr in [1, 2] 1357 try 1358 echo "ok" 1359 try 1360 echo "deeper" 1361 catch 1362 continue 1363 endtry 1364 catch 1365 echo "not ok" 1366 endtry 1367 endfor 1368enddef 1369 1370def Test_disassemble_for_loop_continue() 1371 var instr = execute('disassemble ForLoopContinue') 1372 assert_match('ForLoopContinue\_s*' .. 1373 'for nr in \[1, 2]\_s*' .. 1374 '0 STORE -1 in $0\_s*' .. 1375 '1 PUSHNR 1\_s*' .. 1376 '2 PUSHNR 2\_s*' .. 1377 '3 NEWLIST size 2\_s*' .. 1378 '4 FOR $0 -> 22\_s*' .. 1379 '5 STORE $1\_s*' .. 1380 'try\_s*' .. 1381 '6 TRY catch -> 17, endtry -> 20\_s*' .. 1382 'echo "ok"\_s*' .. 1383 '7 PUSHS "ok"\_s*' .. 1384 '8 ECHO 1\_s*' .. 1385 'try\_s*' .. 1386 '9 TRY catch -> 13, endtry -> 15\_s*' .. 1387 'echo "deeper"\_s*' .. 1388 '10 PUSHS "deeper"\_s*' .. 1389 '11 ECHO 1\_s*' .. 1390 'catch\_s*' .. 1391 '12 JUMP -> 15\_s*' .. 1392 '13 CATCH\_s*' .. 1393 'continue\_s*' .. 1394 '14 TRY-CONTINUE 2 levels -> 4\_s*' .. 1395 'endtry\_s*' .. 1396 '15 ENDTRY\_s*' .. 1397 'catch\_s*' .. 1398 '16 JUMP -> 20\_s*' .. 1399 '17 CATCH\_s*' .. 1400 'echo "not ok"\_s*' .. 1401 '18 PUSHS "not ok"\_s*' .. 1402 '19 ECHO 1\_s*' .. 1403 'endtry\_s*' .. 1404 '20 ENDTRY\_s*' .. 1405 'endfor\_s*' .. 1406 '21 JUMP -> 4\_s*' .. 1407 '\d\+ DROP\_s*' .. 1408 '\d\+ RETURN void', 1409 instr) 1410enddef 1411 1412let g:number = 42 1413 1414def TypeCast() 1415 var l: list<number> = [23, <number>g:number] 1416enddef 1417 1418def Test_disassemble_typecast() 1419 var instr = execute('disassemble TypeCast') 1420 assert_match('TypeCast.*' .. 1421 'var l: list<number> = \[23, <number>g:number\].*' .. 1422 '\d PUSHNR 23\_s*' .. 1423 '\d LOADG g:number\_s*' .. 1424 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1425 '\d NEWLIST size 2\_s*' .. 1426 '\d SETTYPE list<number>\_s*' .. 1427 '\d STORE $0\_s*' .. 1428 '\d RETURN void\_s*', 1429 instr) 1430enddef 1431 1432def Computing() 1433 var nr = 3 1434 var nrres = nr + 7 1435 nrres = nr - 7 1436 nrres = nr * 7 1437 nrres = nr / 7 1438 nrres = nr % 7 1439 1440 var anyres = g:number + 7 1441 anyres = g:number - 7 1442 anyres = g:number * 7 1443 anyres = g:number / 7 1444 anyres = g:number % 7 1445 1446 if has('float') 1447 var fl = 3.0 1448 var flres = fl + 7.0 1449 flres = fl - 7.0 1450 flres = fl * 7.0 1451 flres = fl / 7.0 1452 endif 1453enddef 1454 1455def Test_disassemble_computing() 1456 var instr = execute('disassemble Computing') 1457 assert_match('Computing.*' .. 1458 'var nr = 3.*' .. 1459 '\d STORE 3 in $0.*' .. 1460 'var nrres = nr + 7.*' .. 1461 '\d LOAD $0.*' .. 1462 '\d PUSHNR 7.*' .. 1463 '\d OPNR +.*' .. 1464 '\d STORE $1.*' .. 1465 'nrres = nr - 7.*' .. 1466 '\d OPNR -.*' .. 1467 'nrres = nr \* 7.*' .. 1468 '\d OPNR \*.*' .. 1469 'nrres = nr / 7.*' .. 1470 '\d OPNR /.*' .. 1471 'nrres = nr % 7.*' .. 1472 '\d OPNR %.*' .. 1473 'var anyres = g:number + 7.*' .. 1474 '\d LOADG g:number.*' .. 1475 '\d PUSHNR 7.*' .. 1476 '\d OPANY +.*' .. 1477 '\d STORE $2.*' .. 1478 'anyres = g:number - 7.*' .. 1479 '\d OPANY -.*' .. 1480 'anyres = g:number \* 7.*' .. 1481 '\d OPANY \*.*' .. 1482 'anyres = g:number / 7.*' .. 1483 '\d OPANY /.*' .. 1484 'anyres = g:number % 7.*' .. 1485 '\d OPANY %.*', 1486 instr) 1487 if has('float') 1488 assert_match('Computing.*' .. 1489 'var fl = 3.0.*' .. 1490 '\d PUSHF 3.0.*' .. 1491 '\d STORE $3.*' .. 1492 'var flres = fl + 7.0.*' .. 1493 '\d LOAD $3.*' .. 1494 '\d PUSHF 7.0.*' .. 1495 '\d OPFLOAT +.*' .. 1496 '\d STORE $4.*' .. 1497 'flres = fl - 7.0.*' .. 1498 '\d OPFLOAT -.*' .. 1499 'flres = fl \* 7.0.*' .. 1500 '\d OPFLOAT \*.*' .. 1501 'flres = fl / 7.0.*' .. 1502 '\d OPFLOAT /.*', 1503 instr) 1504 endif 1505enddef 1506 1507def AddListBlob() 1508 var reslist = [1, 2] + [3, 4] 1509 var resblob = 0z1122 + 0z3344 1510enddef 1511 1512def Test_disassemble_add_list_blob() 1513 var instr = execute('disassemble AddListBlob') 1514 assert_match('AddListBlob.*' .. 1515 'var reslist = \[1, 2] + \[3, 4].*' .. 1516 '\d PUSHNR 1.*' .. 1517 '\d PUSHNR 2.*' .. 1518 '\d NEWLIST size 2.*' .. 1519 '\d PUSHNR 3.*' .. 1520 '\d PUSHNR 4.*' .. 1521 '\d NEWLIST size 2.*' .. 1522 '\d ADDLIST.*' .. 1523 '\d STORE $.*.*' .. 1524 'var resblob = 0z1122 + 0z3344.*' .. 1525 '\d PUSHBLOB 0z1122.*' .. 1526 '\d PUSHBLOB 0z3344.*' .. 1527 '\d ADDBLOB.*' .. 1528 '\d STORE $.*', 1529 instr) 1530enddef 1531 1532let g:aa = 'aa' 1533def ConcatString(): string 1534 var res = g:aa .. "bb" 1535 return res 1536enddef 1537 1538def Test_disassemble_concat() 1539 var instr = execute('disassemble ConcatString') 1540 assert_match('ConcatString.*' .. 1541 'var res = g:aa .. "bb".*' .. 1542 '\d LOADG g:aa.*' .. 1543 '\d PUSHS "bb".*' .. 1544 '\d 2STRING_ANY stack\[-2].*' .. 1545 '\d CONCAT.*' .. 1546 '\d STORE $.*', 1547 instr) 1548 assert_equal('aabb', ConcatString()) 1549enddef 1550 1551def StringIndex(): string 1552 var s = "abcd" 1553 var res = s[1] 1554 return res 1555enddef 1556 1557def Test_disassemble_string_index() 1558 var instr = execute('disassemble StringIndex') 1559 assert_match('StringIndex\_s*' .. 1560 'var s = "abcd"\_s*' .. 1561 '\d PUSHS "abcd"\_s*' .. 1562 '\d STORE $0\_s*' .. 1563 'var res = s\[1]\_s*' .. 1564 '\d LOAD $0\_s*' .. 1565 '\d PUSHNR 1\_s*' .. 1566 '\d STRINDEX\_s*' .. 1567 '\d STORE $1\_s*', 1568 instr) 1569 assert_equal('b', StringIndex()) 1570enddef 1571 1572def StringSlice(): string 1573 var s = "abcd" 1574 var res = s[1 : 8] 1575 return res 1576enddef 1577 1578def Test_disassemble_string_slice() 1579 var instr = execute('disassemble StringSlice') 1580 assert_match('StringSlice\_s*' .. 1581 'var s = "abcd"\_s*' .. 1582 '\d PUSHS "abcd"\_s*' .. 1583 '\d STORE $0\_s*' .. 1584 'var res = s\[1 : 8]\_s*' .. 1585 '\d LOAD $0\_s*' .. 1586 '\d PUSHNR 1\_s*' .. 1587 '\d PUSHNR 8\_s*' .. 1588 '\d STRSLICE\_s*' .. 1589 '\d STORE $1\_s*', 1590 instr) 1591 assert_equal('bcd', StringSlice()) 1592enddef 1593 1594def ListIndex(): number 1595 var l = [1, 2, 3] 1596 var res = l[1] 1597 return res 1598enddef 1599 1600def Test_disassemble_list_index() 1601 var instr = execute('disassemble ListIndex') 1602 assert_match('ListIndex\_s*' .. 1603 'var l = \[1, 2, 3]\_s*' .. 1604 '\d PUSHNR 1\_s*' .. 1605 '\d PUSHNR 2\_s*' .. 1606 '\d PUSHNR 3\_s*' .. 1607 '\d NEWLIST size 3\_s*' .. 1608 '\d STORE $0\_s*' .. 1609 'var res = l\[1]\_s*' .. 1610 '\d LOAD $0\_s*' .. 1611 '\d PUSHNR 1\_s*' .. 1612 '\d LISTINDEX\_s*' .. 1613 '\d STORE $1\_s*', 1614 instr) 1615 assert_equal(2, ListIndex()) 1616enddef 1617 1618def ListSlice(): list<number> 1619 var l = [1, 2, 3] 1620 var res = l[1 : 8] 1621 return res 1622enddef 1623 1624def Test_disassemble_list_slice() 1625 var instr = execute('disassemble ListSlice') 1626 assert_match('ListSlice\_s*' .. 1627 'var l = \[1, 2, 3]\_s*' .. 1628 '\d PUSHNR 1\_s*' .. 1629 '\d PUSHNR 2\_s*' .. 1630 '\d PUSHNR 3\_s*' .. 1631 '\d NEWLIST size 3\_s*' .. 1632 '\d STORE $0\_s*' .. 1633 'var res = l\[1 : 8]\_s*' .. 1634 '\d LOAD $0\_s*' .. 1635 '\d PUSHNR 1\_s*' .. 1636 '\d PUSHNR 8\_s*' .. 1637 '\d LISTSLICE\_s*' .. 1638 '\d STORE $1\_s*', 1639 instr) 1640 assert_equal([2, 3], ListSlice()) 1641enddef 1642 1643def DictMember(): number 1644 var d = {item: 1} 1645 var res = d.item 1646 res = d["item"] 1647 return res 1648enddef 1649 1650def Test_disassemble_dict_member() 1651 var instr = execute('disassemble DictMember') 1652 assert_match('DictMember\_s*' .. 1653 'var d = {item: 1}\_s*' .. 1654 '\d PUSHS "item"\_s*' .. 1655 '\d PUSHNR 1\_s*' .. 1656 '\d NEWDICT size 1\_s*' .. 1657 '\d STORE $0\_s*' .. 1658 'var res = d.item\_s*' .. 1659 '\d\+ LOAD $0\_s*' .. 1660 '\d\+ MEMBER item\_s*' .. 1661 '\d\+ USEDICT\_s*' .. 1662 '\d\+ STORE $1\_s*' .. 1663 'res = d\["item"\]\_s*' .. 1664 '\d\+ LOAD $0\_s*' .. 1665 '\d\+ PUSHS "item"\_s*' .. 1666 '\d\+ MEMBER\_s*' .. 1667 '\d\+ USEDICT\_s*' .. 1668 '\d\+ STORE $1\_s*', 1669 instr) 1670 assert_equal(1, DictMember()) 1671enddef 1672 1673let somelist = [1, 2, 3, 4, 5] 1674def AnyIndex(): number 1675 var res = g:somelist[2] 1676 return res 1677enddef 1678 1679def Test_disassemble_any_index() 1680 var instr = execute('disassemble AnyIndex') 1681 assert_match('AnyIndex\_s*' .. 1682 'var res = g:somelist\[2\]\_s*' .. 1683 '\d LOADG g:somelist\_s*' .. 1684 '\d PUSHNR 2\_s*' .. 1685 '\d ANYINDEX\_s*' .. 1686 '\d STORE $0\_s*' .. 1687 'return res\_s*' .. 1688 '\d LOAD $0\_s*' .. 1689 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1690 '\d RETURN', 1691 instr) 1692 assert_equal(3, AnyIndex()) 1693enddef 1694 1695def AnySlice(): list<number> 1696 var res = g:somelist[1 : 3] 1697 return res 1698enddef 1699 1700def Test_disassemble_any_slice() 1701 var instr = execute('disassemble AnySlice') 1702 assert_match('AnySlice\_s*' .. 1703 'var res = g:somelist\[1 : 3\]\_s*' .. 1704 '\d LOADG g:somelist\_s*' .. 1705 '\d PUSHNR 1\_s*' .. 1706 '\d PUSHNR 3\_s*' .. 1707 '\d ANYSLICE\_s*' .. 1708 '\d STORE $0\_s*' .. 1709 'return res\_s*' .. 1710 '\d LOAD $0\_s*' .. 1711 '\d CHECKTYPE list<number> stack\[-1\]\_s*' .. 1712 '\d RETURN', 1713 instr) 1714 assert_equal([2, 3, 4], AnySlice()) 1715enddef 1716 1717def NegateNumber(): number 1718 g:nr = 9 1719 var plus = +g:nr 1720 var minus = -g:nr 1721 return minus 1722enddef 1723 1724def Test_disassemble_negate_number() 1725 var instr = execute('disassemble NegateNumber') 1726 assert_match('NegateNumber\_s*' .. 1727 'g:nr = 9\_s*' .. 1728 '\d PUSHNR 9\_s*' .. 1729 '\d STOREG g:nr\_s*' .. 1730 'var plus = +g:nr\_s*' .. 1731 '\d LOADG g:nr\_s*' .. 1732 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1733 '\d STORE $0\_s*' .. 1734 'var minus = -g:nr\_s*' .. 1735 '\d LOADG g:nr\_s*' .. 1736 '\d CHECKTYPE number stack\[-1\]\_s*' .. 1737 '\d NEGATENR\_s*' .. 1738 '\d STORE $1\_s*', 1739 instr) 1740 assert_equal(-9, NegateNumber()) 1741enddef 1742 1743def InvertBool(): bool 1744 var flag = true 1745 var invert = !flag 1746 var res = !!flag 1747 return res 1748enddef 1749 1750def Test_disassemble_invert_bool() 1751 var instr = execute('disassemble InvertBool') 1752 assert_match('InvertBool\_s*' .. 1753 'var flag = true\_s*' .. 1754 '\d PUSH true\_s*' .. 1755 '\d STORE $0\_s*' .. 1756 'var invert = !flag\_s*' .. 1757 '\d LOAD $0\_s*' .. 1758 '\d INVERT -1 (!val)\_s*' .. 1759 '\d STORE $1\_s*' .. 1760 'var res = !!flag\_s*' .. 1761 '\d LOAD $0\_s*' .. 1762 '\d 2BOOL -1 (!!val)\_s*' .. 1763 '\d STORE $2\_s*', 1764 instr) 1765 assert_equal(true, InvertBool()) 1766enddef 1767 1768def ReturnBool(): bool 1769 var one = 1 1770 var zero = 0 1771 var name: bool = one && zero || one 1772 return name 1773enddef 1774 1775def Test_disassemble_return_bool() 1776 var instr = execute('disassemble ReturnBool') 1777 assert_match('ReturnBool\_s*' .. 1778 'var one = 1\_s*' .. 1779 '0 STORE 1 in $0\_s*' .. 1780 'var zero = 0\_s*' .. 1781 '1 STORE 0 in $1\_s*' .. 1782 'var name: bool = one && zero || one\_s*' .. 1783 '2 LOAD $0\_s*' .. 1784 '3 COND2BOOL\_s*' .. 1785 '4 JUMP_IF_COND_FALSE -> 7\_s*' .. 1786 '5 LOAD $1\_s*' .. 1787 '6 COND2BOOL\_s*' .. 1788 '7 JUMP_IF_COND_TRUE -> 10\_s*' .. 1789 '8 LOAD $0\_s*' .. 1790 '9 COND2BOOL\_s*' .. 1791 '10 STORE $2\_s*' .. 1792 'return name\_s*' .. 1793 '\d\+ LOAD $2\_s*' .. 1794 '\d\+ RETURN', 1795 instr) 1796 assert_equal(true, InvertBool()) 1797enddef 1798 1799def Test_disassemble_compare() 1800 var cases = [ 1801 ['true == isFalse', 'COMPAREBOOL =='], 1802 ['true != isFalse', 'COMPAREBOOL !='], 1803 ['v:none == isNull', 'COMPARESPECIAL =='], 1804 ['v:none != isNull', 'COMPARESPECIAL !='], 1805 1806 ['111 == aNumber', 'COMPARENR =='], 1807 ['111 != aNumber', 'COMPARENR !='], 1808 ['111 > aNumber', 'COMPARENR >'], 1809 ['111 < aNumber', 'COMPARENR <'], 1810 ['111 >= aNumber', 'COMPARENR >='], 1811 ['111 <= aNumber', 'COMPARENR <='], 1812 ['111 =~ aNumber', 'COMPARENR =\~'], 1813 ['111 !~ aNumber', 'COMPARENR !\~'], 1814 1815 ['"xx" != aString', 'COMPARESTRING !='], 1816 ['"xx" > aString', 'COMPARESTRING >'], 1817 ['"xx" < aString', 'COMPARESTRING <'], 1818 ['"xx" >= aString', 'COMPARESTRING >='], 1819 ['"xx" <= aString', 'COMPARESTRING <='], 1820 ['"xx" =~ aString', 'COMPARESTRING =\~'], 1821 ['"xx" !~ aString', 'COMPARESTRING !\~'], 1822 ['"xx" is aString', 'COMPARESTRING is'], 1823 ['"xx" isnot aString', 'COMPARESTRING isnot'], 1824 1825 ['0z11 == aBlob', 'COMPAREBLOB =='], 1826 ['0z11 != aBlob', 'COMPAREBLOB !='], 1827 ['0z11 is aBlob', 'COMPAREBLOB is'], 1828 ['0z11 isnot aBlob', 'COMPAREBLOB isnot'], 1829 1830 ['[1, 2] == aList', 'COMPARELIST =='], 1831 ['[1, 2] != aList', 'COMPARELIST !='], 1832 ['[1, 2] is aList', 'COMPARELIST is'], 1833 ['[1, 2] isnot aList', 'COMPARELIST isnot'], 1834 1835 ['{a: 1} == aDict', 'COMPAREDICT =='], 1836 ['{a: 1} != aDict', 'COMPAREDICT !='], 1837 ['{a: 1} is aDict', 'COMPAREDICT is'], 1838 ['{a: 1} isnot aDict', 'COMPAREDICT isnot'], 1839 1840 ['(() => 33) == (() => 44)', 'COMPAREFUNC =='], 1841 ['(() => 33) != (() => 44)', 'COMPAREFUNC !='], 1842 ['(() => 33) is (() => 44)', 'COMPAREFUNC is'], 1843 ['(() => 33) isnot (() => 44)', 'COMPAREFUNC isnot'], 1844 1845 ['77 == g:xx', 'COMPAREANY =='], 1846 ['77 != g:xx', 'COMPAREANY !='], 1847 ['77 > g:xx', 'COMPAREANY >'], 1848 ['77 < g:xx', 'COMPAREANY <'], 1849 ['77 >= g:xx', 'COMPAREANY >='], 1850 ['77 <= g:xx', 'COMPAREANY <='], 1851 ['77 =~ g:xx', 'COMPAREANY =\~'], 1852 ['77 !~ g:xx', 'COMPAREANY !\~'], 1853 ['77 is g:xx', 'COMPAREANY is'], 1854 ['77 isnot g:xx', 'COMPAREANY isnot'], 1855 ] 1856 var floatDecl = '' 1857 if has('float') 1858 cases->extend([ 1859 ['1.1 == aFloat', 'COMPAREFLOAT =='], 1860 ['1.1 != aFloat', 'COMPAREFLOAT !='], 1861 ['1.1 > aFloat', 'COMPAREFLOAT >'], 1862 ['1.1 < aFloat', 'COMPAREFLOAT <'], 1863 ['1.1 >= aFloat', 'COMPAREFLOAT >='], 1864 ['1.1 <= aFloat', 'COMPAREFLOAT <='], 1865 ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'], 1866 ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'], 1867 ]) 1868 floatDecl = 'var aFloat = 2.2' 1869 endif 1870 1871 var nr = 1 1872 for case in cases 1873 # declare local variables to get a non-constant with the right type 1874 writefile(['def TestCase' .. nr .. '()', 1875 ' var isFalse = false', 1876 ' var isNull = v:null', 1877 ' var aNumber = 222', 1878 ' var aString = "yy"', 1879 ' var aBlob = 0z22', 1880 ' var aList = [3, 4]', 1881 ' var aDict = {x: 2}', 1882 floatDecl, 1883 ' if ' .. case[0], 1884 ' echo 42' 1885 ' endif', 1886 'enddef'], 'Xdisassemble') 1887 source Xdisassemble 1888 var instr = execute('disassemble TestCase' .. nr) 1889 assert_match('TestCase' .. nr .. '.*' .. 1890 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1891 '\d \(PUSH\|FUNCREF\).*' .. 1892 '\d \(PUSH\|FUNCREF\|LOAD\).*' .. 1893 '\d ' .. case[1] .. '.*' .. 1894 '\d JUMP_IF_FALSE -> \d\+.*', 1895 instr) 1896 1897 nr += 1 1898 endfor 1899 1900 delete('Xdisassemble') 1901enddef 1902 1903def s:FalsyOp() 1904 echo g:flag ?? "yes" 1905 echo [] ?? "empty list" 1906 echo "" ?? "empty string" 1907enddef 1908 1909def Test_dsassemble_falsy_op() 1910 var res = execute('disass s:FalsyOp') 1911 assert_match('\<SNR>\d*_FalsyOp\_s*' .. 1912 'echo g:flag ?? "yes"\_s*' .. 1913 '0 LOADG g:flag\_s*' .. 1914 '1 JUMP_AND_KEEP_IF_TRUE -> 3\_s*' .. 1915 '2 PUSHS "yes"\_s*' .. 1916 '3 ECHO 1\_s*' .. 1917 'echo \[\] ?? "empty list"\_s*' .. 1918 '4 NEWLIST size 0\_s*' .. 1919 '5 JUMP_AND_KEEP_IF_TRUE -> 7\_s*' .. 1920 '6 PUSHS "empty list"\_s*' .. 1921 '7 ECHO 1\_s*' .. 1922 'echo "" ?? "empty string"\_s*' .. 1923 '\d\+ PUSHS "empty string"\_s*' .. 1924 '\d\+ ECHO 1\_s*' .. 1925 '\d\+ RETURN void', 1926 res) 1927enddef 1928 1929def Test_disassemble_compare_const() 1930 var cases = [ 1931 ['"xx" == "yy"', false], 1932 ['"aa" == "aa"', true], 1933 ['has("eval") ? true : false', true], 1934 ['has("asdf") ? true : false', false], 1935 ] 1936 1937 var nr = 1 1938 for case in cases 1939 writefile(['def TestCase' .. nr .. '()', 1940 ' if ' .. case[0], 1941 ' echo 42' 1942 ' endif', 1943 'enddef'], 'Xdisassemble') 1944 source Xdisassemble 1945 var instr = execute('disassemble TestCase' .. nr) 1946 if case[1] 1947 # condition true, "echo 42" executed 1948 assert_match('TestCase' .. nr .. '.*' .. 1949 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. 1950 '\d PUSHNR 42.*' .. 1951 '\d ECHO 1.*' .. 1952 '\d RETURN void', 1953 instr) 1954 else 1955 # condition false, function just returns 1956 assert_match('TestCase' .. nr .. '.*' .. 1957 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' .. 1958 'echo 42[ \n]*' .. 1959 'endif[ \n]*' .. 1960 '\d RETURN void', 1961 instr) 1962 endif 1963 1964 nr += 1 1965 endfor 1966 1967 delete('Xdisassemble') 1968enddef 1969 1970def s:Execute() 1971 execute 'help vim9.txt' 1972 var cmd = 'help vim9.txt' 1973 execute cmd 1974 var tag = 'vim9.txt' 1975 execute 'help ' .. tag 1976enddef 1977 1978def Test_disassemble_execute() 1979 var res = execute('disass s:Execute') 1980 assert_match('\<SNR>\d*_Execute\_s*' .. 1981 "execute 'help vim9.txt'\\_s*" .. 1982 '\d PUSHS "help vim9.txt"\_s*' .. 1983 '\d EXECUTE 1\_s*' .. 1984 "var cmd = 'help vim9.txt'\\_s*" .. 1985 '\d PUSHS "help vim9.txt"\_s*' .. 1986 '\d STORE $0\_s*' .. 1987 'execute cmd\_s*' .. 1988 '\d LOAD $0\_s*' .. 1989 '\d EXECUTE 1\_s*' .. 1990 "var tag = 'vim9.txt'\\_s*" .. 1991 '\d PUSHS "vim9.txt"\_s*' .. 1992 '\d STORE $1\_s*' .. 1993 "execute 'help ' .. tag\\_s*" .. 1994 '\d\+ PUSHS "help "\_s*' .. 1995 '\d\+ LOAD $1\_s*' .. 1996 '\d\+ CONCAT\_s*' .. 1997 '\d\+ EXECUTE 1\_s*' .. 1998 '\d\+ RETURN void', 1999 res) 2000enddef 2001 2002def s:Echomsg() 2003 echomsg 'some' 'message' 2004 echoconsole 'nothing' 2005 echoerr 'went' .. 'wrong' 2006enddef 2007 2008def Test_disassemble_echomsg() 2009 var res = execute('disass s:Echomsg') 2010 assert_match('\<SNR>\d*_Echomsg\_s*' .. 2011 "echomsg 'some' 'message'\\_s*" .. 2012 '\d PUSHS "some"\_s*' .. 2013 '\d PUSHS "message"\_s*' .. 2014 '\d ECHOMSG 2\_s*' .. 2015 "echoconsole 'nothing'\\_s*" .. 2016 '\d PUSHS "nothing"\_s*' .. 2017 '\d ECHOCONSOLE 1\_s*' .. 2018 "echoerr 'went' .. 'wrong'\\_s*" .. 2019 '\d PUSHS "wentwrong"\_s*' .. 2020 '\d ECHOERR 1\_s*' .. 2021 '\d RETURN void', 2022 res) 2023enddef 2024 2025def SomeStringArg(arg: string) 2026 echo arg 2027enddef 2028 2029def SomeAnyArg(arg: any) 2030 echo arg 2031enddef 2032 2033def SomeStringArgAndReturn(arg: string): string 2034 return arg 2035enddef 2036 2037def Test_display_func() 2038 var res1 = execute('function SomeStringArg') 2039 assert_match('.* def SomeStringArg(arg: string)\_s*' .. 2040 '\d *echo arg.*' .. 2041 ' *enddef', 2042 res1) 2043 2044 var res2 = execute('function SomeAnyArg') 2045 assert_match('.* def SomeAnyArg(arg: any)\_s*' .. 2046 '\d *echo arg\_s*' .. 2047 ' *enddef', 2048 res2) 2049 2050 var res3 = execute('function SomeStringArgAndReturn') 2051 assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' .. 2052 '\d *return arg\_s*' .. 2053 ' *enddef', 2054 res3) 2055enddef 2056 2057def Test_vim9script_forward_func() 2058 var lines =<< trim END 2059 vim9script 2060 def FuncOne(): string 2061 return FuncTwo() 2062 enddef 2063 def FuncTwo(): string 2064 return 'two' 2065 enddef 2066 g:res_FuncOne = execute('disass FuncOne') 2067 END 2068 writefile(lines, 'Xdisassemble') 2069 source Xdisassemble 2070 2071 # check that the first function calls the second with DCALL 2072 assert_match('\<SNR>\d*_FuncOne\_s*' .. 2073 'return FuncTwo()\_s*' .. 2074 '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' .. 2075 '\d RETURN', 2076 g:res_FuncOne) 2077 2078 delete('Xdisassemble') 2079 unlet g:res_FuncOne 2080enddef 2081 2082def s:ConcatStrings(): string 2083 return 'one' .. 'two' .. 'three' 2084enddef 2085 2086def s:ComputeConst(): number 2087 return 2 + 3 * 4 / 6 + 7 2088enddef 2089 2090def s:ComputeConstParen(): number 2091 return ((2 + 4) * (8 / 2)) / (3 + 4) 2092enddef 2093 2094def Test_simplify_const_expr() 2095 var res = execute('disass s:ConcatStrings') 2096 assert_match('<SNR>\d*_ConcatStrings\_s*' .. 2097 "return 'one' .. 'two' .. 'three'\\_s*" .. 2098 '\d PUSHS "onetwothree"\_s*' .. 2099 '\d RETURN', 2100 res) 2101 2102 res = execute('disass s:ComputeConst') 2103 assert_match('<SNR>\d*_ComputeConst\_s*' .. 2104 'return 2 + 3 \* 4 / 6 + 7\_s*' .. 2105 '\d PUSHNR 11\_s*' .. 2106 '\d RETURN', 2107 res) 2108 2109 res = execute('disass s:ComputeConstParen') 2110 assert_match('<SNR>\d*_ComputeConstParen\_s*' .. 2111 'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' .. 2112 '\d PUSHNR 3\>\_s*' .. 2113 '\d RETURN', 2114 res) 2115enddef 2116 2117def s:CallAppend() 2118 eval "some text"->append(2) 2119enddef 2120 2121def Test_shuffle() 2122 var res = execute('disass s:CallAppend') 2123 assert_match('<SNR>\d*_CallAppend\_s*' .. 2124 'eval "some text"->append(2)\_s*' .. 2125 '\d PUSHS "some text"\_s*' .. 2126 '\d PUSHNR 2\_s*' .. 2127 '\d SHUFFLE 2 up 1\_s*' .. 2128 '\d BCALL append(argc 2)\_s*' .. 2129 '\d DROP\_s*' .. 2130 '\d RETURN void', 2131 res) 2132enddef 2133 2134 2135def s:SilentMessage() 2136 silent echomsg "text" 2137 silent! echoerr "error" 2138enddef 2139 2140def Test_silent() 2141 var res = execute('disass s:SilentMessage') 2142 assert_match('<SNR>\d*_SilentMessage\_s*' .. 2143 'silent echomsg "text"\_s*' .. 2144 '\d CMDMOD silent\_s*' .. 2145 '\d PUSHS "text"\_s*' .. 2146 '\d ECHOMSG 1\_s*' .. 2147 '\d CMDMOD_REV\_s*' .. 2148 'silent! echoerr "error"\_s*' .. 2149 '\d CMDMOD silent!\_s*' .. 2150 '\d PUSHS "error"\_s*' .. 2151 '\d ECHOERR 1\_s*' .. 2152 '\d CMDMOD_REV\_s*' .. 2153 '\d\+ RETURN void', 2154 res) 2155enddef 2156 2157def s:SilentIf() 2158 silent if 4 == g:five 2159 silent elseif 4 == g:five 2160 endif 2161enddef 2162 2163def Test_silent_if() 2164 var res = execute('disass s:SilentIf') 2165 assert_match('<SNR>\d*_SilentIf\_s*' .. 2166 'silent if 4 == g:five\_s*' .. 2167 '\d\+ CMDMOD silent\_s*' .. 2168 '\d\+ PUSHNR 4\_s*' .. 2169 '\d\+ LOADG g:five\_s*' .. 2170 '\d\+ COMPAREANY ==\_s*' .. 2171 '\d\+ CMDMOD_REV\_s*' .. 2172 '\d\+ JUMP_IF_FALSE -> \d\+\_s*' .. 2173 'silent elseif 4 == g:five\_s*' .. 2174 '\d\+ JUMP -> \d\+\_s*' .. 2175 '\d\+ CMDMOD silent\_s*' .. 2176 '\d\+ PUSHNR 4\_s*' .. 2177 '\d\+ LOADG g:five\_s*' .. 2178 '\d\+ COMPAREANY ==\_s*' .. 2179 '\d\+ CMDMOD_REV\_s*' .. 2180 '\d\+ JUMP_IF_FALSE -> \d\+\_s*' .. 2181 'endif\_s*' .. 2182 '\d\+ RETURN void', 2183 res) 2184enddef 2185 2186def s:SilentFor() 2187 silent for i in [0] 2188 endfor 2189enddef 2190 2191def Test_silent_for() 2192 var res = execute('disass s:SilentFor') 2193 assert_match('<SNR>\d*_SilentFor\_s*' .. 2194 'silent for i in \[0\]\_s*' .. 2195 '\d CMDMOD silent\_s*' .. 2196 '\d STORE -1 in $0\_s*' .. 2197 '\d PUSHNR 0\_s*' .. 2198 '\d NEWLIST size 1\_s*' .. 2199 '\d CMDMOD_REV\_s*' .. 2200 '5 FOR $0 -> 8\_s*' .. 2201 '\d STORE $1\_s*' .. 2202 'endfor\_s*' .. 2203 '\d JUMP -> 5\_s*' .. 2204 '8 DROP\_s*' .. 2205 '\d RETURN void\_s*', 2206 res) 2207enddef 2208 2209def s:SilentWhile() 2210 silent while g:not 2211 endwhile 2212enddef 2213 2214def Test_silent_while() 2215 var res = execute('disass s:SilentWhile') 2216 assert_match('<SNR>\d*_SilentWhile\_s*' .. 2217 'silent while g:not\_s*' .. 2218 '0 CMDMOD silent\_s*' .. 2219 '\d LOADG g:not\_s*' .. 2220 '\d COND2BOOL\_s*' .. 2221 '\d CMDMOD_REV\_s*' .. 2222 '\d JUMP_IF_FALSE -> 6\_s*' .. 2223 2224 'endwhile\_s*' .. 2225 '\d JUMP -> 0\_s*' .. 2226 '6 RETURN void\_s*', 2227 res) 2228enddef 2229 2230def s:SilentReturn(): string 2231 silent return "done" 2232enddef 2233 2234def Test_silent_return() 2235 var res = execute('disass s:SilentReturn') 2236 assert_match('<SNR>\d*_SilentReturn\_s*' .. 2237 'silent return "done"\_s*' .. 2238 '\d CMDMOD silent\_s*' .. 2239 '\d PUSHS "done"\_s*' .. 2240 '\d CMDMOD_REV\_s*' .. 2241 '\d RETURN', 2242 res) 2243enddef 2244 2245def s:Profiled(): string 2246 # comment 2247 echo "profiled" 2248 # comment 2249 var some = "some text" 2250 return "done" 2251enddef 2252 2253def Test_profiled() 2254 if !has('profile') 2255 MissingFeature 'profile' 2256 endif 2257 var res = execute('disass profile s:Profiled') 2258 assert_match('<SNR>\d*_Profiled\_s*' .. 2259 '# comment\_s*' .. 2260 'echo "profiled"\_s*' .. 2261 '\d PROFILE START line 2\_s*' .. 2262 '\d PUSHS "profiled"\_s*' .. 2263 '\d ECHO 1\_s*' .. 2264 '# comment\_s*' .. 2265 'var some = "some text"\_s*' .. 2266 '\d PROFILE END\_s*' .. 2267 '\d PROFILE START line 4\_s*' .. 2268 '\d PUSHS "some text"\_s*' .. 2269 '\d STORE $0\_s*' .. 2270 'return "done"\_s*' .. 2271 '\d PROFILE END\_s*' .. 2272 '\d PROFILE START line 5\_s*' .. 2273 '\d PUSHS "done"\_s*' .. 2274 '\d\+ RETURN\_s*' .. 2275 '\d\+ PROFILE END', 2276 res) 2277enddef 2278 2279def Test_debugged() 2280 var res = execute('disass debug s:Profiled') 2281 assert_match('<SNR>\d*_Profiled\_s*' .. 2282 '# comment\_s*' .. 2283 'echo "profiled"\_s*' .. 2284 '\d DEBUG line 1-2 varcount 0\_s*' .. 2285 '\d PUSHS "profiled"\_s*' .. 2286 '\d ECHO 1\_s*' .. 2287 '# comment\_s*' .. 2288 'var some = "some text"\_s*' .. 2289 '\d DEBUG line 3-4 varcount 0\_s*' .. 2290 '\d PUSHS "some text"\_s*' .. 2291 '\d STORE $0\_s*' .. 2292 'return "done"\_s*' .. 2293 '\d DEBUG line 5-5 varcount 1\_s*' .. 2294 '\d PUSHS "done"\_s*' .. 2295 '\d RETURN\_s*', 2296 res) 2297enddef 2298 2299def s:DebugElseif() 2300 var b = false 2301 if b 2302 eval 1 + 0 2303 silent elseif !b 2304 eval 2 + 0 2305 endif 2306enddef 2307 2308def Test_debug_elseif() 2309 var res = execute('disass debug s:DebugElseif') 2310 assert_match('<SNR>\d*_DebugElseif\_s*' .. 2311 'var b = false\_s*' .. 2312 '0 DEBUG line 1-1 varcount 0\_s*' .. 2313 '1 PUSH false\_s*' .. 2314 '2 STORE $0\_s*' .. 2315 2316 'if b\_s*' .. 2317 '3 DEBUG line 2-2 varcount 1\_s*' .. 2318 '4 LOAD $0\_s*' .. 2319 '5 JUMP_IF_FALSE -> 10\_s*' .. 2320 2321 'eval 1 + 0\_s*' .. 2322 '6 DEBUG line 3-3 varcount 1\_s*' .. 2323 '7 PUSHNR 1\_s*' .. 2324 '8 DROP\_s*' .. 2325 2326 'silent elseif !b\_s*' .. 2327 '9 JUMP -> 20\_s*' .. 2328 '10 CMDMOD silent\_s*' .. 2329 '11 DEBUG line 4-4 varcount 1\_s*' .. 2330 '12 LOAD $0\_s*' .. 2331 '13 INVERT -1 (!val)\_s*' .. 2332 '14 CMDMOD_REV\_s*' .. 2333 '15 JUMP_IF_FALSE -> 20\_s*' .. 2334 2335 'eval 2 + 0\_s*' .. 2336 '16 DEBUG line 5-5 varcount 1\_s*' .. 2337 '17 PUSHNR 2\_s*' .. 2338 '18 DROP\_s*' .. 2339 2340 'endif\_s*' .. 2341 '19 DEBUG line 6-6 varcount 1\_s*' .. 2342 '20 RETURN void*', 2343 res) 2344enddef 2345 2346func Legacy() dict 2347 echo 'legacy' 2348endfunc 2349 2350def s:UseMember() 2351 var d = {func: Legacy} 2352 var v = d.func() 2353enddef 2354 2355def Test_disassemble_dict_stack() 2356 var res = execute('disass s:UseMember') 2357 assert_match('<SNR>\d*_UseMember\_s*' .. 2358 'var d = {func: Legacy}\_s*' .. 2359 '\d PUSHS "func"\_s*' .. 2360 '\d PUSHFUNC "Legacy"\_s*' .. 2361 '\d NEWDICT size 1\_s*' .. 2362 '\d STORE $0\_s*' .. 2363 2364 'var v = d.func()\_s*' .. 2365 '\d LOAD $0\_s*' .. 2366 '\d MEMBER func\_s*' .. 2367 '\d PCALL top (argc 0)\_s*' .. 2368 '\d PCALL end\_s*' .. 2369 '\d CLEARDICT\_s*' .. 2370 '\d\+ STORE $1\_s*' .. 2371 '\d\+ RETURN void*', 2372 res) 2373enddef 2374 2375def s:EchoMessages() 2376 echohl ErrorMsg | echom v:exception | echohl NONE 2377enddef 2378 2379def Test_disassemble_nextcmd() 2380 # splitting commands and removing trailing blanks should not change the line 2381 var res = execute('disass s:EchoMessages') 2382 assert_match('<SNR>\d*_EchoMessages\_s*' .. 2383 'echohl ErrorMsg | echom v:exception | echohl NONE', 2384 res) 2385enddef 2386 2387def Test_disassemble_after_reload() 2388 var lines =<< trim END 2389 vim9script 2390 if exists('g:ThisFunc') 2391 finish 2392 endif 2393 var name: any 2394 def g:ThisFunc(): number 2395 g:name = name 2396 return 0 2397 enddef 2398 def g:ThatFunc(): number 2399 name = g:name 2400 return 0 2401 enddef 2402 END 2403 lines->writefile('Xreload.vim') 2404 2405 source Xreload.vim 2406 g:ThisFunc() 2407 g:ThatFunc() 2408 2409 source Xreload.vim 2410 var res = execute('disass g:ThisFunc') 2411 assert_match('ThisFunc\_s*' .. 2412 'g:name = name\_s*' .. 2413 '\d LOADSCRIPT \[deleted\] from .*/Xreload.vim\_s*' .. 2414 '\d STOREG g:name\_s*' .. 2415 'return 0\_s*' .. 2416 '\d PUSHNR 0\_s*' .. 2417 '\d RETURN\_s*', 2418 res) 2419 2420 res = execute('disass g:ThatFunc') 2421 assert_match('ThatFunc\_s*' .. 2422 'name = g:name\_s*' .. 2423 '\d LOADG g:name\_s*' .. 2424 '\d STORESCRIPT \[deleted\] in .*/Xreload.vim\_s*' .. 2425 'return 0\_s*' .. 2426 '\d PUSHNR 0\_s*' .. 2427 '\d RETURN\_s*', 2428 res) 2429 2430 delete('Xreload.vim') 2431 delfunc g:ThisFunc 2432 delfunc g:ThatFunc 2433enddef 2434 2435 2436 2437" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker 2438