Ai
12 Star 47 Fork 0

Gitee 极速下载/Vim

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/vim/vim
克隆/下载
test_vim9_disassemble.vim 102.46 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072
" Test the :disassemble command, and compilation as a side effect
import './util/vim9.vim' as v9
func s:NotCompiled()
echo "not"
endfunc
let s:scriptvar = 4
let g:globalvar = 'g'
let b:buffervar = 'b'
let w:windowvar = 'w'
let t:tabpagevar = 't'
def s:ScriptFuncLoad(arg: string)
var local = 1
buffers
echo
echo arg
echo local
echo &lines
echo v:version
echo s:scriptvar
echo g:globalvar
echo get(g:, "global")
echo g:auto#var
echo b:buffervar
echo get(b:, "buffer")
echo w:windowvar
echo get(w:, "window")
echo t:tabpagevar
echo get(t:, "tab")
echo &tabstop
echo $ENVVAR
echo @z
enddef
def Test_disassemble_load()
assert_fails('disass NoFunc', 'E1061:')
assert_fails('disass NotCompiled', 'E1091:')
assert_fails('disass', 'E471:')
assert_fails('disass [', 'E475:')
assert_fails('disass 234', 'E129:')
assert_fails('disass <XX>foo', 'E129:')
assert_fails('disass Test_disassemble_load burp', 'E488:')
assert_fails('disass debug debug Test_disassemble_load', 'E488:')
assert_fails('disass profile profile Test_disassemble_load', 'E488:')
var res = execute('disass s:ScriptFuncLoad')
assert_match('<SNR>\d*_ScriptFuncLoad.*' ..
'buffers\_s*' ..
'\d\+ EXEC \+buffers\_s*' ..
'echo\_s*' ..
'echo arg\_s*' ..
'\d\+ LOAD arg\[-1\]\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo local\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo &lines\_s*' ..
'\d\+ LOADOPT &lines\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo v:version\_s*' ..
'\d\+ LOADV v:version\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo s:scriptvar\_s*' ..
'\d\+ LOADS s:scriptvar from .*test_vim9_disassemble.vim\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo g:globalvar\_s*' ..
'\d\+ LOADG g:globalvar\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo get(g:, "global")\_s*' ..
'\d\+ LOAD g:\_s*' ..
'\d\+ PUSHS "global"\_s*' ..
'\d\+ BCALL get(argc 2)\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo g:auto#var\_s*' ..
'\d\+ LOADAUTO g:auto#var\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo b:buffervar\_s*' ..
'\d\+ LOADB b:buffervar\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo get(b:, "buffer")\_s*' ..
'\d\+ LOAD b:\_s*' ..
'\d\+ PUSHS "buffer"\_s*' ..
'\d\+ BCALL get(argc 2).*' ..
' LOADW w:windowvar.*' ..
'echo get(w:, "window")\_s*' ..
'\d\+ LOAD w:\_s*' ..
'\d\+ PUSHS "window"\_s*' ..
'\d\+ BCALL get(argc 2).*' ..
' LOADT t:tabpagevar.*' ..
'echo get(t:, "tab")\_s*' ..
'\d\+ LOAD t:\_s*' ..
'\d\+ PUSHS "tab"\_s*' ..
'\d\+ BCALL get(argc 2).*' ..
' LOADENV $ENVVAR.*' ..
' LOADREG @z.*',
res)
enddef
def s:EditExpand()
var filename = "file"
var filenr = 123
edit the`=filename``=filenr`.txt
enddef
def Test_disassemble_exec_expr()
var res = execute('disass s:EditExpand')
assert_match('<SNR>\d*_EditExpand\_s*' ..
' var filename = "file"\_s*' ..
'\d PUSHS "file"\_s*' ..
'\d STORE $0\_s*' ..
' var filenr = 123\_s*' ..
'\d STORE 123 in $1\_s*' ..
' edit the`=filename``=filenr`.txt\_s*' ..
'\d PUSHS "edit the"\_s*' ..
'\d LOAD $0\_s*' ..
'\d LOAD $1\_s*' ..
'\d 2STRING stack\[-1\]\_s*' ..
'\d\+ PUSHS ".txt"\_s*' ..
'\d\+ EXECCONCAT 4\_s*' ..
'\d\+ RETURN void',
res)
enddef
if has('python3')
def s:PyHeredoc()
python3 << EOF
print('hello')
EOF
enddef
def Test_disassemble_python_heredoc()
var res = execute('disass s:PyHeredoc')
assert_match('<SNR>\d*_PyHeredoc.*' ..
" python3 << EOF^@ print('hello')^@EOF\\_s*" ..
'\d EXEC_SPLIT python3 << EOF^@ print(''hello'')^@EOF\_s*' ..
'\d RETURN void',
res)
enddef
endif
def s:Substitute()
var expr = "abc"
:%s/a/\=expr/&g#c
enddef
def Test_disassemble_substitute()
var res = execute('disass s:Substitute')
assert_match('<SNR>\d*_Substitute.*' ..
' var expr = "abc"\_s*' ..
'\d PUSHS "abc"\_s*' ..
'\d STORE $0\_s*' ..
' :%s/a/\\=expr/&g#c\_s*' ..
'\d SUBSTITUTE :%s/a/\\=expr/&g#c\_s*' ..
' 0 LOAD $0\_s*' ..
' -------------\_s*' ..
'\d RETURN void',
res)
enddef
def s:SearchPair()
var col = 8
searchpair("{", "", "}", "", "col('.') > col")
enddef
def Test_disassemble_seachpair()
var res = execute('disass s:SearchPair')
assert_match('<SNR>\d*_SearchPair.*' ..
' var col = 8\_s*' ..
'\d STORE 8 in $0\_s*' ..
' searchpair("{", "", "}", "", "col(''.'') > col")\_s*' ..
'\d PUSHS "{"\_s*' ..
'\d PUSHS ""\_s*' ..
'\d PUSHS "}"\_s*' ..
'\d PUSHS ""\_s*' ..
'\d INSTR\_s*' ..
' 0 PUSHS "."\_s*' ..
' 1 BCALL col(argc 1)\_s*' ..
' 2 LOAD $0\_s*' ..
' 3 COMPARENR >\_s*' ..
' -------------\_s*' ..
'\d BCALL searchpair(argc 5)\_s*' ..
'\d DROP\_s*' ..
'\d RETURN void',
res)
enddef
def s:SubstituteExpr()
substitute('a', 'b', '\=123', 'g')
enddef
def Test_disassemble_substitute_expr()
var res = execute('disass s:SubstituteExpr')
assert_match('<SNR>\d*_SubstituteExpr.*' ..
'substitute(''a'', ''b'', ''\\=123'', ''g'')\_s*' ..
'\d PUSHS "a"\_s*' ..
'\d PUSHS "b"\_s*' ..
'\d INSTR\_s*' ..
' 0 PUSHNR 123\_s*' ..
' -------------\_s*' ..
'\d PUSHS "g"\_s*' ..
'\d BCALL substitute(argc 4)\_s*' ..
'\d DROP\_s*' ..
'\d RETURN void',
res)
enddef
def s:RedirVar()
var result: string
redir =>> result
echo "text"
redir END
enddef
def Test_disassemble_redir_var()
var res = execute('disass s:RedirVar')
assert_match('<SNR>\d*_RedirVar.*' ..
' var result: string\_s*' ..
'\d PUSHS "\[NULL\]"\_s*' ..
'\d STORE $0\_s*' ..
' redir =>> result\_s*' ..
'\d REDIR\_s*' ..
' echo "text"\_s*' ..
'\d PUSHS "text"\_s*' ..
'\d ECHO 1\_s*' ..
' redir END\_s*' ..
'\d LOAD $0\_s*' ..
'\d REDIR END\_s*' ..
'\d CONCAT size 2\_s*' ..
'\d STORE $0\_s*' ..
'\d RETURN void',
res)
enddef
def s:Cexpr()
var errors = "list of errors"
cexpr errors
enddef
def Test_disassemble_cexpr()
CheckFeature quickfix
var res = execute('disass s:Cexpr')
assert_match('<SNR>\d*_Cexpr.*' ..
' var errors = "list of errors"\_s*' ..
'\d PUSHS "list of errors"\_s*' ..
'\d STORE $0\_s*' ..
' cexpr errors\_s*' ..
'\d CEXPR pre cexpr\_s*' ..
'\d LOAD $0\_s*' ..
'\d CEXPR core cexpr "cexpr errors"\_s*' ..
'\d RETURN void',
res)
enddef
def s:YankRange()
norm! m[jjm]
:'[,']yank
enddef
def Test_disassemble_yank_range()
var res = execute('disass s:YankRange')
assert_match('<SNR>\d*_YankRange.*' ..
' norm! m\[jjm\]\_s*' ..
'\d EXEC norm! m\[jjm\]\_s*' ..
' :''\[,''\]yank\_s*' ..
'\d EXEC :''\[,''\]yank\_s*' ..
'\d RETURN void',
res)
enddef
def s:PutExpr()
:3put ="text"
enddef
def Test_disassemble_put_expr()
var res = execute('disass s:PutExpr')
assert_match('<SNR>\d*_PutExpr.*' ..
' :3put ="text"\_s*' ..
'\d PUSHS "text"\_s*' ..
'\d PUT = 3\_s*' ..
'\d RETURN void',
res)
enddef
def s:IputExpr()
:3iput ="text"
enddef
def Test_disassemble_iput_expr()
var res = execute('disass s:IputExpr')
assert_match('<SNR>\d*_IputExpr.*' ..
' :3iput ="text"\_s*' ..
'\d PUSHS "text"\_s*' ..
'\d IPUT = 3\_s*' ..
'\d RETURN void',
res)
enddef
def s:PutRange()
:$-2put a
:$-3put! b
enddef
def Test_disassemble_put_range()
var res = execute('disass s:PutRange')
assert_match('<SNR>\d*_PutRange.*' ..
' :$-2put a\_s*' ..
'\d RANGE $-2\_s*' ..
'\d PUT a range\_s*' ..
' :$-3put! b\_s*' ..
'\d RANGE $-3\_s*' ..
'\d PUT b above range\_s*' ..
'\d RETURN void',
res)
enddef
def s:IputRange()
:$-2iput a
:$-3iput! b
enddef
def Test_disassemble_iput_range()
var res = execute('disass s:IputRange')
assert_match('<SNR>\d*_IputRange.*' ..
' :$-2iput a\_s*' ..
'\d RANGE $-2\_s*' ..
'\d IPUT a range\_s*' ..
' :$-3iput! b\_s*' ..
'\d RANGE $-3\_s*' ..
'\d IPUT b above range\_s*' ..
'\d RETURN void',
res)
enddef
def s:ScriptFuncPush()
var localbool = true
var localspec = v:none
var localblob = 0z1234
var localfloat = 1.234
enddef
def Test_disassemble_push()
mkdir('Xdisdir/autoload', 'pR')
var save_rtp = &rtp
exe 'set rtp^=' .. getcwd() .. '/Xdisdir'
var lines =<< trim END
vim9script
END
writefile(lines, 'Xdisdir/autoload/autoscript.vim')
lines =<< trim END
vim9script
import autoload 'autoscript.vim'
def AutoloadFunc()
&operatorfunc = autoscript.Opfunc
enddef
var res = execute('disass AutoloadFunc')
assert_match('<SNR>\d*_AutoloadFunc.*' ..
'&operatorfunc = autoscript.Opfunc\_s*' ..
'0 AUTOLOAD autoscript#Opfunc\_s*' ..
'1 STOREFUNCOPT &operatorfunc\_s*' ..
'2 RETURN void',
res)
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
def Test_disassemble_import_autoload()
writefile(['vim9script'], 'XimportAL.vim', 'D')
var lines =<< trim END
vim9script
import autoload './XimportAL.vim'
def AutoloadFunc()
echo XimportAL.SomeFunc()
echo XimportAL.someVar
XimportAL.someVar = "yes"
enddef
var res = execute('disass AutoloadFunc')
assert_match('<SNR>\d*_AutoloadFunc.*' ..
'echo XimportAL.SomeFunc()\_s*' ..
'\d SOURCE .*/testdir/XimportAL.vim\_s*' ..
'\d PUSHFUNC "<80><fd>R\d\+_SomeFunc"\_s*' ..
'\d PCALL top (argc 0)\_s*' ..
'\d PCALL end\_s*' ..
'\d ECHO 1\_s*' ..
'echo XimportAL.someVar\_s*' ..
'\d SOURCE .*/testdir/XimportAL.vim\_s*' ..
'\d LOADEXPORT s:someVar from .*/testdir/XimportAL.vim\_s*' ..
'\d ECHO 1\_s*' ..
'XimportAL.someVar = "yes"\_s*' ..
'\d\+ PUSHS "yes"\_s*' ..
'\d\+ SOURCE .*/testdir/XimportAL.vim\_s*' ..
'\d\+ STOREEXPORT someVar in .*/testdir/XimportAL.vim\_s*' ..
'\d\+ RETURN void',
res)
END
v9.CheckScriptSuccess(lines)
enddef
def Test_disassemble_import_autoload_autoload()
mkdir('Xauto_auto/autoload', 'pR')
var lines =<< trim END
vim9script
export const val = 11
END
writefile(lines, 'Xauto_auto/autoload/Xauto_vars_f1.vim')
lines =<< trim END
vim9script
import autoload './Xauto_auto/autoload/Xauto_vars_f1.vim' as f1
def F()
f1.val = 13
enddef
var res = execute('disass F')
assert_match('<SNR>\d*_F.*' ..
'f1.val = 13\_s*' ..
'\d PUSHNR 13\_s*' ..
'\d SOURCE .*/Xauto_auto/autoload/Xauto_vars_f1.vim\_s*' ..
'\d STOREEXPORT val in .*/Xauto_auto/autoload/Xauto_vars_f1.vim\_s*' ..
'\d RETURN void',
res)
END
v9.CheckScriptSuccess(lines)
enddef
def s:ScriptFuncStore()
var localnr = 1
localnr = 2
var localstr = 'abc'
localstr = 'xyz'
v:char = 'abc'
s:scriptvar = 'sv'
g:globalvar = 'gv'
g:auto#var = 'av'
b:buffervar = 'bv'
w:windowvar = 'wv'
t:tabpagevar = 'tv'
&tabstop = 8
&opfunc = (t) => len(t)
$ENVVAR = 'ev'
@z = 'rv'
enddef
def Test_disassemble_store()
var res = execute('disass s:ScriptFuncStore')
assert_match('<SNR>\d*_ScriptFuncStore.*' ..
'var localnr = 1.*' ..
'localnr = 2.*' ..
' STORE 2 in $0.*' ..
'var localstr = ''abc''.*' ..
'localstr = ''xyz''.*' ..
' STORE $1.*' ..
'v:char = ''abc''.*' ..
'STOREV v:char.*' ..
's:scriptvar = ''sv''.*' ..
' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' ..
'g:globalvar = ''gv''.*' ..
' STOREG g:globalvar.*' ..
'g:auto#var = ''av''.*' ..
' STOREAUTO g:auto#var.*' ..
'b:buffervar = ''bv''.*' ..
' STOREB b:buffervar.*' ..
'w:windowvar = ''wv''.*' ..
' STOREW w:windowvar.*' ..
't:tabpagevar = ''tv''.*' ..
' STORET t:tabpagevar.*' ..
'&tabstop = 8\_s*' ..
'\d\+ PUSHNR 8\_s*' ..
'\d\+ STOREOPT &tabstop\_s*' ..
'&opfunc = (t) => len(t)\_s*' ..
'\d\+ FUNCREF <lambda>\d\+\_s*' ..
'\d\+ STOREFUNCOPT &opfunc\_s*' ..
'$ENVVAR = ''ev''\_s*' ..
'\d\+ PUSHS "ev"\_s*' ..
'\d\+ STOREENV $ENVVAR\_s*' ..
'@z = ''rv''.*' ..
'\d\+ STOREREG @z.*',
res)
enddef
def s:ScriptFuncStoreMember()
var locallist: list<number> = []
locallist[0] = 123
var localdict: dict<number> = {}
localdict["a"] = 456
var localblob: blob = 0z1122
localblob[1] = 33
enddef
def Test_disassemble_store_member()
var res = execute('disass s:ScriptFuncStoreMember')
assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' ..
'var locallist: list<number> = []\_s*' ..
'\d NEWLIST size 0\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'locallist\[0\] = 123\_s*' ..
'\d PUSHNR 123\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d LOAD $0\_s*' ..
'\d STOREINDEX list\_s*' ..
'var localdict: dict<number> = {}\_s*' ..
'\d NEWDICT size 0\_s*' ..
'\d SETTYPE dict<number>\_s*' ..
'\d STORE $1\_s*' ..
'localdict\["a"\] = 456\_s*' ..
'\d\+ PUSHNR 456\_s*' ..
'\d\+ PUSHS "a"\_s*' ..
'\d\+ LOAD $1\_s*' ..
'\d\+ STOREINDEX dict\_s*' ..
'var localblob: blob = 0z1122\_s*' ..
'\d\+ PUSHBLOB 0z1122\_s*' ..
'\d\+ STORE $2\_s*' ..
'localblob\[1\] = 33\_s*' ..
'\d\+ PUSHNR 33\_s*' ..
'\d\+ PUSHNR 1\_s*' ..
'\d\+ LOAD $2\_s*' ..
'\d\+ STOREINDEX blob\_s*' ..
'\d\+ RETURN void',
res)
enddef
if has('job')
def s:StoreNull()
var ss = null_string
var bb = null_blob
var dd = null_dict
var ll = null_list
var Ff = null_function
var Pp = null_partial
var jj = null_job
var cc = null_channel
var oo = null_object
var nc = null_class
enddef
def Test_disassemble_assign_null()
var res = execute('disass s:StoreNull')
assert_match('<SNR>\d*_StoreNull\_s*' ..
'var ss = null_string\_s*' ..
'\d\+ PUSHS "\[NULL\]"\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var bb = null_blob\_s*' ..
'\d\+ PUSHBLOB 0z\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var dd = null_dict\_s*' ..
'\d\+ NEWDICT size -1\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var ll = null_list\_s*' ..
'\d\+ NEWLIST size -1\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var Ff = null_function\_s*' ..
'\d\+ PUSHFUNC "\[none\]"\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var Pp = null_partial\_s*' ..
'\d\+ NEWPARTIAL\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var jj = null_job\_s*' ..
'\d\+ PUSHJOB "no process"\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var cc = null_channel\_s*' ..
'\d\+ PUSHCHANNEL 0\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var oo = null_object\_s*' ..
'\d\+ PUSHOBJ null\_s*' ..
'\d\+ STORE $\d\_s*' ..
'var nc = null_class\_s*' ..
'\d\+ PUSHCLASS null\_s*' ..
'\d\+ STORE $\d\_s*' ..
'\d\+ RETURN void',
res)
enddef
endif
def s:ScriptFuncStoreIndex()
var d = {dd: {}}
d.dd[0] = 0
enddef
def Test_disassemble_store_index()
var res = execute('disass s:ScriptFuncStoreIndex')
assert_match('<SNR>\d*_ScriptFuncStoreIndex\_s*' ..
'var d = {dd: {}}\_s*' ..
'\d PUSHS "dd"\_s*' ..
'\d NEWDICT size 0\_s*' ..
'\d NEWDICT size 1\_s*' ..
'\d SETTYPE dict<dict<any>>\_s*' ..
'\d STORE $0\_s*' ..
'd.dd\[0\] = 0\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d LOAD $0\_s*' ..
'\d MEMBER dd\_s*' ..
'\d\+ USEDICT\_s*' ..
'\d\+ STOREINDEX any\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:ListAssign()
var x: string
var y: string
var l: list<any>
[x, y; l] = g:stringlist
enddef
def Test_disassemble_list_assign()
var res = execute('disass s:ListAssign')
assert_match('<SNR>\d*_ListAssign\_s*' ..
'var x: string\_s*' ..
'\d PUSHS "\[NULL\]"\_s*' ..
'\d STORE $0\_s*' ..
'var y: string\_s*' ..
'\d PUSHS "\[NULL\]"\_s*' ..
'\d STORE $1\_s*' ..
'var l: list<any>\_s*' ..
'\d NEWLIST size 0\_s*' ..
'\d STORE $2\_s*' ..
'\[x, y; l\] = g:stringlist\_s*' ..
'\d LOADG g:stringlist\_s*' ..
'\d CHECKTYPE list<any> stack\[-1\]\_s*' ..
'\d CHECKLEN >= 2\_s*' ..
'\d\+ ITEM 0\_s*' ..
'\d\+ CHECKTYPE string stack\[-1\] var 1\_s*' ..
'\d\+ STORE $0\_s*' ..
'\d\+ ITEM 1\_s*' ..
'\d\+ CHECKTYPE string stack\[-1\] var 2\_s*' ..
'\d\+ STORE $1\_s*' ..
'\d\+ SLICE 2\_s*' ..
'\d\+ STORE $2\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:ListAssignWithOp()
var a = 2
var b = 3
[a, b] += [4, 5]
enddef
def Test_disassemble_list_assign_with_op()
var res = execute('disass s:ListAssignWithOp')
assert_match('<SNR>\d*_ListAssignWithOp\_s*' ..
'var a = 2\_s*' ..
'\d STORE 2 in $0\_s*' ..
'var b = 3\_s*' ..
'\d STORE 3 in $1\_s*' ..
'\[a, b\] += \[4, 5\]\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ PUSHNR 5\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ ITEM 0 with op\_s*' ..
'\d\+ OPNR +\_s*' ..
'\d\+ STORE $0\_s*' ..
'\d\+ LOAD $1\_s*' ..
'\d\+ ITEM 1 with op\_s*' ..
'\d\+ OPNR +\_s*' ..
'\d\+ STORE $1\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:ListAdd()
var l: list<number> = []
add(l, 123)
add(l, g:aNumber)
enddef
def Test_disassemble_list_add()
var res = execute('disass s:ListAdd')
assert_match('<SNR>\d*_ListAdd\_s*' ..
'var l: list<number> = []\_s*' ..
'\d NEWLIST size 0\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'add(l, 123)\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 123\_s*' ..
'\d LISTAPPEND\_s*' ..
'\d DROP\_s*' ..
'add(l, g:aNumber)\_s*' ..
'\d LOAD $0\_s*' ..
'\d\+ LOADG g:aNumber\_s*' ..
'\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
'\d\+ LISTAPPEND\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:BlobAdd()
var b: blob = 0z
add(b, 123)
add(b, g:aNumber)
enddef
def Test_disassemble_blob_add()
var res = execute('disass s:BlobAdd')
assert_match('<SNR>\d*_BlobAdd\_s*' ..
'var b: blob = 0z\_s*' ..
'\d PUSHBLOB 0z\_s*' ..
'\d STORE $0\_s*' ..
'add(b, 123)\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 123\_s*' ..
'\d BLOBAPPEND\_s*' ..
'\d DROP\_s*' ..
'add(b, g:aNumber)\_s*' ..
'\d LOAD $0\_s*' ..
'\d\+ LOADG g:aNumber\_s*' ..
'\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
'\d\+ BLOBAPPEND\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:BlobIndexSlice()
var b: blob = 0z112233
echo b[1]
echo b[1 : 2]
enddef
def Test_disassemble_blob_index_slice()
var res = execute('disass s:BlobIndexSlice')
assert_match('<SNR>\d*_BlobIndexSlice\_s*' ..
'var b: blob = 0z112233\_s*' ..
'\d PUSHBLOB 0z112233\_s*' ..
'\d STORE $0\_s*' ..
'echo b\[1\]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d BLOBINDEX\_s*' ..
'\d ECHO 1\_s*' ..
'echo b\[1 : 2\]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d\+ PUSHNR 2\_s*' ..
'\d\+ BLOBSLICE\_s*' ..
'\d\+ ECHO 1\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:ScriptFuncUnlet()
g:somevar = "value"
unlet g:somevar
unlet! g:somevar
unlet $SOMEVAR
var l = [1, 2, 3]
unlet l[2]
unlet l[0 : 1]
enddef
def Test_disassemble_unlet()
var res = execute('disass s:ScriptFuncUnlet')
assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' ..
'g:somevar = "value"\_s*' ..
'\d PUSHS "value"\_s*' ..
'\d STOREG g:somevar\_s*' ..
'unlet g:somevar\_s*' ..
'\d UNLET g:somevar\_s*' ..
'unlet! g:somevar\_s*' ..
'\d UNLET! g:somevar\_s*' ..
'unlet $SOMEVAR\_s*' ..
'\d UNLETENV $SOMEVAR\_s*' ..
'var l = \[1, 2, 3]\_s*' ..
'\d\+ PUSHNR 1\_s*' ..
'\d\+ PUSHNR 2\_s*' ..
'\d\+ PUSHNR 3\_s*' ..
'\d\+ NEWLIST size 3\_s*' ..
'\d\+ SETTYPE list<number>\_s*' ..
'\d\+ STORE $0\_s*' ..
'unlet l\[2]\_s*' ..
'\d\+ PUSHNR 2\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ UNLETINDEX\_s*' ..
'unlet l\[0 : 1]\_s*' ..
'\d\+ PUSHNR 0\_s*' ..
'\d\+ PUSHNR 1\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ UNLETRANGE\_s*',
res)
enddef
def s:LockLocal()
var d = {a: 1}
lockvar d.a
const nr = 22
enddef
def Test_disassemble_lock_local()
var res = execute('disass s:LockLocal')
assert_match('<SNR>\d*_LockLocal\_s*' ..
'var d = {a: 1}\_s*' ..
'\d PUSHS "a"\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d NEWDICT size 1\_s*' ..
'\d SETTYPE dict<number>\_s*' ..
'\d STORE $0\_s*' ..
'lockvar d.a\_s*' ..
'\d LOAD $0\_s*' ..
'\d LOCKUNLOCK lockvar 2 d.a\_s*' ..
'const nr = 22\_s*' ..
'\d\+ PUSHNR 22\_s*' ..
'\d\+ LOCKCONST\_s*' ..
'\d\+ STORE $1',
res)
enddef
def s:ScriptFuncTry()
try
echo "yes"
catch /fail/
echo "no"
finally
throw "end"
endtry
enddef
def Test_disassemble_try()
var res = execute('disass s:ScriptFuncTry')
assert_match('<SNR>\d*_ScriptFuncTry\_s*' ..
'try\_s*' ..
'\d TRY catch -> \d\+, finally -> \d\+, endtry -> \d\+\_s*' ..
'echo "yes"\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d ECHO 1\_s*' ..
'catch /fail/\_s*' ..
'\d JUMP -> \d\+\_s*' ..
'\d PUSH v:exception\_s*' ..
'\d PUSHS "fail"\_s*' ..
'\d COMPARESTRING =\~\_s*' ..
'\d JUMP_IF_FALSE -> \d\+\_s*' ..
'\d CATCH\_s*' ..
'echo "no"\_s*' ..
'\d\+ PUSHS "no"\_s*' ..
'\d\+ ECHO 1\_s*' ..
'finally\_s*' ..
'\d\+ FINALLY\_s*' ..
'throw "end"\_s*' ..
'\d\+ PUSHS "end"\_s*' ..
'\d\+ THROW\_s*' ..
'endtry\_s*' ..
'\d\+ ENDTRY',
res)
enddef
def s:ScriptFuncNew()
var ll = [1, "two", 333]
var dd = {one: 1, two: "val"}
enddef
def Test_disassemble_new()
var res = execute('disass s:ScriptFuncNew')
assert_match('<SNR>\d*_ScriptFuncNew\_s*' ..
'var ll = \[1, "two", 333\]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHS "two"\_s*' ..
'\d PUSHNR 333\_s*' ..
'\d NEWLIST size 3\_s*' ..
'\d STORE $0\_s*' ..
'var dd = {one: 1, two: "val"}\_s*' ..
'\d PUSHS "one"\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHS "two"\_s*' ..
'\d PUSHS "val"\_s*' ..
'\d NEWDICT size 2\_s*',
res)
enddef
def s:FuncWithArg(arg: any)
echo arg
enddef
func s:UserFunc()
echo 'nothing'
endfunc
func s:UserFuncWithArg(arg)
echo a:arg
endfunc
def s:ScriptFuncCall(): string
changenr()
char2nr("abc")
g:Test_disassemble_new()
FuncWithArg(343)
ScriptFuncNew()
s:ScriptFuncNew()
UserFunc()
UserFuncWithArg("foo")
var FuncRef = function("UserFunc")
FuncRef()
var FuncRefWithArg = function("UserFuncWithArg")
FuncRefWithArg("bar")
return "yes"
enddef
def Test_disassemble_call()
var res = execute('disass s:ScriptFuncCall')
assert_match('<SNR>\d\+_ScriptFuncCall\_s*' ..
'changenr()\_s*' ..
'\d BCALL changenr(argc 0)\_s*' ..
'\d DROP\_s*' ..
'char2nr("abc")\_s*' ..
'\d PUSHS "abc"\_s*' ..
'\d BCALL char2nr(argc 1)\_s*' ..
'\d DROP\_s*' ..
'g:Test_disassemble_new()\_s*' ..
'\d DCALL Test_disassemble_new(argc 0)\_s*' ..
'\d DROP\_s*' ..
'FuncWithArg(343)\_s*' ..
'\d\+ PUSHNR 343\_s*' ..
'\d\+ DCALL <SNR>\d\+_FuncWithArg(argc 1)\_s*' ..
'\d\+ DROP\_s*' ..
'ScriptFuncNew()\_s*' ..
'\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' ..
'\d\+ DROP\_s*' ..
's:ScriptFuncNew()\_s*' ..
'\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' ..
'\d\+ DROP\_s*' ..
'UserFunc()\_s*' ..
'\d\+ UCALL <80><fd>R\d\+_UserFunc(argc 0)\_s*' ..
'\d\+ DROP\_s*' ..
'UserFuncWithArg("foo")\_s*' ..
'\d\+ PUSHS "foo"\_s*' ..
'\d\+ UCALL <80><fd>R\d\+_UserFuncWithArg(argc 1)\_s*' ..
'\d\+ DROP\_s*' ..
'var FuncRef = function("UserFunc")\_s*' ..
'\d\+ PUSHS "UserFunc"\_s*' ..
'\d\+ BCALL function(argc 1)\_s*' ..
'\d\+ STORE $0\_s*' ..
'FuncRef()\_s*' ..
'\d\+ LOAD $\d\_s*' ..
'\d\+ PCALL (argc 0)\_s*' ..
'\d\+ DROP\_s*' ..
'var FuncRefWithArg = function("UserFuncWithArg")\_s*' ..
'\d\+ PUSHS "UserFuncWithArg"\_s*' ..
'\d\+ BCALL function(argc 1)\_s*' ..
'\d\+ STORE $1\_s*' ..
'FuncRefWithArg("bar")\_s*' ..
'\d\+ PUSHS "bar"\_s*' ..
'\d\+ LOAD $\d\_s*' ..
'\d\+ PCALL (argc 1)\_s*' ..
'\d\+ DROP\_s*' ..
'return "yes"\_s*' ..
'\d\+ PUSHS "yes"\_s*' ..
'\d\+ RETURN',
res)
enddef
def s:CreateRefs()
var local = 'a'
def Append(arg: string)
local ..= arg
enddef
g:Append = Append
def Get(): string
return local
enddef
g:Get = Get
enddef
def Test_disassemble_closure()
CreateRefs()
var res = execute('disass g:Append')
assert_match('<lambda>\d\_s*' ..
'local ..= arg\_s*' ..
'\d LOADOUTER level 1 $0\_s*' ..
'\d LOAD arg\[-1\]\_s*' ..
'\d CONCAT size 2\_s*' ..
'\d STOREOUTER level 1 $0\_s*' ..
'\d RETURN void',
res)
res = execute('disass g:Get')
assert_match('<lambda>\d\_s*' ..
'return local\_s*' ..
'\d LOADOUTER level 1 $0\_s*' ..
'\d RETURN',
res)
unlet g:Append
unlet g:Get
enddef
def s:ClosureArg(arg: string)
var Ref = () => arg .. "x"
enddef
def Test_disassemble_closure_arg()
var res = execute('disass s:ClosureArg')
assert_match('<SNR>\d\+_ClosureArg\_s*' ..
'var Ref = () => arg .. "x"\_s*' ..
'\d FUNCREF <lambda>\d\+',
res)
var lres = execute('disass ' .. matchstr(res, '<lambda>\d\+'))
assert_match('<lambda>\d\+\_s*' ..
'return arg .. "x"\_s*' ..
'\d LOADOUTER level 1 arg\[-1]\_s*' ..
'\d PUSHS "x"\_s*' ..
'\d CONCAT size 2\_s*' ..
'\d RETURN',
lres)
enddef
def s:ClosureInLoop()
for i in range(5)
var ii = i
continue
break
if g:val
return
endif
g:Ref = () => ii
continue
break
if g:val
return
endif
endfor
enddef
" Mainly check that ENDLOOP is only produced after a closure was created.
def Test_disassemble_closure_in_loop()
var res = execute('disass s:ClosureInLoop')
assert_match('<SNR>\d\+_ClosureInLoop\_s*' ..
'for i in range(5)\_s*' ..
'\d\+ STORE -1 in $0\_s*' ..
'\d\+ PUSHNR 5\_s*' ..
'\d\+ BCALL range(argc 1)\_s*' ..
'\d\+ FOR $0 -> \d\+\_s*' ..
'\d\+ STORE $2\_s*' ..
'var ii = i\_s*' ..
'\d\+ LOAD $2\_s*' ..
'\d\+ STORE $3\_s*' ..
'continue\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'break\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'if g:val\_s*' ..
'\d\+ LOADG g:val\_s*' ..
'\d\+ COND2BOOL\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+\_s*' ..
' return\_s*' ..
'\d\+ PUSHNR 0\_s*' ..
'\d\+ RETURN\_s*' ..
'endif\_s*' ..
'g:Ref = () => ii\_s*' ..
'\d\+ FUNCREF <lambda>\d\+ vars $3-$3\_s*' ..
'\d\+ STOREG g:Ref\_s*' ..
'continue\_s*' ..
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'break\_s*' ..
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'if g:val\_s*' ..
'\d\+ LOADG g:val\_s*' ..
'\d\+ COND2BOOL\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+\_s*' ..
' return\_s*' ..
'\d\+ PUSHNR 0\_s*' ..
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
'\d\+ RETURN\_s*' ..
'endif\_s*' ..
'endfor\_s*' ..
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
res)
enddef
def EchoArg(arg: string): string
return arg
enddef
def s:RefThis(): func
return function('EchoArg')
enddef
def s:ScriptPCall()
RefThis()("text")
enddef
def Test_disassemble_pcall()
var res = execute('disass s:ScriptPCall')
assert_match('<SNR>\d\+_ScriptPCall\_s*' ..
'RefThis()("text")\_s*' ..
'\d DCALL <SNR>\d\+_RefThis(argc 0)\_s*' ..
'\d PUSHS "text"\_s*' ..
'\d PCALL top (argc 1)\_s*' ..
'\d PCALL end\_s*' ..
'\d DROP\_s*' ..
'\d RETURN void',
res)
enddef
def s:FuncWithForwardCall(): string
return g:DefinedLater("yes")
enddef
def DefinedLater(arg: string): string
return arg
enddef
def Test_disassemble_update_instr()
var res = execute('disass s:FuncWithForwardCall')
assert_match('FuncWithForwardCall\_s*' ..
'return g:DefinedLater("yes")\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d DCALL DefinedLater(argc 1)\_s*' ..
'\d RETURN',
res)
# Calling the function will change UCALL into the faster DCALL
assert_equal('yes', FuncWithForwardCall())
res = execute('disass s:FuncWithForwardCall')
assert_match('FuncWithForwardCall\_s*' ..
'return g:DefinedLater("yes")\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d DCALL DefinedLater(argc 1)\_s*' ..
'\d RETURN',
res)
enddef
def FuncWithDefault(l: number, arg: string = "default", nr = 77): string
return arg .. nr
enddef
def Test_disassemble_call_default()
var res = execute('disass FuncWithDefault')
assert_match('FuncWithDefault\_s*' ..
' arg = "default"\_s*' ..
'\d JUMP_IF_ARG_SET arg\[-2\] -> 3\_s*' ..
'\d PUSHS "default"\_s*' ..
'\d STORE arg\[-2]\_s*' ..
' nr = 77\_s*' ..
'3 JUMP_IF_ARG_SET arg\[-1\] -> 6\_s*' ..
'\d PUSHNR 77\_s*' ..
'\d STORE arg\[-1]\_s*' ..
' return arg .. nr\_s*' ..
'6 LOAD arg\[-2]\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d 2STRING stack\[-1]\_s*' ..
'\d\+ CONCAT size 2\_s*' ..
'\d\+ RETURN',
res)
enddef
def s:HasEval()
if has("eval")
echo "yes"
else
echo "no"
endif
enddef
def s:HasNothing()
if has("nothing")
echo "yes"
else
echo "no"
endif
enddef
def s:HasSomething()
if has("nothing")
echo "nothing"
elseif has("something")
echo "something"
elseif has("eval")
echo "eval"
elseif has("less")
echo "less"
endif
enddef
def s:HasGuiRunning()
if has("gui_running")
echo "yes"
else
echo "no"
endif
enddef
def s:LenConstant(): number
return len("foo") + len("fighters")
enddef
def Test_disassemble_const_expr()
var instr = execute('disassemble LenConstant')
assert_match('LenConstant\_s*' ..
'return len("foo") + len("fighters")\_s*' ..
'\d PUSHNR 11\_s*',
instr)
assert_notmatch('BCALL len', instr)
assert_equal("\nyes", execute('HasEval()'))
instr = execute('disassemble HasEval')
assert_match('HasEval\_s*' ..
'if has("eval")\_s*' ..
'echo "yes"\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d ECHO 1\_s*' ..
'else\_s*' ..
'echo "no"\_s*' ..
'endif\_s*',
instr)
assert_notmatch('JUMP', instr)
assert_equal("\nno", execute('HasNothing()'))
instr = execute('disassemble HasNothing')
assert_match('HasNothing\_s*' ..
'if has("nothing")\_s*' ..
'echo "yes"\_s*' ..
'else\_s*' ..
'echo "no"\_s*' ..
'\d PUSHS "no"\_s*' ..
'\d ECHO 1\_s*' ..
'endif',
instr)
assert_notmatch('PUSHS "yes"', instr)
assert_notmatch('JUMP', instr)
assert_equal("\neval", execute('HasSomething()'))
instr = execute('disassemble HasSomething')
assert_match('HasSomething.*' ..
'if has("nothing")\_s*' ..
'echo "nothing"\_s*' ..
'elseif has("something")\_s*' ..
'echo "something"\_s*' ..
'elseif has("eval")\_s*' ..
'echo "eval"\_s*' ..
'\d PUSHS "eval"\_s*' ..
'\d ECHO 1\_s*' ..
'elseif has("less").*' ..
'echo "less"\_s*' ..
'endif',
instr)
assert_notmatch('PUSHS "nothing"', instr)
assert_notmatch('PUSHS "something"', instr)
assert_notmatch('PUSHS "less"', instr)
assert_notmatch('JUMP', instr)
var result: string
var instr_expected: string
if has('gui')
if has('gui_running')
# GUI already running, always returns "yes"
result = "\nyes"
instr_expected = 'HasGuiRunning.*' ..
'if has("gui_running")\_s*' ..
' echo "yes"\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d ECHO 1\_s*' ..
'else\_s*' ..
' echo "no"\_s*' ..
'endif'
else
result = "\nno"
if has('unix')
# GUI not running but can start later, call has()
instr_expected = 'HasGuiRunning.*' ..
'if has("gui_running")\_s*' ..
'\d PUSHS "gui_running"\_s*' ..
'\d BCALL has(argc 1)\_s*' ..
'\d COND2BOOL\_s*' ..
'\d JUMP_IF_FALSE -> \d\_s*' ..
' echo "yes"\_s*' ..
'\d PUSHS "yes"\_s*' ..
'\d ECHO 1\_s*' ..
'else\_s*' ..
'\d JUMP -> \d\_s*' ..
' echo "no"\_s*' ..
'\d PUSHS "no"\_s*' ..
'\d ECHO 1\_s*' ..
'endif'
else
# GUI not running, always return "no"
instr_expected = 'HasGuiRunning.*' ..
'if has("gui_running")\_s*' ..
' echo "yes"\_s*' ..
'else\_s*' ..
' echo "no"\_s*' ..
'\d PUSHS "no"\_s*' ..
'\d ECHO 1\_s*' ..
'endif'
endif
endif
else
# GUI not supported, always return "no"
result = "\nno"
instr_expected = 'HasGuiRunning.*' ..
'if has("gui_running")\_s*' ..
' echo "yes"\_s*' ..
'else\_s*' ..
' echo "no"\_s*' ..
'\d PUSHS "no"\_s*' ..
'\d ECHO 1\_s*' ..
'endif'
endif
assert_equal(result, execute('HasGuiRunning()'))
instr = execute('disassemble HasGuiRunning')
assert_match(instr_expected, instr)
enddef
def ReturnInIf(): string
if 1 < 0
return "maybe"
endif
if g:cond
return "yes"
else
return "no"
endif
enddef
def Test_disassemble_return_in_if()
var instr = execute('disassemble ReturnInIf')
assert_match('ReturnInIf\_s*' ..
'if 1 < 0\_s*' ..
' return "maybe"\_s*' ..
'endif\_s*' ..
'if g:cond\_s*' ..
'0 LOADG g:cond\_s*' ..
'1 COND2BOOL\_s*' ..
'2 JUMP_IF_FALSE -> 5\_s*' ..
'return "yes"\_s*' ..
'3 PUSHS "yes"\_s*' ..
'4 RETURN\_s*' ..
'else\_s*' ..
' return "no"\_s*' ..
'5 PUSHS "no"\_s*' ..
'6 RETURN$',
instr)
enddef
def WithFunc()
var Funky1: func
var Funky2: func = function("len")
var Party2: func = funcref("UserFunc")
enddef
def Test_disassemble_function()
var instr = execute('disassemble WithFunc')
assert_match('WithFunc\_s*' ..
'var Funky1: func\_s*' ..
'0 PUSHFUNC "\[none]"\_s*' ..
'1 STORE $0\_s*' ..
'var Funky2: func = function("len")\_s*' ..
'2 PUSHS "len"\_s*' ..
'3 BCALL function(argc 1)\_s*' ..
'4 STORE $1\_s*' ..
'var Party2: func = funcref("UserFunc")\_s*' ..
'\d PUSHS "UserFunc"\_s*' ..
'\d BCALL funcref(argc 1)\_s*' ..
'\d STORE $2\_s*' ..
'\d RETURN void',
instr)
enddef
if has('channel')
def WithChannel()
var job1: job
var job2: job = job_start("donothing")
var chan1: channel
enddef
endif
def Test_disassemble_channel()
CheckFeature channel
var instr = execute('disassemble WithChannel')
assert_match('WithChannel\_s*' ..
'var job1: job\_s*' ..
'\d PUSHJOB "no process"\_s*' ..
'\d STORE $0\_s*' ..
'var job2: job = job_start("donothing")\_s*' ..
'\d PUSHS "donothing"\_s*' ..
'\d BCALL job_start(argc 1)\_s*' ..
'\d STORE $1\_s*' ..
'var chan1: channel\_s*' ..
'\d PUSHCHANNEL 0\_s*' ..
'\d STORE $2\_s*' ..
'\d RETURN void',
instr)
enddef
def s:WithLambda(): string
var F = (a) => "X" .. a .. "X"
return F("x")
enddef
def Test_disassemble_lambda()
assert_equal("XxX", WithLambda())
var instr = execute('disassemble WithLambda')
assert_match('WithLambda\_s*' ..
'var F = (a) => "X" .. a .. "X"\_s*' ..
'\d FUNCREF <lambda>\d\+\_s*' ..
'\d STORE $0\_s*' ..
'return F("x")\_s*' ..
'\d PUSHS "x"\_s*' ..
'\d LOAD $0\_s*' ..
'\d PCALL (argc 1)\_s*' ..
'\d RETURN',
instr)
var name = substitute(instr, '.*\(<lambda>\d\+\).*', '\1', '')
instr = execute('disassemble ' .. name)
assert_match('<lambda>\d\+\_s*' ..
'return "X" .. a .. "X"\_s*' ..
'\d PUSHS "X"\_s*' ..
'\d LOAD arg\[-1\]\_s*' ..
'\d 2STRING_ANY stack\[-1\]\_s*' ..
'\d CONCAT size 2\_s*' ..
'\d PUSHS "X"\_s*' ..
'\d CONCAT size 2\_s*' ..
'\d RETURN',
instr)
enddef
def s:LambdaWithType(): number
var Ref = (a: number) => a + 10
return Ref(g:value)
enddef
def Test_disassemble_lambda_with_type()
g:value = 5
assert_equal(15, LambdaWithType())
var instr = execute('disassemble LambdaWithType')
assert_match('LambdaWithType\_s*' ..
'var Ref = (a: number) => a + 10\_s*' ..
'\d FUNCREF <lambda>\d\+\_s*' ..
'\d STORE $0\_s*' ..
'return Ref(g:value)\_s*' ..
'\d LOADG g:value\_s*' ..
'\d LOAD $0\_s*' ..
'\d CHECKTYPE number stack\[-2\] arg 1\_s*' ..
'\d PCALL (argc 1)\_s*' ..
'\d RETURN',
instr)
enddef
def NestedOuter()
def g:Inner()
echomsg "inner"
enddef
enddef
def Test_disassemble_nested_func()
var instr = execute('disassemble NestedOuter')
assert_match('NestedOuter\_s*' ..
'def g:Inner()\_s*' ..
'echomsg "inner"\_s*' ..
'enddef\_s*' ..
'\d NEWFUNC <lambda>\d\+ Inner\_s*' ..
'\d RETURN void',
instr)
enddef
def NestedDefList()
def
def Info
def /Info
def /Info/
enddef
def Test_disassemble_nested_def_list()
var instr = execute('disassemble NestedDefList')
assert_match('NestedDefList\_s*' ..
'def\_s*' ..
'\d DEF \_s*' ..
'def Info\_s*' ..
'\d DEF Info\_s*' ..
'def /Info\_s*' ..
'\d DEF /Info\_s*' ..
'def /Info/\_s*' ..
'\d DEF /Info/\_s*' ..
'\d RETURN void',
instr)
enddef
def s:AndOr(arg: any): string
if arg == 1 && arg != 2 || arg == 4
return 'yes'
endif
return 'no'
enddef
def Test_disassemble_and_or()
assert_equal("yes", AndOr(1))
assert_equal("no", AndOr(2))
assert_equal("yes", AndOr(4))
var instr = execute('disassemble AndOr')
assert_match('AndOr\_s*' ..
'if arg == 1 && arg != 2 || arg == 4\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d COMPAREANY ==\_s*' ..
'\d JUMP_IF_COND_FALSE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d COMPAREANY !=\_s*' ..
'\d JUMP_IF_COND_TRUE -> \d\+\_s*' ..
'\d LOAD arg\[-1]\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ COMPAREANY ==\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+',
instr)
enddef
def s:AndConstant(arg: any): string
if true && arg
return "yes"
endif
if false && arg
return "never"
endif
return "no"
enddef
def Test_disassemble_and_constant()
assert_equal("yes", AndConstant(1))
assert_equal("no", AndConstant(false))
var instr = execute('disassemble AndConstant')
assert_match('AndConstant\_s*' ..
'if true && arg\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 COND2BOOL\_s*' ..
'2 JUMP_IF_FALSE -> 5\_s*' ..
'return "yes"\_s*' ..
'3 PUSHS "yes"\_s*' ..
'4 RETURN\_s*' ..
'endif\_s*' ..
'if false && arg\_s*' ..
'return "never"\_s*' ..
'endif\_s*' ..
'return "no"\_s*' ..
'5 PUSHS "no"\_s*' ..
'6 RETURN',
instr)
enddef
def s:ForLoop(): list<number>
var res: list<number>
for i in range(3)
res->add(i)
endfor
return res
enddef
def Test_disassemble_for_loop()
assert_equal([0, 1, 2], ForLoop())
var instr = execute('disassemble ForLoop')
assert_match('ForLoop\_s*' ..
'var res: list<number>\_s*' ..
'\d NEWLIST size 0\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'for i in range(3)\_s*' ..
'\d STORE -1 in $1\_s*' ..
'\d PUSHNR 3\_s*' ..
'\d BCALL range(argc 1)\_s*' ..
'\d FOR $1 -> \d\+\_s*' ..
'\d STORE $3\_s*' ..
'res->add(i)\_s*' ..
'\d LOAD $0\_s*' ..
'\d LOAD $3\_s*' ..
'\d\+ LISTAPPEND\_s*' ..
'\d\+ DROP\_s*' ..
'endfor\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'\d\+ DROP',
instr)
enddef
def s:ForLoopEval(): string
var res = ""
for str in eval('["one", "two"]')
res ..= str
endfor
return res
enddef
def Test_disassemble_for_loop_eval()
assert_equal('onetwo', ForLoopEval())
var instr = execute('disassemble ForLoopEval')
assert_match('ForLoopEval\_s*' ..
'var res = ""\_s*' ..
'\d PUSHS ""\_s*' ..
'\d STORE $0\_s*' ..
'for str in eval(''\["one", "two"\]'')\_s*' ..
'\d STORE -1 in $1\_s*' ..
'\d PUSHS "\["one", "two"\]"\_s*' ..
'\d BCALL eval(argc 1)\_s*' ..
'\d FOR $1 -> \d\+\_s*' ..
'\d STORE $3\_s*' ..
'res ..= str\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ LOAD $3\_s*' ..
'\d 2STRING_ANY stack\[-1\]\_s*' ..
'\d\+ CONCAT size 2\_s*' ..
'\d\+ STORE $0\_s*' ..
'endfor\_s*' ..
'\d\+ JUMP -> 5\_s*' ..
'\d\+ DROP\_s*' ..
'return res\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ RETURN',
instr)
enddef
def s:ForLoopUnpack()
for [x1, x2] in [[1, 2], [3, 4]]
echo x1 x2
endfor
enddef
def Test_disassemble_for_loop_unpack()
var instr = execute('disassemble ForLoopUnpack')
assert_match('ForLoopUnpack\_s*' ..
'for \[x1, x2\] in \[\[1, 2\], \[3, 4\]\]\_s*' ..
'\d\+ STORE -1 in $0\_s*' ..
'\d\+ PUSHNR 1\_s*' ..
'\d\+ PUSHNR 2\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ PUSHNR 3\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ FOR $0 -> 16\_s*' ..
'\d\+ UNPACK 2\_s*' ..
'\d\+ STORE $2\_s*' ..
'\d\+ STORE $3\_s*' ..
'echo x1 x2\_s*' ..
'\d\+ LOAD $2\_s*' ..
'\d\+ LOAD $3\_s*' ..
'\d\+ ECHO 2\_s*' ..
'endfor\_s*' ..
'\d\+ JUMP -> 8\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
instr)
enddef
def s:ForLoopContinue()
for nr in [1, 2]
try
echo "ok"
try
echo "deeper"
catch
continue
endtry
catch
echo "not ok"
endtry
endfor
enddef
def Test_disassemble_for_loop_continue()
var instr = execute('disassemble ForLoopContinue')
assert_match('ForLoopContinue\_s*' ..
'for nr in \[1, 2]\_s*' ..
'0 STORE -1 in $0\_s*' ..
'1 PUSHNR 1\_s*' ..
'2 PUSHNR 2\_s*' ..
'3 NEWLIST size 2\_s*' ..
'4 FOR $0 -> 22\_s*' ..
'5 STORE $2\_s*' ..
'try\_s*' ..
'6 TRY catch -> 17, endtry -> 20\_s*' ..
'echo "ok"\_s*' ..
'7 PUSHS "ok"\_s*' ..
'8 ECHO 1\_s*' ..
'try\_s*' ..
'9 TRY catch -> 13, endtry -> 15\_s*' ..
'echo "deeper"\_s*' ..
'10 PUSHS "deeper"\_s*' ..
'11 ECHO 1\_s*' ..
'catch\_s*' ..
'12 JUMP -> 15\_s*' ..
'13 CATCH\_s*' ..
'continue\_s*' ..
'14 TRY-CONTINUE 2 levels -> 4\_s*' ..
'endtry\_s*' ..
'15 ENDTRY\_s*' ..
'catch\_s*' ..
'16 JUMP -> 20\_s*' ..
'17 CATCH\_s*' ..
'echo "not ok"\_s*' ..
'18 PUSHS "not ok"\_s*' ..
'19 ECHO 1\_s*' ..
'endtry\_s*' ..
'20 ENDTRY\_s*' ..
'endfor\_s*' ..
'21 JUMP -> 4\_s*' ..
'\d\+ DROP\_s*' ..
'\d\+ RETURN void',
instr)
enddef
let g:number = 42
def s:TypeCast()
var l: list<number> = [23, <number>g:number]
enddef
def Test_disassemble_typecast()
var instr = execute('disassemble TypeCast')
assert_match('TypeCast.*' ..
'var l: list<number> = \[23, <number>g:number\].*' ..
'\d PUSHNR 23\_s*' ..
'\d LOADG g:number\_s*' ..
'\d CHECKTYPE number stack\[-1\]\_s*' ..
'\d NEWLIST size 2\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'\d RETURN void\_s*',
instr)
enddef
def Test_disassemble_object_cast()
# Downcasting.
var lines =<< trim END
vim9script
class A
endclass
class B extends A
var mylen: number
endclass
def F(o: A): number
return (<B>o).mylen
enddef
g:instr = execute('disassemble F')
END
v9.CheckScriptSuccess(lines)
assert_match('\<SNR>\d*_F\_s*' ..
'return (<B>o).mylen\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 CHECKTYPE object<B> stack\[-1\]\_s*' ..
'2 OBJ_MEMBER 0\_s*' ..
'3 RETURN\_s*',
g:instr)
# Upcasting.
lines =<< trim END
vim9script
class A
var mylen: number
endclass
class B extends A
endclass
def F(o: B): number
return (<A>o).mylen
enddef
g:instr = execute('disassemble F')
END
v9.CheckScriptSuccess(lines)
assert_match('\<SNR>\d*_F\_s*' ..
'return (<A>o).mylen\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 OBJ_MEMBER 0\_s*' ..
'2 RETURN\_s*',
g:instr)
# Casting, type is not statically known.
lines =<< trim END
vim9script
class A
endclass
class B extends A
endclass
def F(o: any): any
return <A>o
enddef
g:instr = execute('disassemble F')
END
v9.CheckScriptSuccess(lines)
assert_match('\<SNR>\d*_F\_s*' ..
'return <A>o\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 CHECKTYPE object<A> stack\[-1\]\_s*' ..
'2 RETURN\_s*',
g:instr)
enddef
def s:Computing()
var nr = 3
var nrres = nr + 7
nrres = nr - 7
nrres = nr * 7
nrres = nr / 7
nrres = nr % 7
var anyres = g:number + 7
anyres = g:number - 7
anyres = g:number * 7
anyres = g:number / 7
anyres = g:number % 7
var fl = 3.0
var flres = fl + 7.0
flres = fl - 7.0
flres = fl * 7.0
flres = fl / 7.0
enddef
def Test_disassemble_computing()
var instr = execute('disassemble Computing')
assert_match('Computing.*' ..
'var nr = 3.*' ..
'\d STORE 3 in $0.*' ..
'var nrres = nr + 7.*' ..
'\d LOAD $0.*' ..
'\d PUSHNR 7.*' ..
'\d OPNR +.*' ..
'\d STORE $1.*' ..
'nrres = nr - 7.*' ..
'\d OPNR -.*' ..
'nrres = nr \* 7.*' ..
'\d OPNR \*.*' ..
'nrres = nr / 7.*' ..
'\d OPNR /.*' ..
'nrres = nr % 7.*' ..
'\d OPNR %.*' ..
'var anyres = g:number + 7.*' ..
'\d LOADG g:number.*' ..
'\d PUSHNR 7.*' ..
'\d OPANY +.*' ..
'\d STORE $2.*' ..
'anyres = g:number - 7.*' ..
'\d OPANY -.*' ..
'anyres = g:number \* 7.*' ..
'\d OPANY \*.*' ..
'anyres = g:number / 7.*' ..
'\d OPANY /.*' ..
'anyres = g:number % 7.*' ..
'\d OPANY %.*',
instr)
assert_match('Computing.*' ..
'var fl = 3.0.*' ..
'\d PUSHF 3.0.*' ..
'\d STORE $3.*' ..
'var flres = fl + 7.0.*' ..
'\d LOAD $3.*' ..
'\d PUSHF 7.0.*' ..
'\d OPFLOAT +.*' ..
'\d STORE $4.*' ..
'flres = fl - 7.0.*' ..
'\d OPFLOAT -.*' ..
'flres = fl \* 7.0.*' ..
'\d OPFLOAT \*.*' ..
'flres = fl / 7.0.*' ..
'\d OPFLOAT /.*',
instr)
enddef
def s:AddListBlob()
var reslist = [1, 2] + [3, 4]
var resblob = 0z1122 + 0z3344
enddef
def Test_disassemble_add_list_blob()
var instr = execute('disassemble AddListBlob')
assert_match('AddListBlob.*' ..
'var reslist = \[1, 2] + \[3, 4].*' ..
'\d PUSHNR 1.*' ..
'\d PUSHNR 2.*' ..
'\d NEWLIST size 2.*' ..
'\d PUSHNR 3.*' ..
'\d PUSHNR 4.*' ..
'\d NEWLIST size 2.*' ..
'\d ADDLIST.*' ..
'\d STORE $.*.*' ..
'var resblob = 0z1122 + 0z3344.*' ..
'\d PUSHBLOB 0z1122.*' ..
'\d PUSHBLOB 0z3344.*' ..
'\d ADDBLOB.*' ..
'\d STORE $.*',
instr)
enddef
let g:aa = 'aa'
def s:ConcatString(): string
var res = g:aa .. "bb"
return res
enddef
def Test_disassemble_concat()
var instr = execute('disassemble ConcatString')
assert_match('ConcatString.*' ..
'var res = g:aa .. "bb".*' ..
'\d LOADG g:aa.*' ..
'\d PUSHS "bb".*' ..
'\d 2STRING_ANY stack\[-2].*' ..
'\d CONCAT.*' ..
'\d STORE $.*',
instr)
assert_equal('aabb', ConcatString())
enddef
def s:StringIndex(): string
var s = "abcd"
var res = s[1]
return res
enddef
def Test_disassemble_string_index()
var instr = execute('disassemble StringIndex')
assert_match('StringIndex\_s*' ..
'var s = "abcd"\_s*' ..
'\d PUSHS "abcd"\_s*' ..
'\d STORE $0\_s*' ..
'var res = s\[1]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d STRINDEX\_s*' ..
'\d STORE $1\_s*',
instr)
assert_equal('b', StringIndex())
enddef
def s:StringSlice(): string
var s = "abcd"
var res = s[1 : 8]
return res
enddef
def Test_disassemble_string_slice()
var instr = execute('disassemble StringSlice')
assert_match('StringSlice\_s*' ..
'var s = "abcd"\_s*' ..
'\d PUSHS "abcd"\_s*' ..
'\d STORE $0\_s*' ..
'var res = s\[1 : 8]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 8\_s*' ..
'\d STRSLICE\_s*' ..
'\d STORE $1\_s*',
instr)
assert_equal('bcd', StringSlice())
enddef
def s:ListIndex(): number
var l = [1, 2, 3]
var res = l[1]
return res
enddef
def Test_disassemble_list_index()
var instr = execute('disassemble ListIndex')
assert_match('ListIndex\_s*' ..
'var l = \[1, 2, 3]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d PUSHNR 3\_s*' ..
'\d NEWLIST size 3\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'var res = l\[1]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d LISTINDEX\_s*' ..
'\d STORE $1\_s*',
instr)
assert_equal(2, ListIndex())
enddef
def s:ListSlice(): list<number>
var l = [1, 2, 3]
var res = l[1 : 8]
return res
enddef
def Test_disassemble_list_slice()
var instr = execute('disassemble ListSlice')
assert_match('ListSlice\_s*' ..
'var l = \[1, 2, 3]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d PUSHNR 3\_s*' ..
'\d NEWLIST size 3\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'var res = l\[1 : 8]\_s*' ..
'\d LOAD $0\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 8\_s*' ..
'\d\+ LISTSLICE\_s*' ..
'\d\+ SETTYPE list<number>\_s*' ..
'\d\+ STORE $1\_s*',
instr)
assert_equal([2, 3], ListSlice())
enddef
def s:DictMember(): number
var d = {item: 1}
var res = d.item
res = d["item"]
return res
enddef
def Test_disassemble_dict_member()
var instr = execute('disassemble DictMember')
assert_match('DictMember\_s*' ..
'var d = {item: 1}\_s*' ..
'\d PUSHS "item"\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d NEWDICT size 1\_s*' ..
'\d SETTYPE dict<number>\_s*' ..
'\d STORE $0\_s*' ..
'var res = d.item\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ MEMBER item\_s*' ..
'\d\+ USEDICT\_s*' ..
'\d\+ STORE $1\_s*' ..
'res = d\["item"\]\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ PUSHS "item"\_s*' ..
'\d\+ MEMBER\_s*' ..
'\d\+ USEDICT\_s*' ..
'\d\+ STORE $1\_s*',
instr)
assert_equal(1, DictMember())
enddef
let somelist = [1, 2, 3, 4, 5]
def s:AnyIndex(): number
var res = g:somelist[2]
return res
enddef
def Test_disassemble_any_index()
var instr = execute('disassemble AnyIndex')
assert_match('AnyIndex\_s*' ..
'var res = g:somelist\[2\]\_s*' ..
'\d LOADG g:somelist\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d ANYINDEX\_s*' ..
'\d STORE $0\_s*' ..
'return res\_s*' ..
'\d LOAD $0\_s*' ..
'\d CHECKTYPE number stack\[-1\]\_s*' ..
'\d RETURN',
instr)
assert_equal(3, AnyIndex())
enddef
def s:AnySlice(): list<number>
var res = g:somelist[1 : 3]
return res
enddef
def Test_disassemble_any_slice()
var instr = execute('disassemble AnySlice')
assert_match('AnySlice\_s*' ..
'var res = g:somelist\[1 : 3\]\_s*' ..
'\d LOADG g:somelist\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 3\_s*' ..
'\d ANYSLICE\_s*' ..
'\d STORE $0\_s*' ..
'return res\_s*' ..
'\d LOAD $0\_s*' ..
'\d CHECKTYPE list<number> stack\[-1\]\_s*' ..
'\d RETURN',
instr)
assert_equal([2, 3, 4], AnySlice())
enddef
def s:NegateNumber(): number
g:nr = 9
var plus = +g:nr
var minus = -g:nr
return minus
enddef
def Test_disassemble_negate_number()
var instr = execute('disassemble NegateNumber')
assert_match('NegateNumber\_s*' ..
'g:nr = 9\_s*' ..
'\d PUSHNR 9\_s*' ..
'\d STOREG g:nr\_s*' ..
'var plus = +g:nr\_s*' ..
'\d LOADG g:nr\_s*' ..
'\d CHECKTYPE number stack\[-1\]\_s*' ..
'\d STORE $0\_s*' ..
'var minus = -g:nr\_s*' ..
'\d LOADG g:nr\_s*' ..
'\d CHECKTYPE number stack\[-1\]\_s*' ..
'\d NEGATENR\_s*' ..
'\d STORE $1\_s*',
instr)
assert_equal(-9, NegateNumber())
enddef
def s:InvertBool(): bool
var flag = true
var invert = !flag
var res = !!flag
return res
enddef
def Test_disassemble_invert_bool()
var instr = execute('disassemble InvertBool')
assert_match('InvertBool\_s*' ..
'var flag = true\_s*' ..
'\d PUSH true\_s*' ..
'\d STORE $0\_s*' ..
'var invert = !flag\_s*' ..
'\d LOAD $0\_s*' ..
'\d INVERT -1 (!val)\_s*' ..
'\d STORE $1\_s*' ..
'var res = !!flag\_s*' ..
'\d LOAD $0\_s*' ..
'\d 2BOOL -1 (!!val)\_s*' ..
'\d STORE $2\_s*',
instr)
assert_equal(true, InvertBool())
enddef
def s:ReturnBool(): bool
var one = 1
var zero = 0
var none: number
var name: bool = one && zero || one
return name
enddef
def Test_disassemble_return_bool()
var instr = execute('disassemble ReturnBool')
assert_match('ReturnBool\_s*' ..
'var one = 1\_s*' ..
'0 STORE 1 in $0\_s*' ..
'var zero = 0\_s*' ..
'var none: number\_s*' ..
'var name: bool = one && zero || one\_s*' ..
'1 LOAD $0\_s*' ..
'2 COND2BOOL\_s*' ..
'3 JUMP_IF_COND_FALSE -> 6\_s*' ..
'4 LOAD $1\_s*' ..
'5 COND2BOOL\_s*' ..
'6 JUMP_IF_COND_TRUE -> 9\_s*' ..
'7 LOAD $0\_s*' ..
'8 COND2BOOL\_s*' ..
'9 STORE $3\_s*' ..
'return name\_s*' ..
'\d\+ LOAD $3\_s*' ..
'\d\+ RETURN',
instr)
assert_equal(true, InvertBool())
enddef
def s:AutoInit()
var t: number
t = 1
t = 0
enddef
def Test_disassemble_auto_init()
var instr = execute('disassemble AutoInit')
assert_match('AutoInit\_s*' ..
'var t: number\_s*' ..
't = 1\_s*' ..
'\d STORE 1 in $0\_s*' ..
't = 0\_s*' ..
'\d STORE 0 in $0\_s*' ..
'\d\+ RETURN void',
instr)
enddef
def Test_disassemble_compare()
var cases = [
['true == isFalse', 'COMPAREBOOL =='],
['true != isFalse', 'COMPAREBOOL !='],
['v:none == isNull', 'COMPARESPECIAL =='],
['v:none != isNull', 'COMPARESPECIAL !='],
['"text" == isNull', 'COMPARENULL =='],
['"text" != isNull', 'COMPARENULL !='],
['111 == aNumber', 'COMPARENR =='],
['111 != aNumber', 'COMPARENR !='],
['111 > aNumber', 'COMPARENR >'],
['111 < aNumber', 'COMPARENR <'],
['111 >= aNumber', 'COMPARENR >='],
['111 <= aNumber', 'COMPARENR <='],
['111 =~ aNumber', 'COMPARENR =\~'],
['111 !~ aNumber', 'COMPARENR !\~'],
['"xx" != aString', 'COMPARESTRING !='],
['"xx" > aString', 'COMPARESTRING >'],
['"xx" < aString', 'COMPARESTRING <'],
['"xx" >= aString', 'COMPARESTRING >='],
['"xx" <= aString', 'COMPARESTRING <='],
['"xx" =~ aString', 'COMPARESTRING =\~'],
['"xx" !~ aString', 'COMPARESTRING !\~'],
['"xx" is aString', 'COMPARESTRING is'],
['"xx" isnot aString', 'COMPARESTRING isnot'],
['0z11 == aBlob', 'COMPAREBLOB =='],
['0z11 != aBlob', 'COMPAREBLOB !='],
['0z11 is aBlob', 'COMPAREBLOB is'],
['0z11 isnot aBlob', 'COMPAREBLOB isnot'],
['[1, 2] == aList', 'COMPARELIST =='],
['[1, 2] != aList', 'COMPARELIST !='],
['[1, 2] is aList', 'COMPARELIST is'],
['[1, 2] isnot aList', 'COMPARELIST isnot'],
['{a: 1} == aDict', 'COMPAREDICT =='],
['{a: 1} != aDict', 'COMPAREDICT !='],
['{a: 1} is aDict', 'COMPAREDICT is'],
['{a: 1} isnot aDict', 'COMPAREDICT isnot'],
['(() => 33) == (() => 44)', 'COMPAREFUNC =='],
['(() => 33) != (() => 44)', 'COMPAREFUNC !='],
['(() => 33) is (() => 44)', 'COMPAREFUNC is'],
['(() => 33) isnot (() => 44)', 'COMPAREFUNC isnot'],
['77 == g:xx', 'COMPAREANY =='],
['77 != g:xx', 'COMPAREANY !='],
['77 > g:xx', 'COMPAREANY >'],
['77 < g:xx', 'COMPAREANY <'],
['77 >= g:xx', 'COMPAREANY >='],
['77 <= g:xx', 'COMPAREANY <='],
['77 =~ g:xx', 'COMPAREANY =\~'],
['77 !~ g:xx', 'COMPAREANY !\~'],
['77 is g:xx', 'COMPAREANY is'],
['77 isnot g:xx', 'COMPAREANY isnot'],
]
var floatDecl = ''
cases->extend([
['1.1 == aFloat', 'COMPAREFLOAT =='],
['1.1 != aFloat', 'COMPAREFLOAT !='],
['1.1 > aFloat', 'COMPAREFLOAT >'],
['1.1 < aFloat', 'COMPAREFLOAT <'],
['1.1 >= aFloat', 'COMPAREFLOAT >='],
['1.1 <= aFloat', 'COMPAREFLOAT <='],
['1.1 =~ aFloat', 'COMPAREFLOAT =\~'],
['1.1 !~ aFloat', 'COMPAREFLOAT !\~'],
])
floatDecl = 'var aFloat = 2.2'
var nr = 1
for case in cases
# declare local variables to get a non-constant with the right type
writefile(['def TestCase' .. nr .. '()',
' var isFalse = false',
' var isNull = v:null',
' var aNumber = 222',
' var aString = "yy"',
' var aBlob = 0z22',
' var aList = [3, 4]',
' var aDict = {x: 2}',
floatDecl,
' if ' .. case[0],
' echo 42',
' endif',
'enddef'], 'Xdisassemble')
source Xdisassemble
var instr = execute('disassemble TestCase' .. nr)
assert_match('TestCase' .. nr .. '.*' ..
'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' ..
'\d \(PUSH\|FUNCREF\).*' ..
'\d \(PUSH\|FUNCREF\|LOAD\).*' ..
'\d ' .. case[1] .. '.*' ..
'\d JUMP_IF_FALSE -> \d\+.*',
instr)
nr += 1
endfor
delete('Xdisassemble')
enddef
def s:FalsyOp()
echo g:flag ?? "yes"
echo [] ?? "empty list"
echo "" ?? "empty string"
enddef
def Test_disassemble_falsy_op()
var res = execute('disass s:FalsyOp')
assert_match('\<SNR>\d*_FalsyOp\_s*' ..
'echo g:flag ?? "yes"\_s*' ..
'0 LOADG g:flag\_s*' ..
'1 JUMP_AND_KEEP_IF_TRUE -> 3\_s*' ..
'2 PUSHS "yes"\_s*' ..
'3 ECHO 1\_s*' ..
'echo \[\] ?? "empty list"\_s*' ..
'4 NEWLIST size 0\_s*' ..
'5 JUMP_AND_KEEP_IF_TRUE -> 7\_s*' ..
'6 PUSHS "empty list"\_s*' ..
'7 ECHO 1\_s*' ..
'echo "" ?? "empty string"\_s*' ..
'\d\+ PUSHS "empty string"\_s*' ..
'\d\+ ECHO 1\_s*' ..
'\d\+ RETURN void',
res)
enddef
def Test_disassemble_compare_const()
var cases = [
['"xx" == "yy"', false],
['"aa" == "aa"', true],
['has("eval") ? true : false', true],
['has("asdf") ? true : false', false],
]
var nr = 1
for case in cases
writefile(['def TestCase' .. nr .. '()',
' if ' .. case[0],
' echo 42',
' endif',
'enddef'], 'Xdisassemble')
source Xdisassemble
var instr = execute('disassemble TestCase' .. nr)
if case[1]
# condition true, "echo 42" executed
assert_match('TestCase' .. nr .. '.*' ..
'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' ..
'\d PUSHNR 42.*' ..
'\d ECHO 1.*' ..
'\d RETURN void',
instr)
else
# condition false, function just returns
assert_match('TestCase' .. nr .. '.*' ..
'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '[ \n]*' ..
'echo 42[ \n]*' ..
'endif[ \n]*' ..
'\d RETURN void',
instr)
endif
nr += 1
endfor
delete('Xdisassemble')
enddef
def s:Execute()
execute 'help vim9.txt'
var cmd = 'help vim9.txt'
execute cmd
var tag = 'vim9.txt'
execute 'help ' .. tag
enddef
def Test_disassemble_execute()
var res = execute('disass s:Execute')
assert_match('\<SNR>\d*_Execute\_s*' ..
"execute 'help vim9.txt'\\_s*" ..
'\d PUSHS "help vim9.txt"\_s*' ..
'\d EXECUTE 1\_s*' ..
"var cmd = 'help vim9.txt'\\_s*" ..
'\d PUSHS "help vim9.txt"\_s*' ..
'\d STORE $0\_s*' ..
'execute cmd\_s*' ..
'\d LOAD $0\_s*' ..
'\d EXECUTE 1\_s*' ..
"var tag = 'vim9.txt'\\_s*" ..
'\d PUSHS "vim9.txt"\_s*' ..
'\d STORE $1\_s*' ..
"execute 'help ' .. tag\\_s*" ..
'\d\+ PUSHS "help "\_s*' ..
'\d\+ LOAD $1\_s*' ..
'\d\+ CONCAT size 2\_s*' ..
'\d\+ EXECUTE 1\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:OnlyRange()
:$
:123
:'m
enddef
def Test_disassemble_range_only()
var res = execute('disass s:OnlyRange')
assert_match('\<SNR>\d*_OnlyRange\_s*' ..
':$\_s*' ..
'\d EXECRANGE $\_s*' ..
':123\_s*' ..
'\d EXECRANGE 123\_s*' ..
':''m\_s*' ..
'\d EXECRANGE ''m\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:StoreRange()
var l = [1, 2]
l[0 : 1] = [7, 8]
enddef
def Test_disassemble_store_range()
var res = execute('disass s:StoreRange')
assert_match('\<SNR>\d*_StoreRange\_s*' ..
'var l = \[1, 2]\_s*' ..
'\d PUSHNR 1\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d NEWLIST size 2\_s*' ..
'\d SETTYPE list<number>\_s*' ..
'\d STORE $0\_s*' ..
'l\[0 : 1] = \[7, 8]\_s*' ..
'\d\+ PUSHNR 7\_s*' ..
'\d\+ PUSHNR 8\_s*' ..
'\d\+ NEWLIST size 2\_s*' ..
'\d\+ PUSHNR 0\_s*' ..
'\d\+ PUSHNR 1\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ STORERANGE\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:Echomsg()
echomsg 'some' 'message'
echoconsole 'nothing'
echoerr 'went' .. 'wrong'
var local = 'window'
echowin 'in' local
:5echowin 'five'
enddef
def Test_disassemble_echomsg()
var res = execute('disass s:Echomsg')
assert_match('\<SNR>\d*_Echomsg\_s*' ..
"echomsg 'some' 'message'\\_s*" ..
'\d PUSHS "some"\_s*' ..
'\d PUSHS "message"\_s*' ..
'\d ECHOMSG 2\_s*' ..
"echoconsole 'nothing'\\_s*" ..
'\d PUSHS "nothing"\_s*' ..
'\d ECHOCONSOLE 1\_s*' ..
"echoerr 'went' .. 'wrong'\\_s*" ..
'\d PUSHS "wentwrong"\_s*' ..
'\d ECHOERR 1\_s*' ..
"var local = 'window'\\_s*" ..
'\d\+ PUSHS "window"\_s*' ..
'\d\+ STORE $0\_s*' ..
"echowin 'in' local\\_s*" ..
'\d\+ PUSHS "in"\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ ECHOWINDOW 2\_s*' ..
":5echowin 'five'\\_s*" ..
'\d\+ PUSHS "five"\_s*' ..
'\d\+ ECHOWINDOW 1 (5 sec)\_s*' ..
'\d\+ RETURN void',
res)
enddef
def SomeStringArg(arg: string)
echo arg
enddef
def SomeAnyArg(arg: any)
echo arg
enddef
def SomeStringArgAndReturn(arg: string): string
return arg
enddef
def Test_display_func()
var res1 = execute('function SomeStringArg')
assert_match('.* def SomeStringArg(arg: string)\_s*' ..
'\d *echo arg.*' ..
' *enddef',
res1)
var res2 = execute('function SomeAnyArg')
assert_match('.* def SomeAnyArg(arg: any)\_s*' ..
'\d *echo arg\_s*' ..
' *enddef',
res2)
var res3 = execute('function SomeStringArgAndReturn')
assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' ..
'\d *return arg\_s*' ..
' *enddef',
res3)
enddef
def Test_vim9script_forward_func()
var lines =<< trim END
vim9script
def FuncOne(): string
return FuncTwo()
enddef
def FuncTwo(): string
return 'two'
enddef
g:res_FuncOne = execute('disass FuncOne')
END
writefile(lines, 'Xdisassemble', 'D')
source Xdisassemble
# check that the first function calls the second with DCALL
assert_match('\<SNR>\d*_FuncOne\_s*' ..
'return FuncTwo()\_s*' ..
'\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' ..
'\d RETURN',
g:res_FuncOne)
unlet g:res_FuncOne
enddef
def s:ConcatStrings(): string
return 'one' .. 'two' .. 'three'
enddef
def s:ComputeConst(): number
return 2 + 3 * 4 / 6 + 7
enddef
def s:ComputeConstParen(): number
return ((2 + 4) * (8 / 2)) / (3 + 4)
enddef
def Test_simplify_const_expr()
var res = execute('disass s:ConcatStrings')
assert_match('<SNR>\d*_ConcatStrings\_s*' ..
"return 'one' .. 'two' .. 'three'\\_s*" ..
'\d PUSHS "onetwothree"\_s*' ..
'\d RETURN',
res)
res = execute('disass s:ComputeConst')
assert_match('<SNR>\d*_ComputeConst\_s*' ..
'return 2 + 3 \* 4 / 6 + 7\_s*' ..
'\d PUSHNR 11\_s*' ..
'\d RETURN',
res)
res = execute('disass s:ComputeConstParen')
assert_match('<SNR>\d*_ComputeConstParen\_s*' ..
'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' ..
'\d PUSHNR 3\>\_s*' ..
'\d RETURN',
res)
enddef
def s:CallAppend()
eval "some text"->append(2)
enddef
def Test_shuffle()
var res = execute('disass s:CallAppend')
assert_match('<SNR>\d*_CallAppend\_s*' ..
'eval "some text"->append(2)\_s*' ..
'\d PUSHS "some text"\_s*' ..
'\d PUSHNR 2\_s*' ..
'\d SHUFFLE 2 up 1\_s*' ..
'\d BCALL append(argc 2)\_s*' ..
'\d DROP\_s*' ..
'\d RETURN void',
res)
enddef
def s:SilentMessage()
silent echomsg "text"
silent! echoerr "error"
enddef
def Test_silent()
var res = execute('disass s:SilentMessage')
assert_match('<SNR>\d*_SilentMessage\_s*' ..
'silent echomsg "text"\_s*' ..
'\d CMDMOD silent\_s*' ..
'\d PUSHS "text"\_s*' ..
'\d ECHOMSG 1\_s*' ..
'\d CMDMOD_REV\_s*' ..
'silent! echoerr "error"\_s*' ..
'\d CMDMOD silent!\_s*' ..
'\d PUSHS "error"\_s*' ..
'\d ECHOERR 1\_s*' ..
'\d CMDMOD_REV\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:SilentIf()
silent if 4 == g:five
silent elseif 4 == g:five
endif
enddef
def Test_silent_if()
var res = execute('disass s:SilentIf')
assert_match('<SNR>\d*_SilentIf\_s*' ..
'silent if 4 == g:five\_s*' ..
'\d\+ CMDMOD silent\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ LOADG g:five\_s*' ..
'\d\+ COMPAREANY ==\_s*' ..
'\d\+ CMDMOD_REV\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+\_s*' ..
'silent elseif 4 == g:five\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
'\d\+ CMDMOD silent\_s*' ..
'\d\+ PUSHNR 4\_s*' ..
'\d\+ LOADG g:five\_s*' ..
'\d\+ COMPAREANY ==\_s*' ..
'\d\+ CMDMOD_REV\_s*' ..
'\d\+ JUMP_IF_FALSE -> \d\+\_s*' ..
'endif\_s*' ..
'\d\+ RETURN void',
res)
enddef
def s:SilentFor()
silent for i in [0]
endfor
enddef
def Test_silent_for()
var res = execute('disass s:SilentFor')
assert_match('<SNR>\d*_SilentFor\_s*' ..
'silent for i in \[0\]\_s*' ..
'\d CMDMOD silent\_s*' ..
'\d STORE -1 in $0\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d NEWLIST size 1\_s*' ..
'\d CMDMOD_REV\_s*' ..
'5 FOR $0 -> 8\_s*' ..
'\d STORE $2\_s*' ..
'endfor\_s*' ..
'\d JUMP -> 5\_s*' ..
'8 DROP\_s*' ..
'\d RETURN void\_s*',
res)
enddef
def s:SilentWhile()
silent while g:not
endwhile
enddef
def Test_silent_while()
var res = execute('disass s:SilentWhile')
assert_match('<SNR>\d*_SilentWhile\_s*' ..
'silent while g:not\_s*' ..
'0 CMDMOD silent\_s*' ..
'\d LOADG g:not\_s*' ..
'\d COND2BOOL\_s*' ..
'\d CMDMOD_REV\_s*' ..
'\d WHILE $0 -> 6\_s*' ..
'endwhile\_s*' ..
'\d JUMP -> 0\_s*' ..
'6 RETURN void\_s*',
res)
enddef
def s:SilentReturn(): string
silent return "done"
enddef
def Test_silent_return()
var res = execute('disass s:SilentReturn')
assert_match('<SNR>\d*_SilentReturn\_s*' ..
'silent return "done"\_s*' ..
'\d CMDMOD silent\_s*' ..
'\d PUSHS "done"\_s*' ..
'\d CMDMOD_REV\_s*' ..
'\d RETURN',
res)
enddef
def s:Profiled(): string
# comment
echo "profiled"
# comment
var some = "some text"
return "done"
enddef
def Test_profiled()
if !has('profile')
MissingFeature 'profile'
endif
var res = execute('disass profile s:Profiled')
assert_match('<SNR>\d*_Profiled\_s*' ..
'# comment\_s*' ..
'echo "profiled"\_s*' ..
'\d PROFILE START line 2\_s*' ..
'\d PUSHS "profiled"\_s*' ..
'\d ECHO 1\_s*' ..
'# comment\_s*' ..
'var some = "some text"\_s*' ..
'\d PROFILE END\_s*' ..
'\d PROFILE START line 4\_s*' ..
'\d PUSHS "some text"\_s*' ..
'\d STORE $0\_s*' ..
'return "done"\_s*' ..
'\d PROFILE END\_s*' ..
'\d PROFILE START line 5\_s*' ..
'\d PUSHS "done"\_s*' ..
'\d\+ RETURN\_s*' ..
'\d\+ PROFILE END',
res)
enddef
def Test_debugged()
var res = execute('disass debug s:Profiled')
assert_match('<SNR>\d*_Profiled\_s*' ..
'# comment\_s*' ..
'echo "profiled"\_s*' ..
'\d DEBUG line 1-2 varcount 0\_s*' ..
'\d PUSHS "profiled"\_s*' ..
'\d ECHO 1\_s*' ..
'# comment\_s*' ..
'var some = "some text"\_s*' ..
'\d DEBUG line 3-4 varcount 0\_s*' ..
'\d PUSHS "some text"\_s*' ..
'\d STORE $0\_s*' ..
'return "done"\_s*' ..
'\d DEBUG line 5-5 varcount 1\_s*' ..
'\d PUSHS "done"\_s*' ..
'\d RETURN\_s*',
res)
enddef
def s:ElseifConstant()
if g:value
echo "one"
elseif true
echo "true"
elseif false
echo "false"
endif
if 0
echo "yes"
elseif 0
echo "no"
endif
enddef
def Test_debug_elseif_constant()
var res = execute('disass debug s:ElseifConstant')
assert_match('<SNR>\d*_ElseifConstant\_s*' ..
'if g:value\_s*' ..
'0 DEBUG line 1-1 varcount 0\_s*' ..
'1 LOADG g:value\_s*' ..
'2 COND2BOOL\_s*' ..
'3 JUMP_IF_FALSE -> 8\_s*' ..
'echo "one"\_s*' ..
'4 DEBUG line 2-2 varcount 0\_s*' ..
'5 PUSHS "one"\_s*' ..
'6 ECHO 1\_s*' ..
'elseif true\_s*' ..
'7 JUMP -> 12\_s*' ..
'8 DEBUG line 3-3 varcount 0\_s*' ..
'echo "true"\_s*' ..
'9 DEBUG line 4-4 varcount 0\_s*' ..
'10 PUSHS "true"\_s*' ..
'11 ECHO 1\_s*' ..
'elseif false\_s*' ..
'echo "false"\_s*' ..
'endif\_s*' ..
'if 0\_s*' ..
'12 DEBUG line 8-8 varcount 0\_s*' ..
'echo "yes"\_s*' ..
'elseif 0\_s*' ..
'13 DEBUG line 11-10 varcount 0\_s*' ..
'echo "no"\_s*' ..
'endif\_s*' ..
'14 RETURN void*',
res)
enddef
def s:DebugElseif()
var b = false
if b
eval 1 + 0
silent elseif !b
eval 2 + 0
endif
enddef
def Test_debug_elseif()
var res = execute('disass debug s:DebugElseif')
assert_match('<SNR>\d*_DebugElseif\_s*' ..
'var b = false\_s*' ..
'0 DEBUG line 1-1 varcount 0\_s*' ..
'1 PUSH false\_s*' ..
'2 STORE $0\_s*' ..
'if b\_s*' ..
'3 DEBUG line 2-2 varcount 1\_s*' ..
'4 LOAD $0\_s*' ..
'5 JUMP_IF_FALSE -> 10\_s*' ..
'eval 1 + 0\_s*' ..
'6 DEBUG line 3-3 varcount 1\_s*' ..
'7 PUSHNR 1\_s*' ..
'8 DROP\_s*' ..
'silent elseif !b\_s*' ..
'9 JUMP -> 20\_s*' ..
'10 CMDMOD silent\_s*' ..
'11 DEBUG line 4-4 varcount 1\_s*' ..
'12 LOAD $0\_s*' ..
'13 INVERT -1 (!val)\_s*' ..
'14 CMDMOD_REV\_s*' ..
'15 JUMP_IF_FALSE -> 20\_s*' ..
'eval 2 + 0\_s*' ..
'16 DEBUG line 5-5 varcount 1\_s*' ..
'17 PUSHNR 2\_s*' ..
'18 DROP\_s*' ..
'endif\_s*' ..
'19 DEBUG line 6-6 varcount 1\_s*' ..
'20 RETURN void*',
res)
enddef
def s:DebugFor()
echo "hello"
for a in [0]
echo a
endfor
enddef
def Test_debug_for()
var res = execute('disass debug s:DebugFor')
assert_match('<SNR>\d*_DebugFor\_s*' ..
'echo "hello"\_s*' ..
'0 DEBUG line 1-1 varcount 0\_s*' ..
'1 PUSHS "hello"\_s*' ..
'2 ECHO 1\_s*' ..
'for a in \[0\]\_s*' ..
'3 DEBUG line 2-2 varcount 0\_s*' ..
'4 STORE -1 in $0\_s*' ..
'5 PUSHNR 0\_s*' ..
'6 NEWLIST size 1\_s*' ..
'7 DEBUG line 2-2 varcount 3\_s*' ..
'8 FOR $0 -> 15\_s*' ..
'9 STORE $2\_s*' ..
'echo a\_s*' ..
'10 DEBUG line 3-3 varcount 3\_s*' ..
'11 LOAD $2\_s*' ..
'12 ECHO 1\_s*' ..
'endfor\_s*' ..
'13 DEBUG line 4-4 varcount 3\_s*' ..
'14 JUMP -> 7\_s*' ..
'15 DROP\_s*' ..
'16 RETURN void*',
res)
enddef
def s:TryCatch()
try
echo "try"
catch /error/
echo "caught"
endtry
enddef
def Test_debug_try_catch()
var res = execute('disass debug s:TryCatch')
assert_match('<SNR>\d*_TryCatch\_s*' ..
'try\_s*' ..
'0 DEBUG line 1-1 varcount 0\_s*' ..
'1 TRY catch -> 7, endtry -> 17\_s*' ..
'echo "try"\_s*' ..
'2 DEBUG line 2-2 varcount 0\_s*' ..
'3 PUSHS "try"\_s*' ..
'4 ECHO 1\_s*' ..
'catch /error/\_s*' ..
'5 DEBUG line 3-3 varcount 0\_s*' ..
'6 JUMP -> 17\_s*' ..
'7 DEBUG line 4-3 varcount 0\_s*' ..
'8 PUSH v:exception\_s*' ..
'9 PUSHS "error"\_s*' ..
'10 COMPARESTRING =\~\_s*' ..
'11 JUMP_IF_FALSE -> 17\_s*' ..
'12 CATCH\_s*' ..
'echo "caught"\_s*' ..
'13 DEBUG line 4-4 varcount 0\_s*' ..
'14 PUSHS "caught"\_s*' ..
'15 ECHO 1\_s*' ..
'endtry\_s*' ..
'16 DEBUG line 5-5 varcount 0\_s*' ..
'17 ENDTRY\_s*' ..
'\d\+ RETURN void',
res)
enddef
func s:Legacy() dict
echo 'legacy'
endfunc
def s:UseMember()
var d = {func: Legacy}
var v = d.func()
enddef
def Test_disassemble_dict_stack()
var res = execute('disass s:UseMember')
assert_match('<SNR>\d*_UseMember\_s*' ..
'var d = {func: Legacy}\_s*' ..
'\d PUSHS "func"\_s*' ..
'\d PUSHFUNC "<80><fd>R\d\+_Legacy"\_s*' ..
'\d NEWDICT size 1\_s*' ..
'\d SETTYPE dict<func(...): any>\_s*' ..
'\d STORE $0\_s*' ..
'var v = d.func()\_s*' ..
'\d LOAD $0\_s*' ..
'\d MEMBER func\_s*' ..
'\d PCALL top (argc 0)\_s*' ..
'\d PCALL end\_s*' ..
'\d CLEARDICT\_s*' ..
'\d\+ STORE $1\_s*' ..
'\d\+ RETURN void*',
res)
enddef
def s:RetLegacy(): string
legacy return "yes"
enddef
def Test_disassemble_return_legacy()
var res = execute('disass s:RetLegacy')
assert_match('<SNR>\d*_RetLegacy\_s*' ..
'legacy return "yes"\_s*' ..
'\d CMDMOD legacy\_s*' ..
'\d EVAL legacy "yes"\_s*' ..
'\d CHECKTYPE string stack\[-1]\_s*' ..
'\d CMDMOD_REV\_s*' ..
'\d RETURN',
res)
enddef
def s:EchoMessages()
echohl ErrorMsg | echom v:exception | echohl NONE
enddef
def Test_disassemble_nextcmd()
# splitting commands and removing trailing blanks should not change the line
var res = execute('disass s:EchoMessages')
assert_match('<SNR>\d*_EchoMessages\_s*' ..
'echohl ErrorMsg | echom v:exception | echohl NONE',
res)
enddef
def Test_disassemble_after_reload()
var lines =<< trim END
vim9script
if exists('g:ThisFunc')
finish
endif
var name: any
def g:ThisFunc(): number
g:name = name
return 0
enddef
def g:ThatFunc(): number
name = g:name
return 0
enddef
END
lines->writefile('Xreload.vim', 'D')
source Xreload.vim
g:ThisFunc()
g:ThatFunc()
source Xreload.vim
var res = execute('disass g:ThisFunc')
assert_match('ThisFunc\_s*' ..
'g:name = name\_s*' ..
'\d LOADSCRIPT \[deleted\] from .*/Xreload.vim\_s*' ..
'\d STOREG g:name\_s*' ..
'return 0\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d RETURN\_s*',
res)
res = execute('disass g:ThatFunc')
assert_match('ThatFunc\_s*' ..
'name = g:name\_s*' ..
'\d LOADG g:name\_s*' ..
'\d STORESCRIPT \[deleted\] in .*/Xreload.vim\_s*' ..
'return 0\_s*' ..
'\d PUSHNR 0\_s*' ..
'\d RETURN\_s*',
res)
delfunc g:ThisFunc
delfunc g:ThatFunc
enddef
def s:MakeString(x: number): string
return $"x={x} x^2={x * x}"
enddef
def Test_disassemble_string_interp()
var instr = execute('disassemble s:MakeString')
assert_match('MakeString\_s*' ..
'return $"x={x} x^2={x \* x}"\_s*' ..
'0 PUSHS "x="\_s*' ..
'1 LOAD arg\[-1\]\_s*' ..
'2 2STRING stack\[-1\]\_s*' ..
'3 PUSHS " x^2="\_s*' ..
'4 LOAD arg\[-1\]\_s*' ..
'5 LOAD arg\[-1\]\_s*' ..
'6 OPNR \*\_s*' ..
'7 2STRING stack\[-1\]\_s*' ..
'8 CONCAT size 4\_s*' ..
'9 RETURN\_s*',
instr)
enddef
def BitShift()
var a = 1 << 2
var b = 8 >> 1
var c = a << b
var d = b >> a
enddef
def Test_disassemble_bitshift()
var instr = execute('disassemble BitShift')
assert_match('BitShift\_s*' ..
'var a = 1 << 2\_s*' ..
'0 STORE 4 in $0\_s*' ..
'var b = 8 >> 1\_s*' ..
'1 STORE 4 in $1\_s*' ..
'var c = a << b\_s*' ..
'2 LOAD $0\_s*' ..
'3 LOAD $1\_s*' ..
'4 OPNR <<\_s*' ..
'5 STORE $2\_s*' ..
'var d = b >> a\_s*' ..
'6 LOAD $1\_s*' ..
'7 LOAD $0\_s*' ..
'8 OPNR >>\_s*' ..
'9 STORE $3\_s*' ..
'10 RETURN void', instr)
enddef
def s:OneDefer()
defer delete("file")
enddef
def Test_disassemble_defer()
var instr = execute('disassemble s:OneDefer')
assert_match('OneDefer\_s*' ..
'defer delete("file")\_s*' ..
'\d PUSHFUNC "delete"\_s*' ..
'\d PUSHS "file"\_s*' ..
'\d DEFER 1 args\_s*' ..
'\d RETURN\_s*',
instr)
enddef
def Test_disassemble_class_function()
var lines =<< trim END
vim9script
class Cl
static def Fc(): string
return "x"
enddef
endclass
g:instr = execute('disassemble Cl.Fc')
END
v9.CheckScriptSuccess(lines)
assert_match('Fc\_s*' ..
'return "x"\_s*' ..
'\d PUSHS "x"\_s*' ..
'\d RETURN\_s*',
g:instr)
lines =<< trim END
vim9script
class Cl
def Fo(): string
return "y"
enddef
endclass
g:instr = execute('disassemble Cl.Fo')
END
v9.CheckScriptSuccess(lines)
assert_match('Fo\_s*' ..
'return "y"\_s*' ..
'\d PUSHS "y"\_s*' ..
'\d RETURN\_s*',
g:instr)
unlet g:instr
enddef
" Disassemble instructions for using an interface with static and regular member
" variables.
def Test_disassemble_interface_static_member()
var lines =<< trim END
vim9script
interface I
var o_var: number
var o_var2: number
endinterface
class C implements I
public static var s_var: number
var o_var: number
public static var s_var2: number
var o_var2: number
endclass
def F1(i: I)
var x: number
x = i.o_var
x = i.o_var2
enddef
def F2(o: C)
var x: number
x = o.o_var
x = o.o_var2
enddef
g:instr1 = execute('disassemble F1')
g:instr2 = execute('disassemble F2')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_F1\_s*' ..
'var x: number\_s*' ..
'x = i.o_var\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 ITF_MEMBER 0 on I\_s*' ..
'2 STORE $0\_s*' ..
'x = i.o_var2\_s*' ..
'3 LOAD arg\[-1\]\_s*' ..
'4 ITF_MEMBER 1 on I\_s*' ..
'5 STORE $0\_s*' ..
'6 RETURN void\_s*',
g:instr1)
assert_match('<SNR>\d*_F2\_s*' ..
'var x: number\_s*' ..
'x = o.o_var\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 OBJ_MEMBER 0\_s*' ..
'2 STORE $0\_s*' ..
'x = o.o_var2\_s*' ..
'3 LOAD arg\[-1\]\_s*' ..
'4 OBJ_MEMBER 1\_s*' ..
'5 STORE $0\_s*' ..
'6 RETURN void',
g:instr2)
unlet g:instr1
unlet g:instr2
enddef
" Disassemble instructions for loading and storing class variables
def Test_disassemble_class_variable()
var lines =<< trim END
vim9script
class A
public static var val = 10
def Foo(): number
val = 20
return val
enddef
endclass
g:instr = execute('disassemble A.Foo')
END
v9.CheckScriptSuccess(lines)
assert_match('Foo\_s*' ..
'val = 20\_s*' ..
'0 PUSHNR 20\_s*' ..
'1 STORE CLASSMEMBER A.val\_s*' ..
'return val\_s*' ..
'2 LOAD CLASSMEMBER A.val\_s*' ..
'3 RETURN', g:instr)
unlet g:instr
enddef
" Disassemble instructions for METHODCALL
def Test_disassemble_methodcall()
var lines =<< trim END
vim9script
interface A
def Foo()
endinterface
def Bar(a: A)
a.Foo()
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'a.Foo()\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 METHODCALL A.Foo(argc 0)\_s*' ..
'2 DROP\_s*' ..
'3 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for ISN_JUMP_IF_ARG_NOT_SET
def Test_disassemble_ifargnotset()
var lines =<< trim END
vim9script
class A
var val: number = 10
endclass
g:instr = execute('disassemble A.new')
END
v9.CheckScriptSuccess(lines)
assert_match('new\_s*' ..
'0 NEW A size \d\+\_s*' ..
'1 PUSHNR 10\_s*' ..
'2 STORE_THIS 0\_s*' ..
'ifargisset 0 this.val = val\_s*' ..
'3 JUMP_IF_ARG_NOT_SET arg\[-1\] -> 8\_s*' ..
'4 LOAD arg\[-1\]\_s*' ..
'5 PUSHNR 0\_s*' ..
'6 LOAD $0\_s*' ..
'7 STOREINDEX object\_s*' ..
'8 RETURN object', g:instr)
unlet g:instr
enddef
" Disassemble instructions for ISN_COMPAREOBJECT
def Test_disassemble_compare_class_object()
var lines =<< trim END
vim9script
class A
endclass
class B
endclass
def Foo(a: A, b: B)
if a == b
endif
enddef
g:instr = execute('disassemble Foo')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Foo\_s*' ..
'if a == b\_s*' ..
'0 LOAD arg\[-2\]\_s*' ..
'1 LOAD arg\[-1\]\_s*' ..
'2 COMPAREOBJECT ==\_s*' ..
'3 JUMP_IF_FALSE -> 4\_s*' ..
'endif\_s*' ..
'4 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for ISN_CHECKTYPE with a float|number
def Test_checktype_float()
var lines =<< trim END
vim9script
def Foo()
var f: float = 0.0
var a: any
f += a
enddef
g:instr = execute('disassemble Foo')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Foo\_s*' ..
'var f: float = 0.0\_s*' ..
'0 PUSHF 0.0\_s*' ..
'1 STORE $0\_s*' ..
'var a: any\_s*' ..
'f += a\_s*' ..
'2 LOAD $0\_s*' ..
'3 LOAD $1\_s*' ..
'4 CHECKTYPE float|number stack\[-1\]\_s*' ..
'5 OPANY +\_s*' ..
'6 STORE $0\_s*' ..
'7 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for ISN_FUNCREF with a class
def Test_funcref_with_class()
var lines =<< trim END
vim9script
class A
def Foo()
enddef
endclass
class B extends A
def Foo()
enddef
endclass
def Bar(a: A)
defer a.Foo()
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'defer a.Foo()\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 FUNCREF A.Foo\_s*' ..
'2 DEFER 0 args\_s*' ..
'3 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for calls to a string() function in an object
def Test_disassemble_object_string()
var lines =<< trim END
vim9script
class A
def string(): string
return 'A'
enddef
endclass
def Bar()
var a = A.new()
var s = string(a)
s = string(A)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = string(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 METHODCALL A.string(argc 0)\_s*' ..
'4 STORE $1\_s*' ..
's = string(A)\_s*' ..
'5 LOADSCRIPT A-0 from .*\_s*' ..
'6 BCALL string(argc 1)\_s*' ..
'7 STORE $1\_s*' ..
'8 RETURN void', g:instr)
unlet g:instr
# Use the default string() function for a class
lines =<< trim END
vim9script
class A
endclass
def Bar()
var a = A.new()
var s = string(a)
s = string(A)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = string(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 BCALL string(argc 1)\_s*' ..
'4 STORE $1\_s*' ..
's = string(A)\_s*' ..
'5 LOADSCRIPT A-0 from .*\_s*' ..
'6 BCALL string(argc 1)\_s*' ..
'7 STORE $1\_s*' ..
'8 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for calls to a empty() function in an object
def Test_disassemble_object_empty()
var lines =<< trim END
vim9script
class A
def empty(): bool
return true
enddef
endclass
def Bar()
var a = A.new()
var s = empty(a)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = empty(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 METHODCALL A.empty(argc 0)\_s*' ..
'4 STORE $1\_s*' ..
'5 RETURN void', g:instr)
unlet g:instr
# Use the default empty() function for a class
lines =<< trim END
vim9script
class A
endclass
def Bar()
var a = A.new()
var s = empty(a)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = empty(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 BCALL empty(argc 1)\_s*' ..
'4 STORE $1\_s*' ..
'5 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for calls to a len() function in an object
def Test_disassemble_object_len()
var lines =<< trim END
vim9script
class A
def len(): number
return 10
enddef
endclass
def Bar()
var a = A.new()
var s = len(a)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = len(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 METHODCALL A.len(argc 0)\_s*' ..
'4 STORE $1\_s*' ..
'5 RETURN void', g:instr)
unlet g:instr
# Use the default len() function for a class
lines =<< trim END
vim9script
class A
endclass
def Bar()
var a = A.new()
var s = len(a)
enddef
g:instr = execute('disassemble Bar')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d*_Bar\_s*' ..
'var a = A.new()\_s*' ..
'0 DCALL new(argc 0)\_s*' ..
'1 STORE $0\_s*' ..
'var s = len(a)\_s*' ..
'2 LOAD $0\_s*' ..
'3 BCALL len(argc 1)\_s*' ..
'4 STORE $1\_s*' ..
'5 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble instructions for using a compound operator in a closure
def Test_disassemble_compound_op_in_closure()
var lines =<< trim END
vim9script
class A
var foo: number = 1
def Foo(): func
var Fn = () => {
this.foo += 1
}
return Fn
enddef
endclass
var a = A.new()
var Lambda = a.Foo()
var num = matchstr(string(Lambda), '\d\+')
g:instr = execute($'disassemble <lambda>{num}')
END
v9.CheckScriptSuccess(lines)
assert_match('<lambda>\d\+\_s*' ..
'this.foo += 1\_s*' ..
'0 LOADOUTER level 0 $0\_s*' ..
'1 OBJ_MEMBER 0\_s*' ..
'2 PUSHNR 1\_s*' ..
'3 OPNR +\_s*' ..
'4 PUSHNR 0\_s*' ..
'5 LOADOUTER level 0 $0\_s*' ..
'6 STOREINDEX object\_s*' ..
'7 RETURN void', g:instr)
unlet g:instr
enddef
def Test_disassemble_member_initializer()
var lines =<< trim END
vim9script
class A
var l: list<string> = []
var d: dict<string> = {}
endclass
g:instr = execute('disassemble A.new')
END
v9.CheckScriptSuccess(lines)
# Ensure SETTYPE is emitted and that matches the declared type.
assert_match('new\_s*' ..
'0 NEW A size \d\+\_s*' ..
'1 NEWLIST size 0\_s*' ..
'2 SETTYPE list<string>\_s*' ..
'3 STORE_THIS 0\_s*' ..
'4 NEWDICT size 0\_s*' ..
'5 SETTYPE dict<string>\_s*' ..
'6 STORE_THIS 1', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for accessing a interface member variable
def Test_disassemble_interface_variable_access()
var lines =<< trim END
vim9script
interface IX
var F: func(): string
endinterface
def Foo(ix: IX): string
return ix.F()
enddef
g:instr = execute('disassemble Foo')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Foo\_s*' ..
'return ix.F()\_s*' ..
'0 LOAD arg\[-1\]\_s*' ..
'1 ITF_MEMBER 0 on IX\_s*' ..
'2 PCALL top (argc 0)\_s*' ..
'3 PCALL end\_s*' ..
'4 RETURN', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for accessing a script-local funcref
def Test_disassemble_using_script_local_funcref()
var lines =<< trim END
vim9script
def Noop()
enddef
export var Setup = Noop
export def Run()
Setup()
enddef
g:instr = execute('disassemble Run')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Run\_s*' ..
'Setup()\_s*' ..
'0 LOADSCRIPT Setup-0 from .*\_s*' ..
'1 PCALL (argc 0)\_s*' ..
'2 DROP\_s*' ..
'3 RETURN void\_s*', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for using a script local variable
" in an instance variable initialization expression
def Test_disassemble_using_script_local_var_in_obj_init()
var lines =<< trim END
vim9script
const DEFAULT = 'default-obj_key'
export class ObjKey
const unique_object_id3 = DEFAULT
endclass
END
writefile(lines, 'Xscriptlocalobjinit.vim', 'D')
lines =<< trim END
vim9script
import './Xscriptlocalobjinit.vim' as obj_key
class C1 extends obj_key.ObjKey
endclass
g:instr = execute('disassemble C1.new')
END
v9.CheckScriptSuccess(lines)
assert_match('new\_s*' ..
'0 NEW C1 size \d\+\_s*' ..
'1 SCRIPTCTX_SET .*/Xscriptlocalobjinit.vim\_s*' ..
'2 LOADSCRIPT DEFAULT-0 from .*/Xscriptlocalobjinit.vim\_s*' ..
'3 SCRIPTCTX_SET .*\_s*' ..
'4 STORE_THIS 0', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for indexing a tuple
def Test_disassemble_tuple_indexing()
var lines =<< trim END
vim9script
def Fn(): tuple<...list<number>>
var t = (5, 6, 7)
var i = t[2]
var j = t[1 : 2]
return t
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var t = (5, 6, 7)\_s*' ..
'0 PUSHNR 5\_s*' ..
'1 PUSHNR 6\_s*' ..
'2 PUSHNR 7\_s*' ..
'3 NEWTUPLE size 3\_s*' ..
'4 SETTYPE tuple<number, number, number>\_s*' ..
'5 STORE $0\_s*' ..
'var i = t\[2\]\_s*' ..
'6 LOAD $0\_s*' ..
'7 PUSHNR 2\_s*' ..
'8 TUPLEINDEX\_s*' ..
'9 STORE $1\_s*' ..
'var j = t\[1 : 2\]\_s*' ..
'10 LOAD $0\_s*' ..
'11 PUSHNR 1\_s*' ..
'12 PUSHNR 2\_s*' ..
'13 TUPLESLICE\_s*' ..
'14 SETTYPE tuple<number, number, number>\_s*' ..
'15 STORE $2\_s*' ..
'return t\_s*' ..
'16 LOAD $0\_s*' ..
'17 RETURN', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for assigning a tuple to a default value
def Test_disassemble_tuple_default_value()
var lines =<< trim END
vim9script
def Fn()
var t: tuple<number>
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var t: tuple<number>\_s*' ..
'0 NEWTUPLE size 0\_s*' ..
'1 SETTYPE tuple<number>\_s*' ..
'2 STORE $0\_s*' ..
'3 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for comparing tuples
def Test_disassemble_tuple_compare()
var lines =<< trim END
vim9script
def Fn()
var t1 = (1, 2)
var t2 = t1
var x = t1 == t2
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var t1 = (1, 2)\_s*' ..
'0 PUSHNR 1\_s*' ..
'1 PUSHNR 2\_s*' ..
'2 NEWTUPLE size 2\_s*' ..
'3 SETTYPE tuple<number, number>\_s*' ..
'4 STORE $0\_s*' ..
'var t2 = t1\_s*' ..
'5 LOAD $0\_s*' ..
'6 SETTYPE tuple<number, number>\_s*' ..
'7 STORE $1\_s*' ..
'var x = t1 == t2\_s*' ..
'8 LOAD $0\_s*' ..
'9 LOAD $1\_s*' ..
'10 COMPARETUPLE ==\_s*' ..
'11 STORE $2\_s*' ..
'12 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for concatenating tuples
def Test_disassemble_tuple_concatenate()
var lines =<< trim END
vim9script
def Fn()
var t1 = (1,) + (2,)
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var t1 = (1,) + (2,)\_s*' ..
'0 PUSHNR 1\_s*' ..
'1 NEWTUPLE size 1\_s*' ..
'2 PUSHNR 2\_s*' ..
'3 NEWTUPLE size 1\_s*' ..
'4 ADDTUPLE\_s*' ..
'5 SETTYPE tuple<number, number>\_s*' ..
'6 STORE $0\_s*' ..
'7 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for a constant tupe
def Test_disassemble_tuple_const()
var lines =<< trim END
vim9script
def Fn()
const t = (1, 2, 3)
var x = t[1 : 2]
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'const t = (1, 2, 3)\_s*' ..
'0 PUSHNR 1\_s*' ..
'1 PUSHNR 2\_s*' ..
'2 PUSHNR 3\_s*' ..
'3 NEWTUPLE size 3\_s*' ..
'4 LOCKCONST\_s*' ..
'5 SETTYPE tuple<number, number, number>\_s*' ..
'6 STORE $0\_s*' ..
'var x = t\[1 : 2\]\_s*' ..
'7 LOAD $0\_s*' ..
'8 PUSHNR 1\_s*' ..
'9 PUSHNR 2\_s*' ..
'10 TUPLESLICE\_s*' ..
'11 SETTYPE tuple<number, number, number>\_s*' ..
'12 STORE $1\_s*' ..
'13 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for setting the type when using a tuple in an
" assignment
def Test_disassemble_assign_tuple_set_type()
var lines =<< trim END
vim9script
def Fn()
var x = (1,)
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var x = (1,)\_s*' ..
'0 PUSHNR 1\_s*' ..
'1 NEWTUPLE size 1\_s*' ..
'2 SETTYPE tuple<number>\_s*' ..
'3 STORE $0\_s*' ..
'4 RETURN void', g:instr)
lines =<< trim END
vim9script
def Fn()
var x = ()
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'var x = ()\_s*' ..
'0 NEWTUPLE size 0\_s*' ..
'1 STORE $0\_s*' ..
'2 RETURN void', g:instr)
unlet g:instr
enddef
" Disassemble the code generated for a has() function call
def Test_disassemble_has_shortcircuit()
# true && false condition check
var lines =<< trim END
vim9script
def Fn(): string
if has('jumplist') && has('foobar')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''jumplist'') && has(''foobar'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# false && true condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') && has('jumplist')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') && has(''jumplist'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# false && false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') && has('foobaz')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') && has(''foobaz'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
# true || false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('jumplist') || has('foobar')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''jumplist'') || has(''foobar'')\_s*' ..
'return ''present''\_s*' ..
'0 PUSHS "present"\_s*' ..
'1 RETURN\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'2 PUSHS "missing"\_s*' ..
'3 RETURN', g:instr)
# false || true condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') || has('jumplist')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') || has(''jumplist'')\_s*' ..
'return ''present''\_s*' ..
'0 PUSHS "present"\_s*' ..
'1 RETURN\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'2 PUSHS "missing"\_s*' ..
'3 RETURN', g:instr)
# false || false condition check
lines =<< trim END
vim9script
def Fn(): string
if has('foobar') || has('foobaz')
return 'present'
endif
return 'missing'
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'if has(''foobar'') || has(''foobaz'')\_s*' ..
'return ''present''\_s*' ..
'endif\_s*' ..
'return ''missing''\_s*' ..
'0 PUSHS "missing"\_s*' ..
'1 RETURN', g:instr)
enddef
" Disassemble the code generated for a loop with closure following another loop
def Test_disassemble_loop_with_closure_after_loop()
var lines =<< trim END
vim9script
def Fn()
for i in "a"
var v1 = 0
endfor
var idx = 1
while idx > 0
idx -= 1
endwhile
var s = "abc"
for j in range(2)
var k = 0
g:Ref = () => j
endfor
enddef
g:instr = execute('disassemble Fn')
END
v9.CheckScriptSuccess(lines)
assert_match('<SNR>\d\+_Fn\_s*' ..
'for i in "a"\_s*' ..
'0 STORE -1 in $0\_s*' ..
'1 PUSHS "a"\_s*' ..
'2 FOR $0 -> 6\_s*' ..
'3 STORE $2\_s*' ..
'var v1 = 0\_s*' ..
'4 STORE 0 in $3\_s*' ..
'endfor\_s*' ..
'5 JUMP -> 2\_s*' ..
'6 DROP\_s*' ..
'var idx = 1\_s*' ..
'7 STORE 1 in $4\_s*' ..
'while idx > 0\_s*' ..
'8 LOAD $4\_s*' ..
'9 PUSHNR 0\_s*' ..
'10 COMPARENR >\_s*' ..
'11 WHILE $5 -> 17\_s*' ..
'idx -= 1\_s*' ..
'12 LOAD $4\_s*' ..
'13 PUSHNR 1\_s*' ..
'14 OPNR -\_s*' ..
'15 STORE $4\_s*' ..
'endwhile\_s*' ..
'16 JUMP -> 8\_s*' ..
'var s = "abc"\_s*' ..
'17 PUSHS "abc"\_s*' ..
'18 STORE $6\_s*' ..
'for j in range(2)\_s*' ..
'19 STORE -1 in $7\_s*' ..
'20 PUSHNR 2\_s*' ..
'21 BCALL range(argc 1)\_s*' ..
'22 FOR $7 -> 29\_s*' ..
'23 STORE $9\_s*' ..
'var k = 0\_s*' ..
'24 STORE 0 in $10\_s*' ..
'g:Ref = () => j\_s*' ..
'25 FUNCREF <lambda>\d\+ vars $10-$10\_s*' ..
'26 STOREG g:Ref\_s*' ..
'endfor\_s*' ..
'27 ENDLOOP ref $8 save $10-$10 depth 0\_s*' ..
'28 JUMP -> 22\_s*' ..
'29 DROP\_s*' ..
'30 RETURN void', g:instr)
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/mirrors/vim.git
git@gitee.com:mirrors/vim.git
mirrors
vim
Vim
master

搜索帮助