IDLGenerators.cpp 215 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132
  1. /*
  2. * Copyright (c) 2020-2023, Andreas Kling <andreas@ladybird.org>
  3. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021-2023, Luke Wilde <lukew@serenityos.org>
  5. * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  6. * Copyright (c) 2023-2024, Kenneth Myhra <kennethmyhra@serenityos.org>
  7. * Copyright (c) 2023-2024, Shannon Booth <shannon@serenityos.org>
  8. * Copyright (c) 2023-2024, Matthew Olsson <mattco@serenityos.org>
  9. *
  10. * SPDX-License-Identifier: BSD-2-Clause
  11. */
  12. #include "IDLGenerators.h"
  13. #include "Namespaces.h"
  14. #include <AK/Array.h>
  15. #include <AK/LexicalPath.h>
  16. #include <AK/Queue.h>
  17. #include <AK/QuickSort.h>
  18. #include <LibIDL/Types.h>
  19. namespace IDL {
  20. Vector<StringView> g_header_search_paths;
  21. // FIXME: Generate this automatically somehow.
  22. static bool is_platform_object(Type const& type)
  23. {
  24. // NOTE: This is a hand-curated subset of platform object types that are actually relevant
  25. // in places where this function is used. If you add IDL code and get compile errors, you
  26. // might simply need to add another type here.
  27. static constexpr Array types = {
  28. "AbortSignal"sv,
  29. "Animation"sv,
  30. "AnimationEffect"sv,
  31. "AnimationTimeline"sv,
  32. "Attr"sv,
  33. "AudioBuffer"sv,
  34. "AudioListener"sv,
  35. "AudioNode"sv,
  36. "AudioParam"sv,
  37. "AudioScheduledSourceNode"sv,
  38. "AudioTrack"sv,
  39. "BaseAudioContext"sv,
  40. "Blob"sv,
  41. "CanvasGradient"sv,
  42. "CanvasPattern"sv,
  43. "CanvasRenderingContext2D"sv,
  44. "CloseWatcher"sv,
  45. "CryptoKey"sv,
  46. "DataTransfer"sv,
  47. "Document"sv,
  48. "DocumentType"sv,
  49. "DOMRectReadOnly"sv,
  50. "DynamicsCompressorNode"sv,
  51. "ElementInternals"sv,
  52. "EventTarget"sv,
  53. "File"sv,
  54. "FileList"sv,
  55. "FontFace"sv,
  56. "FormData"sv,
  57. "HTMLCollection"sv,
  58. "IDBCursor"sv,
  59. "IDBIndex"sv,
  60. "IDBKeyRange"sv,
  61. "IDBObjectStore"sv,
  62. "IDBTransaction"sv,
  63. "ImageBitmap"sv,
  64. "ImageData"sv,
  65. "Instance"sv,
  66. "IntersectionObserverEntry"sv,
  67. "KeyframeEffect"sv,
  68. "MediaList"sv,
  69. "Memory"sv,
  70. "MessagePort"sv,
  71. "Module"sv,
  72. "MutationRecord"sv,
  73. "NamedNodeMap"sv,
  74. "NavigationDestination"sv,
  75. "NavigationHistoryEntry"sv,
  76. "Node"sv,
  77. "Path2D"sv,
  78. "PerformanceEntry"sv,
  79. "PerformanceMark"sv,
  80. "PerformanceNavigation"sv,
  81. "PeriodicWave"sv,
  82. "PointerEvent"sv,
  83. "ReadableStreamBYOBReader"sv,
  84. "ReadableStreamDefaultReader"sv,
  85. "RadioNodeList"sv,
  86. "Range"sv,
  87. "ReadableStream"sv,
  88. "Request"sv,
  89. "Selection"sv,
  90. "ServiceWorkerContainer"sv,
  91. "ServiceWorkerRegistration"sv,
  92. "SVGTransform"sv,
  93. "ShadowRoot"sv,
  94. "SourceBuffer"sv,
  95. "Table"sv,
  96. "Text"sv,
  97. "TextMetrics"sv,
  98. "TextTrack"sv,
  99. "TimeRanges"sv,
  100. "URLSearchParams"sv,
  101. "VTTRegion"sv,
  102. "VideoTrack"sv,
  103. "VideoTrackList"sv,
  104. "WebGL2RenderingContext"sv,
  105. "WebGLActiveInfo"sv,
  106. "WebGLBuffer"sv,
  107. "WebGLFramebuffer"sv,
  108. "WebGLObject"sv,
  109. "WebGLProgram"sv,
  110. "WebGLRenderbuffer"sv,
  111. "WebGLRenderingContext"sv,
  112. "WebGLShader"sv,
  113. "WebGLShaderPrecisionFormat"sv,
  114. "WebGLTexture"sv,
  115. "WebGLUniformLocation"sv,
  116. "WebGLVertexArrayObject"sv,
  117. "Window"sv,
  118. "WindowProxy"sv,
  119. "WritableStream"sv,
  120. };
  121. if (type.name().ends_with("Element"sv))
  122. return true;
  123. if (type.name().ends_with("Event"sv))
  124. return true;
  125. if (types.span().contains_slow(type.name()))
  126. return true;
  127. return false;
  128. }
  129. // FIXME: Generate this automatically somehow.
  130. static bool is_javascript_builtin(Type const& type)
  131. {
  132. // NOTE: This is a hand-curated subset of JavaScript built-in types that are actually relevant
  133. // in places where this function is used. If you add IDL code and get compile errors, you
  134. // might simply need to add another type here.
  135. static constexpr Array types = {
  136. "ArrayBuffer"sv,
  137. "Float16Array"sv,
  138. "Float32Array"sv,
  139. "Float64Array"sv,
  140. "Uint8Array"sv,
  141. "Uint8ClampedArray"sv,
  142. };
  143. return types.span().contains_slow(type.name());
  144. }
  145. static StringView sequence_storage_type_to_cpp_storage_type_name(SequenceStorageType sequence_storage_type)
  146. {
  147. switch (sequence_storage_type) {
  148. case SequenceStorageType::Vector:
  149. return "Vector"sv;
  150. case SequenceStorageType::MarkedVector:
  151. return "GC::MarkedVector"sv;
  152. default:
  153. VERIFY_NOT_REACHED();
  154. }
  155. }
  156. CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface);
  157. static ByteString union_type_to_variant(UnionType const& union_type, Interface const& interface)
  158. {
  159. StringBuilder builder;
  160. builder.append("Variant<"sv);
  161. auto flattened_types = union_type.flattened_member_types();
  162. for (size_t type_index = 0; type_index < flattened_types.size(); ++type_index) {
  163. auto& type = flattened_types.at(type_index);
  164. if (type_index > 0)
  165. builder.append(", "sv);
  166. auto cpp_type = idl_type_name_to_cpp_type(type, interface);
  167. builder.append(cpp_type.name);
  168. }
  169. if (union_type.includes_undefined())
  170. builder.append(", Empty"sv);
  171. builder.append('>');
  172. return builder.to_byte_string();
  173. }
  174. CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
  175. {
  176. if (is_platform_object(type) || type.name() == "WindowProxy"sv)
  177. return { .name = ByteString::formatted("GC::Root<{}>", type.name()), .sequence_storage_type = SequenceStorageType::MarkedVector };
  178. if (is_javascript_builtin(type))
  179. return { .name = ByteString::formatted("GC::Root<JS::{}>", type.name()), .sequence_storage_type = SequenceStorageType::MarkedVector };
  180. if (interface.callback_functions.contains(type.name()))
  181. return { .name = "GC::Root<WebIDL::CallbackType>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  182. if (type.is_string())
  183. return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector };
  184. if ((type.name() == "double" || type.name() == "unrestricted double") && !type.is_nullable())
  185. return { .name = "double", .sequence_storage_type = SequenceStorageType::Vector };
  186. if ((type.name() == "float" || type.name() == "unrestricted float") && !type.is_nullable())
  187. return { .name = "float", .sequence_storage_type = SequenceStorageType::Vector };
  188. if (type.name() == "boolean" && !type.is_nullable())
  189. return { .name = "bool", .sequence_storage_type = SequenceStorageType::Vector };
  190. if (type.name() == "unsigned long" && !type.is_nullable())
  191. return { .name = "WebIDL::UnsignedLong", .sequence_storage_type = SequenceStorageType::Vector };
  192. if (type.name() == "short" && !type.is_nullable())
  193. return { .name = "WebIDL::Short", .sequence_storage_type = SequenceStorageType::Vector };
  194. if (type.name() == "unsigned short" && !type.is_nullable())
  195. return { .name = "WebIDL::UnsignedShort", .sequence_storage_type = SequenceStorageType::Vector };
  196. if (type.name() == "long long" && !type.is_nullable())
  197. return { .name = "WebIDL::LongLong", .sequence_storage_type = SequenceStorageType::Vector };
  198. if (type.name() == "unsigned long long" && !type.is_nullable())
  199. return { .name = "WebIDL::UnsignedLongLong", .sequence_storage_type = SequenceStorageType::Vector };
  200. if (type.name() == "long" && !type.is_nullable())
  201. return { .name = "WebIDL::Long", .sequence_storage_type = SequenceStorageType::Vector };
  202. if (type.name() == "any" || type.name() == "undefined")
  203. return { .name = "JS::Value", .sequence_storage_type = SequenceStorageType::MarkedVector };
  204. if (type.name() == "object")
  205. return { .name = "GC::Root<JS::Object>", .sequence_storage_type = SequenceStorageType::Vector };
  206. if (type.name() == "BufferSource")
  207. return { .name = "GC::Root<WebIDL::BufferSource>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  208. if (type.name() == "ArrayBufferView")
  209. return { .name = "GC::Root<WebIDL::ArrayBufferView>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  210. if (type.name() == "File")
  211. return { .name = "GC::Root<FileAPI::File>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  212. if (type.name() == "Function")
  213. return { .name = "GC::Ref<WebIDL::CallbackType>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  214. if (type.name() == "sequence") {
  215. auto& parameterized_type = verify_cast<ParameterizedType>(type);
  216. auto& sequence_type = parameterized_type.parameters().first();
  217. auto sequence_cpp_type = idl_type_name_to_cpp_type(sequence_type, interface);
  218. auto storage_type_name = sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type);
  219. if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::MarkedVector)
  220. return { .name = storage_type_name, .sequence_storage_type = SequenceStorageType::Vector };
  221. return { .name = ByteString::formatted("{}<{}>", storage_type_name, sequence_cpp_type.name), .sequence_storage_type = SequenceStorageType::Vector };
  222. }
  223. if (type.name() == "record") {
  224. auto& parameterized_type = verify_cast<ParameterizedType>(type);
  225. auto& record_key_type = parameterized_type.parameters()[0];
  226. auto& record_value_type = parameterized_type.parameters()[1];
  227. auto record_key_cpp_type = idl_type_name_to_cpp_type(record_key_type, interface);
  228. auto record_value_cpp_type = idl_type_name_to_cpp_type(record_value_type, interface);
  229. return { .name = ByteString::formatted("OrderedHashMap<{}, {}>", record_key_cpp_type.name, record_value_cpp_type.name), .sequence_storage_type = SequenceStorageType::Vector };
  230. }
  231. if (is<UnionType>(type)) {
  232. auto& union_type = verify_cast<UnionType>(type);
  233. return { .name = union_type_to_variant(union_type, interface), .sequence_storage_type = SequenceStorageType::Vector };
  234. }
  235. if (!type.is_nullable()) {
  236. for (auto& dictionary : interface.dictionaries) {
  237. if (type.name() == dictionary.key)
  238. return { .name = type.name(), .sequence_storage_type = SequenceStorageType::Vector };
  239. }
  240. }
  241. if (interface.enumerations.contains(type.name()))
  242. return { .name = type.name(), .sequence_storage_type = SequenceStorageType::Vector };
  243. dbgln("Unimplemented type for idl_type_name_to_cpp_type: {}{}", type.name(), type.is_nullable() ? "?" : "");
  244. TODO();
  245. }
  246. static ByteString make_input_acceptable_cpp(ByteString const& input)
  247. {
  248. if (input.is_one_of("class", "template", "for", "default", "char", "namespace", "delete", "inline", "register")) {
  249. StringBuilder builder;
  250. builder.append(input);
  251. builder.append('_');
  252. return builder.to_byte_string();
  253. }
  254. return input.replace("-"sv, "_"sv, ReplaceMode::All);
  255. }
  256. static void generate_include_for_iterator(auto& generator, auto& iterator_path)
  257. {
  258. auto iterator_generator = generator.fork();
  259. iterator_generator.set("iterator_class.path", iterator_path);
  260. iterator_generator.append(R"~~~(
  261. # include <LibWeb/@iterator_class.path@.h>
  262. )~~~");
  263. }
  264. static void generate_include_for(auto& generator, auto& path)
  265. {
  266. auto forked_generator = generator.fork();
  267. auto path_string = path;
  268. for (auto& search_path : g_header_search_paths) {
  269. if (!path.starts_with(search_path))
  270. continue;
  271. auto relative_path = *LexicalPath::relative_path(path, search_path);
  272. if (relative_path.length() < path_string.length())
  273. path_string = relative_path;
  274. }
  275. LexicalPath include_path { path_string };
  276. forked_generator.set("include.path", ByteString::formatted("{}/{}.h", include_path.dirname(), include_path.title()));
  277. forked_generator.append(R"~~~(
  278. #include <@include.path@>
  279. )~~~");
  280. }
  281. static void emit_includes_for_all_imports(auto& interface, auto& generator, bool is_iterator = false)
  282. {
  283. Queue<RemoveCVReference<decltype(interface)> const*> interfaces;
  284. HashTable<ByteString> paths_imported;
  285. interfaces.enqueue(&interface);
  286. while (!interfaces.is_empty()) {
  287. auto interface = interfaces.dequeue();
  288. if (paths_imported.contains(interface->module_own_path))
  289. continue;
  290. paths_imported.set(interface->module_own_path);
  291. for (auto& imported_interface : interface->imported_modules) {
  292. if (!paths_imported.contains(imported_interface.module_own_path))
  293. interfaces.enqueue(&imported_interface);
  294. }
  295. if (!interface->will_generate_code())
  296. continue;
  297. generate_include_for(generator, interface->module_own_path);
  298. }
  299. if (is_iterator) {
  300. auto iterator_path = ByteString::formatted("{}Iterator", interface.fully_qualified_name.replace("::"sv, "/"sv, ReplaceMode::All));
  301. generate_include_for_iterator(generator, iterator_path);
  302. }
  303. }
  304. template<typename ParameterType>
  305. static void generate_to_string(SourceGenerator& scoped_generator, ParameterType const& parameter, bool variadic, bool optional, Optional<ByteString> const& optional_default_value)
  306. {
  307. if (parameter.type->name() == "USVString") {
  308. scoped_generator.set("to_string", "to_usv_string"sv);
  309. } else if (parameter.type->name() == "ByteString") {
  310. scoped_generator.set("to_string", "to_byte_string"sv);
  311. } else {
  312. scoped_generator.set("to_string", "to_string"sv);
  313. }
  314. if (variadic) {
  315. scoped_generator.append(R"~~~(
  316. Vector<String> @cpp_name@;
  317. if (vm.argument_count() > @js_suffix@) {
  318. @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
  319. for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
  320. auto to_string_result = TRY(WebIDL::@to_string@(vm, vm.argument(i)));
  321. @cpp_name@.unchecked_append(move(to_string_result));
  322. }
  323. }
  324. )~~~");
  325. } else if (!optional) {
  326. if (!parameter.type->is_nullable()) {
  327. scoped_generator.append(R"~~~(
  328. @string_type@ @cpp_name@;
  329. if (!@legacy_null_to_empty_string@ || !@js_name@@js_suffix@.is_null()) {
  330. @cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
  331. }
  332. )~~~");
  333. } else {
  334. scoped_generator.append(R"~~~(
  335. Optional<@string_type@> @cpp_name@;
  336. if (!@js_name@@js_suffix@.is_nullish())
  337. @cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
  338. )~~~");
  339. }
  340. } else {
  341. bool may_be_null = !optional_default_value.has_value() || parameter.type->is_nullable() || optional_default_value.value() == "null";
  342. if (may_be_null) {
  343. scoped_generator.append(R"~~~(
  344. Optional<@string_type@> @cpp_name@;
  345. )~~~");
  346. } else {
  347. scoped_generator.append(R"~~~(
  348. @string_type@ @cpp_name@;
  349. )~~~");
  350. }
  351. if (parameter.type->is_nullable()) {
  352. scoped_generator.append(R"~~~(
  353. if (!@js_name@@js_suffix@.is_undefined()) {
  354. if (!@js_name@@js_suffix@.is_null())
  355. @cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
  356. })~~~");
  357. } else {
  358. scoped_generator.append(R"~~~(
  359. if (!@js_name@@js_suffix@.is_undefined()) {
  360. if (!@legacy_null_to_empty_string@ || !@js_name@@js_suffix@.is_null())
  361. @cpp_name@ = TRY(WebIDL::@to_string@(vm, @js_name@@js_suffix@));
  362. })~~~");
  363. }
  364. if (!may_be_null) {
  365. scoped_generator.append(R"~~~( else {
  366. @cpp_name@ = MUST(@string_type@::from_utf8(@parameter.optional_default_value@sv));
  367. }
  368. )~~~");
  369. } else {
  370. scoped_generator.append(R"~~~(
  371. )~~~");
  372. }
  373. }
  374. }
  375. static void generate_from_integral(SourceGenerator& scoped_generator, IDL::Type const& type)
  376. {
  377. struct TypeMap {
  378. StringView idl_type;
  379. StringView cpp_type;
  380. };
  381. static constexpr auto idl_type_map = to_array<TypeMap>({
  382. { "byte"sv, "WebIDL::Byte"sv },
  383. { "octet"sv, "WebIDL::Octet"sv },
  384. { "short"sv, "WebIDL::Short"sv },
  385. { "unsigned short"sv, "WebIDL::UnsignedShort"sv },
  386. { "long"sv, "WebIDL::Long"sv },
  387. { "unsigned long"sv, "WebIDL::UnsignedLong"sv },
  388. { "long long"sv, "double"sv },
  389. { "unsigned long long"sv, "double"sv },
  390. });
  391. auto it = find_if(idl_type_map.begin(), idl_type_map.end(), [&](auto const& entry) {
  392. return entry.idl_type == type.name();
  393. });
  394. VERIFY(it != idl_type_map.end());
  395. scoped_generator.set("cpp_type"sv, it->cpp_type);
  396. if (type.is_nullable()) {
  397. scoped_generator.append(R"~~~(
  398. @result_expression@ JS::Value(static_cast<@cpp_type@>(@value@.release_value()));
  399. )~~~");
  400. } else {
  401. scoped_generator.append(R"~~~(
  402. @result_expression@ JS::Value(static_cast<@cpp_type@>(@value@));
  403. )~~~");
  404. }
  405. }
  406. template<typename ParameterType>
  407. static void generate_to_integral(SourceGenerator& scoped_generator, ParameterType const& parameter, bool optional, Optional<ByteString> const& optional_default_value)
  408. {
  409. struct TypeMap {
  410. StringView idl_type;
  411. StringView cpp_type;
  412. };
  413. static constexpr auto idl_type_map = to_array<TypeMap>({
  414. { "boolean"sv, "bool"sv },
  415. { "byte"sv, "WebIDL::Byte"sv },
  416. { "octet"sv, "WebIDL::Octet"sv },
  417. { "short"sv, "WebIDL::Short"sv },
  418. { "unsigned short"sv, "WebIDL::UnsignedShort"sv },
  419. { "long"sv, "WebIDL::Long"sv },
  420. { "long long"sv, "WebIDL::LongLong"sv },
  421. { "unsigned long"sv, "WebIDL::UnsignedLong"sv },
  422. { "unsigned long long"sv, "WebIDL::UnsignedLongLong"sv },
  423. });
  424. auto it = find_if(idl_type_map.begin(), idl_type_map.end(), [&](auto const& entry) {
  425. return entry.idl_type == parameter.type->name();
  426. });
  427. VERIFY(it != idl_type_map.end());
  428. scoped_generator.set("cpp_type"sv, it->cpp_type);
  429. scoped_generator.set("enforce_range", parameter.extended_attributes.contains("EnforceRange") ? "Yes" : "No");
  430. scoped_generator.set("clamp", parameter.extended_attributes.contains("Clamp") ? "Yes" : "No");
  431. if ((!optional && !parameter.type->is_nullable()) || optional_default_value.has_value()) {
  432. scoped_generator.append(R"~~~(
  433. @cpp_type@ @cpp_name@;
  434. )~~~");
  435. } else {
  436. scoped_generator.append(R"~~~(
  437. Optional<@cpp_type@> @cpp_name@;
  438. )~~~");
  439. }
  440. if (parameter.type->is_nullable()) {
  441. scoped_generator.append(R"~~~(
  442. if (!@js_name@@js_suffix@.is_null() && !@js_name@@js_suffix@.is_undefined())
  443. )~~~");
  444. } else if (optional) {
  445. scoped_generator.append(R"~~~(
  446. if (!@js_name@@js_suffix@.is_undefined())
  447. )~~~");
  448. }
  449. if (it->cpp_type == "bool"sv) {
  450. scoped_generator.append(R"~~~(
  451. @cpp_name@ = @js_name@@js_suffix@.to_boolean();
  452. )~~~");
  453. } else {
  454. scoped_generator.append(R"~~~(
  455. @cpp_name@ = TRY(WebIDL::convert_to_int<@cpp_type@>(vm, @js_name@@js_suffix@, WebIDL::EnforceRange::@enforce_range@, WebIDL::Clamp::@clamp@));
  456. )~~~");
  457. }
  458. if (optional_default_value.has_value()) {
  459. scoped_generator.append(R"~~~(
  460. else
  461. @cpp_name@ = static_cast<@cpp_type@>(@parameter.optional_default_value@);
  462. )~~~");
  463. }
  464. }
  465. template<typename ParameterType>
  466. static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, ByteString const& js_name, ByteString const& js_suffix, ByteString const& cpp_name, IDL::Interface const& interface, bool legacy_null_to_empty_string = false, bool optional = false, Optional<ByteString> optional_default_value = {}, bool variadic = false, size_t recursion_depth = 0, bool string_to_fly_string = false)
  467. {
  468. auto scoped_generator = generator.fork();
  469. auto acceptable_cpp_name = make_input_acceptable_cpp(cpp_name);
  470. auto explicit_null = parameter.extended_attributes.contains("ExplicitNull");
  471. scoped_generator.set("cpp_name", acceptable_cpp_name);
  472. scoped_generator.set("js_name", js_name);
  473. scoped_generator.set("js_suffix", js_suffix);
  474. scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
  475. scoped_generator.set("string_type", string_to_fly_string ? "FlyString" : "String");
  476. scoped_generator.set("parameter.type.name", parameter.type->name());
  477. scoped_generator.set("parameter.name", parameter.name);
  478. if (explicit_null) {
  479. if (!IDL::is_platform_object(*parameter.type)) {
  480. dbgln("Parameter marked [ExplicitNull] in interface {} must be a platform object", interface.name);
  481. VERIFY_NOT_REACHED();
  482. }
  483. if (!optional || !parameter.type->is_nullable()) {
  484. dbgln("Parameter marked [ExplicitNull] in interface {} must be an optional and nullable type", interface.name);
  485. VERIFY_NOT_REACHED();
  486. }
  487. }
  488. if (optional_default_value.has_value())
  489. scoped_generator.set("parameter.optional_default_value", *optional_default_value);
  490. // FIXME: Add support for optional, variadic, nullable and default values to all types
  491. if (parameter.type->is_string()) {
  492. generate_to_string(scoped_generator, parameter, variadic, optional, optional_default_value);
  493. } else if (parameter.type->is_boolean() || parameter.type->is_integer()) {
  494. generate_to_integral(scoped_generator, parameter, optional, optional_default_value);
  495. } else if (parameter.type->name().is_one_of("EventListener", "NodeFilter")) {
  496. // FIXME: Replace this with support for callback interfaces. https://webidl.spec.whatwg.org/#idl-callback-interface
  497. if (parameter.type->name() == "EventListener")
  498. scoped_generator.set("cpp_type", "IDLEventListener");
  499. else
  500. scoped_generator.set("cpp_type", parameter.type->name());
  501. if (parameter.type->is_nullable()) {
  502. scoped_generator.append(R"~~~(
  503. @cpp_type@* @cpp_name@ = nullptr;
  504. if (!@js_name@@js_suffix@.is_nullish()) {
  505. if (!@js_name@@js_suffix@.is_object())
  506. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  507. auto callback_type = vm.heap().allocate<WebIDL::CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_realm());
  508. @cpp_name@ = TRY(throw_dom_exception_if_needed(vm, [&] { return @cpp_type@::create(realm, *callback_type); }));
  509. }
  510. )~~~");
  511. } else {
  512. scoped_generator.append(R"~~~(
  513. if (!@js_name@@js_suffix@.is_object())
  514. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  515. auto callback_type = vm.heap().allocate<WebIDL::CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_realm());
  516. auto @cpp_name@ = adopt_ref(*new @cpp_type@(callback_type));
  517. )~~~");
  518. }
  519. } else if (IDL::is_platform_object(*parameter.type)) {
  520. if (!parameter.type->is_nullable()) {
  521. if (!optional) {
  522. scoped_generator.append(R"~~~(
  523. if (!@js_name@@js_suffix@.is_object() || !is<@parameter.type.name@>(@js_name@@js_suffix@.as_object()))
  524. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  525. auto& @cpp_name@ = static_cast<@parameter.type.name@&>(@js_name@@js_suffix@.as_object());
  526. )~~~");
  527. } else {
  528. scoped_generator.append(R"~~~(
  529. GC::Ptr<@parameter.type.name@> @cpp_name@;
  530. if (!@js_name@@js_suffix@.is_undefined()) {
  531. if (!@js_name@@js_suffix@.is_object() || !is<@parameter.type.name@>(@js_name@@js_suffix@.as_object()))
  532. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  533. @cpp_name@ = static_cast<@parameter.type.name@&>(@js_name@@js_suffix@.as_object());
  534. }
  535. )~~~");
  536. }
  537. } else {
  538. if (explicit_null) {
  539. scoped_generator.append(R"~~~(
  540. Optional<GC::Ptr<@parameter.type.name@>> @cpp_name@;
  541. if (maybe_@js_name@@js_suffix@.has_value()) {
  542. auto @js_name@@js_suffix@ = maybe_@js_name@@js_suffix@.release_value();
  543. )~~~");
  544. } else {
  545. scoped_generator.append(R"~~~(
  546. GC::Ptr<@parameter.type.name@> @cpp_name@;
  547. )~~~");
  548. }
  549. scoped_generator.append(R"~~~(
  550. if (!@js_name@@js_suffix@.is_nullish()) {
  551. if (!@js_name@@js_suffix@.is_object() || !is<@parameter.type.name@>(@js_name@@js_suffix@.as_object()))
  552. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  553. @cpp_name@ = &static_cast<@parameter.type.name@&>(@js_name@@js_suffix@.as_object());
  554. }
  555. )~~~");
  556. if (explicit_null) {
  557. scoped_generator.append(R"~~~(
  558. }
  559. )~~~");
  560. }
  561. }
  562. } else if (parameter.type->is_floating_point()) {
  563. if (parameter.type->name() == "unrestricted float") {
  564. scoped_generator.set("parameter.type.name", "float");
  565. } else if (parameter.type->name() == "unrestricted double") {
  566. scoped_generator.set("parameter.type.name", "double");
  567. }
  568. bool is_wrapped_in_optional_type = false;
  569. if (!optional) {
  570. scoped_generator.append(R"~~~(
  571. @parameter.type.name@ @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
  572. )~~~");
  573. } else {
  574. if (optional_default_value.has_value() && optional_default_value != "null"sv) {
  575. scoped_generator.append(R"~~~(
  576. @parameter.type.name@ @cpp_name@;
  577. )~~~");
  578. } else {
  579. is_wrapped_in_optional_type = true;
  580. scoped_generator.append(R"~~~(
  581. Optional<@parameter.type.name@> @cpp_name@;
  582. )~~~");
  583. }
  584. scoped_generator.append(R"~~~(
  585. if (!@js_name@@js_suffix@.is_undefined())
  586. @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
  587. )~~~");
  588. if (optional_default_value.has_value() && optional_default_value.value() != "null"sv) {
  589. scoped_generator.append(R"~~~(
  590. else
  591. @cpp_name@ = @parameter.optional_default_value@;
  592. )~~~");
  593. } else {
  594. scoped_generator.append(R"~~~(
  595. )~~~");
  596. }
  597. }
  598. if (parameter.type->is_restricted_floating_point()) {
  599. if (is_wrapped_in_optional_type) {
  600. scoped_generator.append(R"~~~(
  601. if (@cpp_name@.has_value() && (isinf(*@cpp_name@) || isnan(*@cpp_name@))) {
  602. return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidRestrictedFloatingPointParameter, "@parameter.name@");
  603. }
  604. )~~~");
  605. } else {
  606. scoped_generator.append(R"~~~(
  607. if (isinf(@cpp_name@) || isnan(@cpp_name@)) {
  608. return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidRestrictedFloatingPointParameter, "@parameter.name@");
  609. }
  610. )~~~");
  611. }
  612. }
  613. } else if (parameter.type->name() == "Promise") {
  614. // https://webidl.spec.whatwg.org/#js-promise
  615. scoped_generator.append(R"~~~(
  616. // 1. Let promiseCapability be ? NewPromiseCapability(%Promise%).
  617. auto promise_capability = TRY(JS::new_promise_capability(vm, realm.intrinsics().promise_constructor()));
  618. // 2. Perform ? Call(promiseCapability.[[Resolve]], undefined, « V »).
  619. TRY(JS::call(vm, *promise_capability->resolve(), JS::js_undefined(), @js_name@@js_suffix@));
  620. // 3. Return promiseCapability.
  621. auto @cpp_name@ = GC::make_root(promise_capability);
  622. )~~~");
  623. } else if (parameter.type->name() == "object") {
  624. if (parameter.type->is_nullable()) {
  625. scoped_generator.append(R"~~~(
  626. Optional<GC::Root<JS::Object>> @cpp_name@;
  627. if (!@js_name@@js_suffix@.is_null() && !@js_name@@js_suffix@.is_undefined())
  628. @cpp_name@ = GC::make_root(TRY(@js_name@@js_suffix@.to_object(vm)));
  629. )~~~");
  630. } else if (optional) {
  631. scoped_generator.append(R"~~~(
  632. Optional<GC::Root<JS::Object>> @cpp_name@;
  633. if (!@js_name@@js_suffix@.is_undefined())
  634. @cpp_name@ = GC::make_root(TRY(@js_name@@js_suffix@.to_object(vm)));
  635. )~~~");
  636. } else {
  637. scoped_generator.append(R"~~~(
  638. auto @cpp_name@ = GC::make_root(TRY(@js_name@@js_suffix@.to_object(vm)));
  639. )~~~");
  640. }
  641. } else if (is_javascript_builtin(parameter.type) || parameter.type->name() == "BufferSource"sv) {
  642. if (optional) {
  643. scoped_generator.append(R"~~~(
  644. Optional<GC::Root<WebIDL::BufferSource>> @cpp_name@;
  645. if (!@js_name@@js_suffix@.is_undefined()) {
  646. )~~~");
  647. } else {
  648. scoped_generator.append(R"~~~(
  649. GC::Root<WebIDL::BufferSource> @cpp_name@;
  650. )~~~");
  651. }
  652. scoped_generator.append(R"~~~(
  653. if (!@js_name@@js_suffix@.is_object() || !(is<JS::TypedArrayBase>(@js_name@@js_suffix@.as_object()) || is<JS::ArrayBuffer>(@js_name@@js_suffix@.as_object()) || is<JS::DataView>(@js_name@@js_suffix@.as_object())))
  654. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  655. @cpp_name@ = GC::make_root(realm.create<WebIDL::BufferSource>(@js_name@@js_suffix@.as_object()));
  656. )~~~");
  657. if (optional) {
  658. scoped_generator.append(R"~~~(
  659. }
  660. )~~~");
  661. }
  662. } else if (parameter.type->name() == "ArrayBufferView") {
  663. scoped_generator.append(R"~~~(
  664. GC::Root<WebIDL::ArrayBufferView> @cpp_name@;
  665. )~~~");
  666. if (parameter.type->is_nullable()) {
  667. scoped_generator.append(R"~~~(
  668. if (!@js_name@@js_suffix@.is_null() && !@js_name@@js_suffix@.is_undefined()) {
  669. )~~~");
  670. }
  671. scoped_generator.append(R"~~~(
  672. if (!@js_name@@js_suffix@.is_object() || !(is<JS::TypedArrayBase>(@js_name@@js_suffix@.as_object()) || is<JS::DataView>(@js_name@@js_suffix@.as_object())))
  673. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  674. @cpp_name@ = GC::make_root(realm.create<WebIDL::ArrayBufferView>(@js_name@@js_suffix@.as_object()));
  675. )~~~");
  676. if (parameter.type->is_nullable()) {
  677. scoped_generator.append(R"~~~(
  678. }
  679. )~~~");
  680. }
  681. if (optional) {
  682. scoped_generator.append(R"~~~(
  683. }
  684. )~~~");
  685. }
  686. } else if (parameter.type->name() == "any") {
  687. if (variadic) {
  688. scoped_generator.append(R"~~~(
  689. GC::MarkedVector<JS::Value> @cpp_name@ { vm.heap() };
  690. if (vm.argument_count() > @js_suffix@) {
  691. @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
  692. for (size_t i = @js_suffix@; i < vm.argument_count(); ++i)
  693. @cpp_name@.unchecked_append(vm.argument(i));
  694. }
  695. )~~~");
  696. } else if (!optional) {
  697. scoped_generator.append(R"~~~(
  698. auto @cpp_name@ = @js_name@@js_suffix@;
  699. )~~~");
  700. } else {
  701. scoped_generator.append(R"~~~(
  702. JS::Value @cpp_name@ = JS::js_undefined();
  703. if (!@js_name@@js_suffix@.is_undefined())
  704. @cpp_name@ = @js_name@@js_suffix@;
  705. )~~~");
  706. if (optional_default_value.has_value()) {
  707. if (optional_default_value == "null") {
  708. scoped_generator.append(R"~~~(
  709. else
  710. @cpp_name@ = JS::js_null();
  711. )~~~");
  712. } else if (optional_default_value->to_number<int>().has_value() || optional_default_value->to_number<unsigned>().has_value()) {
  713. scoped_generator.append(R"~~~(
  714. else
  715. @cpp_name@ = JS::Value(@parameter.optional_default_value@);
  716. )~~~");
  717. } else {
  718. TODO();
  719. }
  720. }
  721. }
  722. } else if (interface.enumerations.contains(parameter.type->name())) {
  723. auto enum_generator = scoped_generator.fork();
  724. auto& enumeration = interface.enumerations.find(parameter.type->name())->value;
  725. StringView enum_member_name;
  726. if (optional_default_value.has_value()) {
  727. VERIFY(optional_default_value->length() >= 2 && (*optional_default_value)[0] == '"' && (*optional_default_value)[optional_default_value->length() - 1] == '"');
  728. enum_member_name = optional_default_value->substring_view(1, optional_default_value->length() - 2);
  729. } else {
  730. enum_member_name = enumeration.first_member;
  731. }
  732. auto default_value_cpp_name = enumeration.translated_cpp_names.get(enum_member_name);
  733. VERIFY(default_value_cpp_name.has_value());
  734. enum_generator.set("enum.default.cpp_value", *default_value_cpp_name);
  735. enum_generator.set("js_name.as_string", ByteString::formatted("{}{}_string", enum_generator.get("js_name"sv), enum_generator.get("js_suffix"sv)));
  736. enum_generator.append(R"~~~(
  737. @parameter.type.name@ @cpp_name@ { @parameter.type.name@::@enum.default.cpp_value@ };
  738. )~~~");
  739. if (optional) {
  740. enum_generator.append(R"~~~(
  741. if (!@js_name@@js_suffix@.is_undefined()) {
  742. )~~~");
  743. }
  744. enum_generator.append(R"~~~(
  745. auto @js_name.as_string@ = TRY(@js_name@@js_suffix@.to_string(vm));
  746. )~~~");
  747. auto first = true;
  748. VERIFY(enumeration.translated_cpp_names.size() >= 1);
  749. for (auto& it : enumeration.translated_cpp_names) {
  750. enum_generator.set("enum.alt.name", it.key);
  751. enum_generator.set("enum.alt.value", it.value);
  752. enum_generator.set("else", first ? "" : "else ");
  753. first = false;
  754. enum_generator.append(R"~~~(
  755. @else@if (@js_name.as_string@ == "@enum.alt.name@"sv)
  756. @cpp_name@ = @parameter.type.name@::@enum.alt.value@;
  757. )~~~");
  758. }
  759. // NOTE: Attribute setters return undefined instead of throwing when the string doesn't match an enum value.
  760. if constexpr (!IsSame<Attribute, RemoveConst<ParameterType>>) {
  761. enum_generator.append(R"~~~(
  762. else
  763. return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidEnumerationValue, @js_name.as_string@, "@parameter.type.name@");
  764. )~~~");
  765. } else {
  766. enum_generator.append(R"~~~(
  767. else
  768. return JS::js_undefined();
  769. )~~~");
  770. }
  771. if (optional) {
  772. enum_generator.append(R"~~~(
  773. }
  774. )~~~");
  775. }
  776. } else if (interface.dictionaries.contains(parameter.type->name())) {
  777. if (optional_default_value.has_value() && optional_default_value != "{}")
  778. TODO();
  779. auto dictionary_generator = scoped_generator.fork();
  780. dictionary_generator.append(R"~~~(
  781. if (!@js_name@@js_suffix@.is_nullish() && !@js_name@@js_suffix@.is_object())
  782. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  783. @parameter.type.name@ @cpp_name@ {};
  784. )~~~");
  785. auto* current_dictionary = &interface.dictionaries.find(parameter.type->name())->value;
  786. // FIXME: This (i) is a hack to make sure we don't generate duplicate variable names.
  787. static auto i = 0;
  788. while (true) {
  789. for (auto& member : current_dictionary->members) {
  790. dictionary_generator.set("member_key", member.name);
  791. auto member_js_name = make_input_acceptable_cpp(member.name.to_snakecase());
  792. auto member_value_name = ByteString::formatted("{}_value_{}", member_js_name, i);
  793. auto member_property_value_name = ByteString::formatted("{}_property_value_{}", member_js_name, i);
  794. dictionary_generator.set("member_name", member_js_name);
  795. dictionary_generator.set("member_value_name", member_value_name);
  796. dictionary_generator.set("member_property_value_name", member_property_value_name);
  797. dictionary_generator.append(R"~~~(
  798. auto @member_property_value_name@ = JS::js_undefined();
  799. if (@js_name@@js_suffix@.is_object())
  800. @member_property_value_name@ = TRY(@js_name@@js_suffix@.as_object().get("@member_key@"));
  801. )~~~");
  802. if (member.required) {
  803. dictionary_generator.append(R"~~~(
  804. if (@member_property_value_name@.is_undefined())
  805. return vm.throw_completion<JS::TypeError>(JS::ErrorType::MissingRequiredProperty, "@member_key@");
  806. )~~~");
  807. } else if (!member.default_value.has_value()) {
  808. // Assume struct member is Optional<T> and _don't_ assign the generated default
  809. // value (e.g. first enum member) when the dictionary member is optional (i.e.
  810. // no `required` and doesn't have a default value).
  811. // This is needed so that "dictionary has member" checks work as expected.
  812. dictionary_generator.append(R"~~~(
  813. if (!@member_property_value_name@.is_undefined()) {
  814. )~~~");
  815. }
  816. generate_to_cpp(dictionary_generator, member, member_property_value_name, "", member_value_name, interface, member.extended_attributes.contains("LegacyNullToEmptyString"), !member.required, member.default_value);
  817. bool may_be_null = !optional_default_value.has_value() || parameter.type->is_nullable() || optional_default_value.value() == "null";
  818. if (member.type->is_string() && optional && may_be_null) {
  819. dictionary_generator.append(R"~~~(
  820. if (@member_value_name@.has_value())
  821. @cpp_name@.@member_name@ = @member_value_name@.release_value();
  822. )~~~");
  823. } else {
  824. dictionary_generator.append(R"~~~(
  825. @cpp_name@.@member_name@ = @member_value_name@;
  826. )~~~");
  827. }
  828. if (!member.required && !member.default_value.has_value()) {
  829. dictionary_generator.append(R"~~~(
  830. }
  831. )~~~");
  832. }
  833. i++;
  834. }
  835. if (current_dictionary->parent_name.is_empty())
  836. break;
  837. VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
  838. current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
  839. }
  840. } else if (interface.callback_functions.contains(parameter.type->name())) {
  841. // https://webidl.spec.whatwg.org/#es-callback-function
  842. auto callback_function_generator = scoped_generator.fork();
  843. auto& callback_function = interface.callback_functions.find(parameter.type->name())->value;
  844. if (callback_function.return_type->is_object() && callback_function.return_type->name() == "Promise")
  845. callback_function_generator.set("operation_returns_promise", "WebIDL::OperationReturnsPromise::Yes");
  846. else
  847. callback_function_generator.set("operation_returns_promise", "WebIDL::OperationReturnsPromise::No");
  848. // An ECMAScript value V is converted to an IDL callback function type value by running the following algorithm:
  849. // 1. If the result of calling IsCallable(V) is false and the conversion to an IDL value is not being performed due to V being assigned to an attribute whose type is a nullable callback function that is annotated with [LegacyTreatNonObjectAsNull], then throw a TypeError.
  850. if (!parameter.type->is_nullable() && !callback_function.is_legacy_treat_non_object_as_null) {
  851. callback_function_generator.append(R"~~~(
  852. if (!@js_name@@js_suffix@.is_function())
  853. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, @js_name@@js_suffix@.to_string_without_side_effects());
  854. )~~~");
  855. }
  856. // 2. Return the IDL callback function type value that represents a reference to the same object that V represents, with the incumbent realm as the callback context.
  857. if (parameter.type->is_nullable() || callback_function.is_legacy_treat_non_object_as_null) {
  858. callback_function_generator.append(R"~~~(
  859. GC::Ptr<WebIDL::CallbackType> @cpp_name@;
  860. if (@js_name@@js_suffix@.is_object())
  861. @cpp_name@ = vm.heap().allocate<WebIDL::CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_realm(), @operation_returns_promise@);
  862. )~~~");
  863. } else {
  864. callback_function_generator.append(R"~~~(
  865. auto @cpp_name@ = vm.heap().allocate<WebIDL::CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_realm(), @operation_returns_promise@);
  866. )~~~");
  867. }
  868. } else if (parameter.type->name() == "sequence") {
  869. // https://webidl.spec.whatwg.org/#es-sequence
  870. auto sequence_generator = scoped_generator.fork();
  871. auto& parameterized_type = verify_cast<IDL::ParameterizedType>(*parameter.type);
  872. sequence_generator.set("recursion_depth", ByteString::number(recursion_depth));
  873. // An ECMAScript value V is converted to an IDL sequence<T> value as follows:
  874. // 1. If Type(V) is not Object, throw a TypeError.
  875. // 2. Let method be ? GetMethod(V, @@iterator).
  876. // 3. If method is undefined, throw a TypeError.
  877. // 4. Return the result of creating a sequence from V and method.
  878. if (optional) {
  879. auto sequence_cpp_type = idl_type_name_to_cpp_type(parameterized_type.parameters().first(), interface);
  880. sequence_generator.set("sequence.type", sequence_cpp_type.name);
  881. sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type));
  882. if (!optional_default_value.has_value()) {
  883. if (sequence_cpp_type.sequence_storage_type == IDL::SequenceStorageType::Vector) {
  884. sequence_generator.append(R"~~~(
  885. Optional<@sequence.storage_type@<@sequence.type@>> @cpp_name@;
  886. )~~~");
  887. } else {
  888. sequence_generator.append(R"~~~(
  889. Optional<@sequence.storage_type@> @cpp_name@;
  890. )~~~");
  891. }
  892. } else {
  893. if (optional_default_value != "[]")
  894. TODO();
  895. if (sequence_cpp_type.sequence_storage_type == IDL::SequenceStorageType::Vector) {
  896. sequence_generator.append(R"~~~(
  897. @sequence.storage_type@<@sequence.type@> @cpp_name@;
  898. )~~~");
  899. } else {
  900. sequence_generator.append(R"~~~(
  901. @sequence.storage_type@<@sequence.type@> @cpp_name@ { vm.heap() };
  902. )~~~");
  903. }
  904. }
  905. sequence_generator.append(R"~~~(
  906. if (!@js_name@@js_suffix@.is_undefined()) {
  907. )~~~");
  908. }
  909. sequence_generator.append(R"~~~(
  910. if (!@js_name@@js_suffix@.is_object())
  911. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  912. auto iterator_method@recursion_depth@ = TRY(@js_name@@js_suffix@.get_method(vm, vm.well_known_symbol_iterator()));
  913. if (!iterator_method@recursion_depth@)
  914. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotIterable, @js_name@@js_suffix@.to_string_without_side_effects());
  915. )~~~");
  916. parameterized_type.generate_sequence_from_iterable(sequence_generator, ByteString::formatted("{}{}", acceptable_cpp_name, optional ? "_non_optional" : ""), ByteString::formatted("{}{}", js_name, js_suffix), ByteString::formatted("iterator_method{}", recursion_depth), interface, recursion_depth + 1);
  917. if (optional) {
  918. sequence_generator.append(R"~~~(
  919. @cpp_name@ = move(@cpp_name@_non_optional);
  920. }
  921. )~~~");
  922. }
  923. } else if (parameter.type->name() == "record") {
  924. // https://webidl.spec.whatwg.org/#es-record
  925. auto record_generator = scoped_generator.fork();
  926. auto& parameterized_type = verify_cast<IDL::ParameterizedType>(*parameter.type);
  927. record_generator.set("recursion_depth", ByteString::number(recursion_depth));
  928. // A record can only have two types: key type and value type.
  929. VERIFY(parameterized_type.parameters().size() == 2);
  930. // A record only allows the key to be a string.
  931. VERIFY(parameterized_type.parameters()[0]->is_string());
  932. // An ECMAScript value O is converted to an IDL record<K, V> value as follows:
  933. // 1. If Type(O) is not Object, throw a TypeError.
  934. // 2. Let result be a new empty instance of record<K, V>.
  935. // 3. Let keys be ? O.[[OwnPropertyKeys]]().
  936. // 4. For each key of keys:
  937. // 1. Let desc be ? O.[[GetOwnProperty]](key).
  938. // 2. If desc is not undefined and desc.[[Enumerable]] is true:
  939. // 1. Let typedKey be key converted to an IDL value of type K.
  940. // 2. Let value be ? Get(O, key).
  941. // 3. Let typedValue be value converted to an IDL value of type V.
  942. // 4. Set result[typedKey] to typedValue.
  943. // 5. Return result.
  944. auto record_cpp_type = IDL::idl_type_name_to_cpp_type(parameterized_type, interface);
  945. record_generator.set("record.type", record_cpp_type.name);
  946. // If this is a recursive call to generate_to_cpp, assume that the caller has already handled converting the JS value to an object for us.
  947. // This affects record types in unions for example.
  948. if (recursion_depth == 0) {
  949. record_generator.append(R"~~~(
  950. if (!@js_name@@js_suffix@.is_object())
  951. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  952. auto& @js_name@@js_suffix@_object = @js_name@@js_suffix@.as_object();
  953. )~~~");
  954. }
  955. record_generator.append(R"~~~(
  956. @record.type@ @cpp_name@;
  957. auto record_keys@recursion_depth@ = TRY(@js_name@@js_suffix@_object.internal_own_property_keys());
  958. for (auto& key@recursion_depth@ : record_keys@recursion_depth@) {
  959. auto property_key@recursion_depth@ = MUST(JS::PropertyKey::from_value(vm, key@recursion_depth@));
  960. auto descriptor@recursion_depth@ = TRY(@js_name@@js_suffix@_object.internal_get_own_property(property_key@recursion_depth@));
  961. if (!descriptor@recursion_depth@.has_value() || !descriptor@recursion_depth@->enumerable.has_value() || !descriptor@recursion_depth@->enumerable.value())
  962. continue;
  963. )~~~");
  964. IDL::Parameter key_parameter { .type = parameterized_type.parameters()[0], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  965. generate_to_cpp(record_generator, key_parameter, "key", ByteString::number(recursion_depth), ByteString::formatted("typed_key{}", recursion_depth), interface, false, false, {}, false, recursion_depth + 1);
  966. record_generator.append(R"~~~(
  967. auto value@recursion_depth@ = TRY(@js_name@@js_suffix@_object.get(property_key@recursion_depth@));
  968. )~~~");
  969. // FIXME: Record value types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here.
  970. IDL::Parameter value_parameter { .type = parameterized_type.parameters()[1], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  971. generate_to_cpp(record_generator, value_parameter, "value", ByteString::number(recursion_depth), ByteString::formatted("typed_value{}", recursion_depth), interface, false, false, {}, false, recursion_depth + 1);
  972. record_generator.append(R"~~~(
  973. @cpp_name@.set(typed_key@recursion_depth@, typed_value@recursion_depth@);
  974. }
  975. )~~~");
  976. } else if (is<IDL::UnionType>(*parameter.type)) {
  977. // https://webidl.spec.whatwg.org/#es-union
  978. auto union_generator = scoped_generator.fork();
  979. auto& union_type = verify_cast<IDL::UnionType>(*parameter.type);
  980. union_generator.set("union_type", union_type_to_variant(union_type, interface));
  981. union_generator.set("recursion_depth", ByteString::number(recursion_depth));
  982. // NOTE: This is handled out here as we need the dictionary conversion code for the {} optional default value.
  983. // 3. Let types be the flattened member types of the union type.
  984. auto types = union_type.flattened_member_types();
  985. RefPtr<Type const> dictionary_type;
  986. for (auto& dictionary : interface.dictionaries) {
  987. for (auto& type : types) {
  988. if (type->name() == dictionary.key) {
  989. dictionary_type = type;
  990. break;
  991. }
  992. }
  993. if (dictionary_type)
  994. break;
  995. }
  996. if (dictionary_type) {
  997. auto dictionary_generator = union_generator.fork();
  998. dictionary_generator.set("dictionary.type", dictionary_type->name());
  999. // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic.
  1000. dictionary_generator.append(R"~~~(
  1001. auto @js_name@@js_suffix@_to_dictionary = [&vm, &realm](JS::Value @js_name@@js_suffix@) -> JS::ThrowCompletionOr<@dictionary.type@> {
  1002. // This might be unused.
  1003. (void)realm;
  1004. )~~~");
  1005. IDL::Parameter dictionary_parameter { .type = *dictionary_type, .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  1006. generate_to_cpp(dictionary_generator, dictionary_parameter, js_name, js_suffix, "dictionary_union_type"sv, interface, false, false, {}, false, recursion_depth + 1);
  1007. dictionary_generator.append(R"~~~(
  1008. return dictionary_union_type;
  1009. };
  1010. )~~~");
  1011. }
  1012. // A lambda is used because Variants without "Empty" can't easily be default initialized.
  1013. // Plus, this would require the user of union types to always accept a Variant with an Empty type.
  1014. // Additionally, it handles the case of unconditionally throwing a TypeError at the end if none of the types match.
  1015. // This is because we cannot unconditionally throw in generate_to_cpp as generate_to_cpp is supposed to assign to a variable and then continue.
  1016. // Note that all the other types only throw on a condition.
  1017. // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic.
  1018. StringBuilder to_variant_captures;
  1019. to_variant_captures.append("&vm, &realm"sv);
  1020. if (dictionary_type)
  1021. to_variant_captures.append(ByteString::formatted(", &{}{}_to_dictionary", js_name, js_suffix));
  1022. union_generator.set("to_variant_captures", to_variant_captures.to_byte_string());
  1023. union_generator.append(R"~~~(
  1024. auto @js_name@@js_suffix@_to_variant = [@to_variant_captures@](JS::Value @js_name@@js_suffix@) -> JS::ThrowCompletionOr<@union_type@> {
  1025. // These might be unused.
  1026. (void)vm;
  1027. (void)realm;
  1028. )~~~");
  1029. // 1. If the union type includes undefined and V is undefined, then return the unique undefined value.
  1030. if (union_type.includes_undefined()) {
  1031. scoped_generator.append(R"~~~(
  1032. if (@js_name@@js_suffix@.is_undefined())
  1033. return Empty {};
  1034. )~~~");
  1035. }
  1036. // FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
  1037. if (union_type.includes_nullable_type()) {
  1038. // Implement me
  1039. } else if (dictionary_type) {
  1040. // 4. If V is null or undefined, then
  1041. // 4.1 If types includes a dictionary type, then return the result of converting V to that dictionary type.
  1042. union_generator.append(R"~~~(
  1043. if (@js_name@@js_suffix@.is_nullish())
  1044. return @union_type@ { TRY(@js_name@@js_suffix@_to_dictionary(@js_name@@js_suffix@)) };
  1045. )~~~");
  1046. }
  1047. bool includes_object = false;
  1048. for (auto& type : types) {
  1049. if (type->name() == "object") {
  1050. includes_object = true;
  1051. break;
  1052. }
  1053. }
  1054. // FIXME: Don't generate this if the union type doesn't include any object types.
  1055. union_generator.append(R"~~~(
  1056. if (@js_name@@js_suffix@.is_object()) {
  1057. [[maybe_unused]] auto& @js_name@@js_suffix@_object = @js_name@@js_suffix@.as_object();
  1058. )~~~");
  1059. bool includes_platform_object = false;
  1060. for (auto& type : types) {
  1061. if (IDL::is_platform_object(type)) {
  1062. includes_platform_object = true;
  1063. break;
  1064. }
  1065. }
  1066. if (includes_platform_object) {
  1067. // 5. If V is a platform object, then:
  1068. union_generator.append(R"~~~(
  1069. if (is<PlatformObject>(@js_name@@js_suffix@_object)) {
  1070. )~~~");
  1071. // NOTE: This codegen assumes that all union types are cells or values we can create a handle for.
  1072. // 1. If types includes an interface type that V implements, then return the IDL value that is a reference to the object V.
  1073. for (auto& type : types) {
  1074. if (!IDL::is_platform_object(type))
  1075. continue;
  1076. auto union_platform_object_type_generator = union_generator.fork();
  1077. union_platform_object_type_generator.set("platform_object_type", type->name());
  1078. union_platform_object_type_generator.append(R"~~~(
  1079. if (is<@platform_object_type@>(@js_name@@js_suffix@_object))
  1080. return GC::make_root(static_cast<@platform_object_type@&>(@js_name@@js_suffix@_object));
  1081. )~~~");
  1082. }
  1083. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  1084. if (includes_object) {
  1085. union_generator.append(R"~~~(
  1086. return GC::make_root(@js_name@@js_suffix@_object);
  1087. )~~~");
  1088. }
  1089. union_generator.append(R"~~~(
  1090. }
  1091. )~~~");
  1092. }
  1093. bool includes_window_proxy = false;
  1094. for (auto& type : types) {
  1095. if (type->name() == "WindowProxy"sv) {
  1096. includes_window_proxy = true;
  1097. break;
  1098. }
  1099. }
  1100. if (includes_window_proxy) {
  1101. union_generator.append(R"~~~(
  1102. if (is<WindowProxy>(@js_name@@js_suffix@_object))
  1103. return GC::make_root(static_cast<WindowProxy&>(@js_name@@js_suffix@_object));
  1104. )~~~");
  1105. }
  1106. // Note: This covers steps 6-8 for when Buffersource is in a union with a type other than "object".
  1107. // Since in that case, the return type would be Handle<BufferSource>, and not Handle<Object>.
  1108. if (any_of(types, [](auto const& type) { return type->name() == "BufferSource"; }) && !includes_object) {
  1109. union_generator.append(R"~~~(
  1110. if (is<JS::ArrayBuffer>(@js_name@@js_suffix@_object) || is<JS::DataView>(@js_name@@js_suffix@_object) || is<JS::TypedArrayBase>(@js_name@@js_suffix@_object)) {
  1111. GC::Ref<WebIDL::BufferSource> source_object = realm.create<WebIDL::BufferSource>(@js_name@@js_suffix@_object);
  1112. return GC::make_root(source_object);
  1113. }
  1114. )~~~");
  1115. }
  1116. // 6. If Type(V) is Object and V has an [[ArrayBufferData]] internal slot, then
  1117. // 1. If types includes ArrayBuffer, then return the result of converting V to ArrayBuffer.
  1118. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  1119. if (any_of(types, [](auto const& type) { return type->name() == "ArrayBuffer"; }) || includes_object) {
  1120. union_generator.append(R"~~~(
  1121. if (is<JS::ArrayBuffer>(@js_name@@js_suffix@_object))
  1122. return GC::make_root(@js_name@@js_suffix@_object);
  1123. )~~~");
  1124. }
  1125. // 7. If Type(V) is Object and V has a [[DataView]] internal slot, then:
  1126. // 1. If types includes DataView, then return the result of converting V to DataView.
  1127. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  1128. if (any_of(types, [](auto const& type) { return type->name() == "DataView"; }) || includes_object) {
  1129. union_generator.append(R"~~~(
  1130. if (is<JS::DataView>(@js_name@@js_suffix@_object))
  1131. return GC::make_root(@js_name@@js_suffix@_object);
  1132. )~~~");
  1133. }
  1134. // 8. If Type(V) is Object and V has a [[TypedArrayName]] internal slot, then:
  1135. // 1. If types includes a typed array type whose name is the value of V’s [[TypedArrayName]] internal slot, then return the result of converting V to that type.
  1136. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  1137. auto has_typed_array_name = any_of(types, [](auto const& type) {
  1138. return type->name().is_one_of("Int8Array"sv, "Int16Array"sv, "Int32Array"sv, "Uint8Array"sv, "Uint16Array"sv, "Uint32Array"sv, "Uint8ClampedArray"sv, "BigInt64Array"sv, "BigUint64Array", "Float16Array"sv, "Float32Array"sv, "Float64Array"sv);
  1139. });
  1140. if (has_typed_array_name || includes_object) {
  1141. union_generator.append(R"~~~(
  1142. if (is<JS::TypedArrayBase>(@js_name@@js_suffix@_object))
  1143. return GC::make_root(@js_name@@js_suffix@_object);
  1144. )~~~");
  1145. }
  1146. // 9. If IsCallable(V) is true, then:
  1147. // 1. If types includes a callback function type, then return the result of converting V to that callback function type.
  1148. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  1149. bool includes_callable = false;
  1150. for (auto const& type : types) {
  1151. if (type->name() == "Function"sv) {
  1152. includes_callable = true;
  1153. break;
  1154. }
  1155. }
  1156. if (includes_callable) {
  1157. union_generator.append(R"~~~(
  1158. if (@js_name@@js_suffix@_object.is_function())
  1159. return vm.heap().allocate<WebIDL::CallbackType>(@js_name@@js_suffix@.as_function(), HTML::incumbent_realm());
  1160. )~~~");
  1161. }
  1162. // 10. If Type(V) is Object, then:
  1163. // 1. If types includes a sequence type, then:
  1164. RefPtr<IDL::ParameterizedType const> sequence_type;
  1165. for (auto& type : types) {
  1166. if (type->name() == "sequence") {
  1167. sequence_type = verify_cast<IDL::ParameterizedType>(*type);
  1168. break;
  1169. }
  1170. }
  1171. if (sequence_type) {
  1172. // 1. Let method be ? GetMethod(V, @@iterator).
  1173. union_generator.append(R"~~~(
  1174. auto method = TRY(@js_name@@js_suffix@.get_method(vm, vm.well_known_symbol_iterator()));
  1175. )~~~");
  1176. // 2. If method is not undefined, return the result of creating a sequence of that type from V and method.
  1177. union_generator.append(R"~~~(
  1178. if (method) {
  1179. )~~~");
  1180. sequence_type->generate_sequence_from_iterable(union_generator, acceptable_cpp_name, ByteString::formatted("{}{}", js_name, js_suffix), "method", interface, recursion_depth + 1);
  1181. union_generator.append(R"~~~(
  1182. return @cpp_name@;
  1183. }
  1184. )~~~");
  1185. }
  1186. // FIXME: 2. If types includes a frozen array type, then
  1187. // 1. Let method be ? GetMethod(V, @@iterator).
  1188. // 2. If method is not undefined, return the result of creating a frozen array of that type from V and method.
  1189. // 3. If types includes a dictionary type, then return the result of converting V to that dictionary type.
  1190. if (dictionary_type) {
  1191. union_generator.append(R"~~~(
  1192. return @union_type@ { TRY(@js_name@@js_suffix@_to_dictionary(@js_name@@js_suffix@)) };
  1193. )~~~");
  1194. }
  1195. // 4. If types includes a record type, then return the result of converting V to that record type.
  1196. RefPtr<IDL::ParameterizedType const> record_type;
  1197. for (auto& type : types) {
  1198. if (type->name() == "record") {
  1199. record_type = verify_cast<IDL::ParameterizedType>(*type);
  1200. break;
  1201. }
  1202. }
  1203. if (record_type) {
  1204. IDL::Parameter record_parameter { .type = *record_type, .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  1205. generate_to_cpp(union_generator, record_parameter, js_name, js_suffix, "record_union_type"sv, interface, false, false, {}, false, recursion_depth + 1);
  1206. union_generator.append(R"~~~(
  1207. return record_union_type;
  1208. )~~~");
  1209. }
  1210. // FIXME: 5. If types includes a callback interface type, then return the result of converting V to that callback interface type.
  1211. // 6. If types includes object, then return the IDL value that is a reference to the object V.
  1212. if (includes_object) {
  1213. union_generator.append(R"~~~(
  1214. return @js_name@@js_suffix@_object;
  1215. )~~~");
  1216. }
  1217. // End of is_object.
  1218. union_generator.append(R"~~~(
  1219. }
  1220. )~~~");
  1221. // 11. If Type(V) is Boolean, then:
  1222. // 1. If types includes boolean, then return the result of converting V to boolean.
  1223. bool includes_boolean = false;
  1224. for (auto& type : types) {
  1225. if (type->name() == "boolean") {
  1226. includes_boolean = true;
  1227. break;
  1228. }
  1229. }
  1230. if (includes_boolean) {
  1231. union_generator.append(R"~~~(
  1232. if (@js_name@@js_suffix@.is_boolean())
  1233. return @union_type@ { @js_name@@js_suffix@.as_bool() };
  1234. )~~~");
  1235. }
  1236. RefPtr<IDL::Type const> numeric_type;
  1237. for (auto& type : types) {
  1238. if (type->is_numeric()) {
  1239. numeric_type = type;
  1240. break;
  1241. }
  1242. }
  1243. // 12. If Type(V) is Number, then:
  1244. // 1. If types includes a numeric type, then return the result of converting V to that numeric type.
  1245. if (numeric_type) {
  1246. union_generator.append(R"~~~(
  1247. if (@js_name@@js_suffix@.is_number()) {
  1248. )~~~");
  1249. // NOTE: generate_to_cpp doesn't use the parameter name.
  1250. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number.
  1251. IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1252. generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1);
  1253. union_generator.append(R"~~~(
  1254. return { @js_name@@js_suffix@_number };
  1255. }
  1256. )~~~");
  1257. }
  1258. // 13. If Type(V) is BigInt, then:
  1259. // 1. If types includes bigint, then return the result of converting V to bigint
  1260. bool includes_bigint = false;
  1261. for (auto& type : types) {
  1262. if (type->name() == "bigint") {
  1263. includes_bigint = true;
  1264. break;
  1265. }
  1266. }
  1267. if (includes_bigint) {
  1268. union_generator.append(R"~~~(
  1269. if (@js_name@@js_suffix@.is_bigint())
  1270. return @js_name@@js_suffix@.as_bigint();
  1271. )~~~");
  1272. }
  1273. RefPtr<IDL::Type const> string_type;
  1274. for (auto& type : types) {
  1275. if (type->is_string()) {
  1276. string_type = type;
  1277. break;
  1278. }
  1279. }
  1280. if (string_type) {
  1281. // 14. If types includes a string type, then return the result of converting V to that type.
  1282. // NOTE: Currently all string types are converted to String.
  1283. IDL::Parameter parameter { .type = *string_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1284. generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_string", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1);
  1285. union_generator.append(R"~~~(
  1286. return { @js_name@@js_suffix@_string };
  1287. )~~~");
  1288. } else if (numeric_type && includes_bigint) {
  1289. // 15. If types includes a numeric type and bigint, then return the result of converting V to either that numeric type or bigint.
  1290. // https://webidl.spec.whatwg.org/#converted-to-a-numeric-type-or-bigint
  1291. // NOTE: This algorithm is only used here.
  1292. // An ECMAScript value V is converted to an IDL numeric type T or bigint value by running the following algorithm:
  1293. // 1. Let x be ? ToNumeric(V).
  1294. // 2. If Type(x) is BigInt, then
  1295. // 1. Return the IDL bigint value that represents the same numeric value as x.
  1296. // 3. Assert: Type(x) is Number.
  1297. // 4. Return the result of converting x to T.
  1298. auto union_numeric_type_generator = union_generator.fork();
  1299. auto cpp_type = IDL::idl_type_name_to_cpp_type(*numeric_type, interface);
  1300. union_numeric_type_generator.set("numeric_type", cpp_type.name);
  1301. union_numeric_type_generator.append(R"~~~(
  1302. auto x = TRY(@js_name@@js_suffix@.to_numeric(vm));
  1303. if (x.is_bigint())
  1304. return x.as_bigint();
  1305. VERIFY(x.is_number());
  1306. )~~~");
  1307. // NOTE: generate_to_cpp doesn't use the parameter name.
  1308. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number.
  1309. IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1310. generate_to_cpp(union_numeric_type_generator, parameter, "x", ByteString::empty(), "x_number", interface, false, false, {}, false, recursion_depth + 1);
  1311. union_numeric_type_generator.append(R"~~~(
  1312. return x_number;
  1313. )~~~");
  1314. } else if (numeric_type) {
  1315. // 16. If types includes a numeric type, then return the result of converting V to that numeric type.
  1316. // NOTE: generate_to_cpp doesn't use the parameter name.
  1317. // NOTE: generate_to_cpp will use to_{u32,etc.} which uses to_number internally and will thus use TRY, but it cannot throw as we know we are dealing with a number.
  1318. IDL::Parameter parameter { .type = *numeric_type, .name = ByteString::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1319. generate_to_cpp(union_generator, parameter, js_name, js_suffix, ByteString::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1);
  1320. union_generator.append(R"~~~(
  1321. return { @js_name@@js_suffix@_number };
  1322. )~~~");
  1323. } else if (includes_boolean) {
  1324. // 17. If types includes boolean, then return the result of converting V to boolean.
  1325. union_generator.append(R"~~~(
  1326. return @union_type@ { @js_name@@js_suffix@.to_boolean() };
  1327. )~~~");
  1328. } else if (includes_bigint) {
  1329. // 18. If types includes bigint, then return the result of converting V to bigint.
  1330. union_generator.append(R"~~~(
  1331. return TRY(@js_name@@js_suffix@.to_bigint(vm));
  1332. )~~~");
  1333. } else {
  1334. // 19. Throw a TypeError.
  1335. // FIXME: Replace the error message with something more descriptive.
  1336. union_generator.append(R"~~~(
  1337. return vm.throw_completion<JS::TypeError>("No union types matched"sv);
  1338. )~~~");
  1339. }
  1340. // Close the lambda and then perform the conversion.
  1341. union_generator.append(R"~~~(
  1342. };
  1343. )~~~");
  1344. if (!variadic) {
  1345. if (!optional) {
  1346. union_generator.append(R"~~~(
  1347. @union_type@ @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1348. )~~~");
  1349. } else {
  1350. if (!optional_default_value.has_value()) {
  1351. union_generator.append(R"~~~(
  1352. Optional<@union_type@> @cpp_name@;
  1353. if (!@js_name@@js_suffix@.is_undefined())
  1354. @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1355. )~~~");
  1356. } else {
  1357. if (optional_default_value == "null"sv) {
  1358. union_generator.append(R"~~~(
  1359. Optional<@union_type@> @cpp_name@;
  1360. if (!@js_name@@js_suffix@.is_nullish())
  1361. @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1362. )~~~");
  1363. } else if (optional_default_value == "\"\"") {
  1364. union_generator.append(R"~~~(
  1365. @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? String {} : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1366. )~~~");
  1367. } else if (optional_default_value->starts_with("\""sv) && optional_default_value->ends_with("\""sv)) {
  1368. union_generator.set("default_string_value", optional_default_value.value());
  1369. union_generator.append(R"~~~(
  1370. @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? MUST(String::from_utf8(@default_string_value@sv)) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1371. )~~~");
  1372. } else if (optional_default_value == "{}") {
  1373. VERIFY(dictionary_type);
  1374. union_generator.append(R"~~~(
  1375. @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? TRY(@js_name@@js_suffix@_to_dictionary(@js_name@@js_suffix@)) : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1376. )~~~");
  1377. } else if (optional_default_value->to_number<int>().has_value() || optional_default_value->to_number<unsigned>().has_value()) {
  1378. union_generator.append(R"~~~(
  1379. @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? @parameter.optional_default_value@ : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1380. )~~~");
  1381. } else {
  1382. TODO();
  1383. }
  1384. }
  1385. }
  1386. } else {
  1387. union_generator.append(R"~~~(
  1388. Vector<@union_type@> @cpp_name@;
  1389. if (vm.argument_count() > @js_suffix@) {
  1390. @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
  1391. for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
  1392. auto result = TRY(@js_name@@js_suffix@_to_variant(vm.argument(i)));
  1393. @cpp_name@.unchecked_append(move(result));
  1394. }
  1395. }
  1396. )~~~");
  1397. }
  1398. } else {
  1399. dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name());
  1400. VERIFY_NOT_REACHED();
  1401. }
  1402. }
  1403. static void generate_argument_count_check(SourceGenerator& generator, ByteString const& function_name, size_t argument_count)
  1404. {
  1405. if (argument_count == 0)
  1406. return;
  1407. auto argument_count_check_generator = generator.fork();
  1408. argument_count_check_generator.set("function.name", function_name);
  1409. argument_count_check_generator.set("function.nargs", ByteString::number(argument_count));
  1410. if (argument_count == 1) {
  1411. argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne");
  1412. argument_count_check_generator.set(".arg_count_suffix", "");
  1413. } else {
  1414. argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany");
  1415. argument_count_check_generator.set(".arg_count_suffix", ByteString::formatted(", \"{}\"", argument_count));
  1416. }
  1417. argument_count_check_generator.append(R"~~~(
  1418. if (vm.argument_count() < @function.nargs@)
  1419. return vm.throw_completion<JS::TypeError>(@.bad_arg_count@, "@function.name@"@.arg_count_suffix@);
  1420. )~~~");
  1421. }
  1422. static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter> const& parameters, StringBuilder& arguments_builder, IDL::Interface const& interface)
  1423. {
  1424. auto arguments_generator = generator.fork();
  1425. Vector<ByteString> parameter_names;
  1426. size_t argument_index = 0;
  1427. for (auto& parameter : parameters) {
  1428. auto parameter_name = make_input_acceptable_cpp(parameter.name.to_snakecase());
  1429. if (parameter.variadic) {
  1430. // GC::MarkedVector is non-copyable, and the implementations likely want ownership of the
  1431. // list, so we move() it into the parameter list.
  1432. parameter_names.append(ByteString::formatted("move({})", parameter_name));
  1433. } else {
  1434. parameter_names.append(move(parameter_name));
  1435. arguments_generator.set("argument.index", ByteString::number(argument_index));
  1436. if (parameter.extended_attributes.contains("ExplicitNull")) {
  1437. arguments_generator.set("argument.size", ByteString::number(argument_index + 1));
  1438. arguments_generator.append(R"~~~(
  1439. auto maybe_arg@argument.index@ = vm.argument_count() >= @argument.size@ ? Optional<JS::Value> { vm.argument(@argument.index@) } : OptionalNone {};
  1440. )~~~");
  1441. } else {
  1442. arguments_generator.append(R"~~~(
  1443. auto arg@argument.index@ = vm.argument(@argument.index@);
  1444. )~~~");
  1445. }
  1446. }
  1447. bool legacy_null_to_empty_string = parameter.extended_attributes.contains("LegacyNullToEmptyString");
  1448. bool fly_string = parameter.extended_attributes.contains("FlyString");
  1449. generate_to_cpp(generator, parameter, "arg", ByteString::number(argument_index), parameter.name.to_snakecase(), interface, legacy_null_to_empty_string, parameter.optional, parameter.optional_default_value, parameter.variadic, 0, fly_string);
  1450. ++argument_index;
  1451. }
  1452. arguments_builder.join(", "sv, parameter_names);
  1453. }
  1454. // https://webidl.spec.whatwg.org/#create-sequence-from-iterable
  1455. void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& generator, ByteString const& cpp_name, ByteString const& iterable_cpp_name, ByteString const& iterator_method_cpp_name, IDL::Interface const& interface, size_t recursion_depth) const
  1456. {
  1457. auto sequence_generator = generator.fork();
  1458. sequence_generator.set("cpp_name", cpp_name);
  1459. sequence_generator.set("iterable_cpp_name", iterable_cpp_name);
  1460. sequence_generator.set("iterator_method_cpp_name", iterator_method_cpp_name);
  1461. sequence_generator.set("recursion_depth", ByteString::number(recursion_depth));
  1462. auto sequence_cpp_type = idl_type_name_to_cpp_type(parameters().first(), interface);
  1463. sequence_generator.set("sequence.type", sequence_cpp_type.name);
  1464. sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type));
  1465. // To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
  1466. // 1. Let iter be ? GetIterator(iterable, sync, method).
  1467. // 2. Initialize i to be 0.
  1468. // 3. Repeat
  1469. // 1. Let next be ? IteratorStep(iter).
  1470. // 2. If next is false, then return an IDL sequence value of type sequence<T> of length i, where the value of the element at index j is Sj.
  1471. // 3. Let nextItem be ? IteratorValue(next).
  1472. // 4. Initialize Si to the result of converting nextItem to an IDL value of type T.
  1473. // 5. Set i to i + 1.
  1474. // FIXME: The WebIDL spec is out of date - it should be using GetIteratorFromMethod.
  1475. sequence_generator.append(R"~~~(
  1476. auto iterator@recursion_depth@ = TRY(JS::get_iterator_from_method(vm, @iterable_cpp_name@, *@iterator_method_cpp_name@));
  1477. )~~~");
  1478. if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::Vector) {
  1479. sequence_generator.append(R"~~~(
  1480. @sequence.storage_type@<@sequence.type@> @cpp_name@;
  1481. )~~~");
  1482. } else {
  1483. sequence_generator.append(R"~~~(
  1484. @sequence.storage_type@<@sequence.type@> @cpp_name@ { vm.heap() };
  1485. )~~~");
  1486. }
  1487. sequence_generator.append(R"~~~(
  1488. for (;;) {
  1489. auto next@recursion_depth@ = TRY(JS::iterator_step(vm, iterator@recursion_depth@));
  1490. if (!next@recursion_depth@)
  1491. break;
  1492. auto next_item@recursion_depth@ = TRY(JS::iterator_value(vm, *next@recursion_depth@));
  1493. )~~~");
  1494. // FIXME: Sequences types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here.
  1495. IDL::Parameter parameter { .type = parameters().first(), .name = iterable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  1496. generate_to_cpp(sequence_generator, parameter, "next_item", ByteString::number(recursion_depth), ByteString::formatted("sequence_item{}", recursion_depth), interface, false, false, {}, false, recursion_depth);
  1497. sequence_generator.append(R"~~~(
  1498. @cpp_name@.append(sequence_item@recursion_depth@);
  1499. }
  1500. )~~~");
  1501. }
  1502. enum class WrappingReference {
  1503. No,
  1504. Yes,
  1505. };
  1506. static void generate_wrap_statement(SourceGenerator& generator, ByteString const& value, IDL::Type const& type, IDL::Interface const& interface, StringView result_expression, WrappingReference wrapping_reference = WrappingReference::No, size_t recursion_depth = 0)
  1507. {
  1508. auto scoped_generator = generator.fork();
  1509. scoped_generator.set("value", value);
  1510. if (!libweb_interface_namespaces.span().contains_slow(type.name())) {
  1511. if (is_javascript_builtin(type))
  1512. scoped_generator.set("type", ByteString::formatted("JS::{}", type.name()));
  1513. else
  1514. scoped_generator.set("type", type.name());
  1515. } else {
  1516. // e.g. Document.getSelection which returns Selection, which is in the Selection namespace.
  1517. StringBuilder builder;
  1518. builder.append(type.name());
  1519. builder.append("::"sv);
  1520. builder.append(type.name());
  1521. scoped_generator.set("type", builder.to_byte_string());
  1522. }
  1523. scoped_generator.set("result_expression", result_expression);
  1524. scoped_generator.set("recursion_depth", ByteString::number(recursion_depth));
  1525. if (type.name() == "undefined") {
  1526. scoped_generator.append(R"~~~(
  1527. @result_expression@ JS::js_undefined();
  1528. )~~~");
  1529. return;
  1530. }
  1531. if (type.is_nullable() && !is<UnionType>(type)) {
  1532. if (type.is_string()) {
  1533. scoped_generator.append(R"~~~(
  1534. if (!@value@.has_value()) {
  1535. @result_expression@ JS::js_null();
  1536. } else {
  1537. )~~~");
  1538. } else if (type.name() == "sequence") {
  1539. scoped_generator.append(R"~~~(
  1540. if (!@value@.has_value()) {
  1541. @result_expression@ JS::js_null();
  1542. } else {
  1543. )~~~");
  1544. } else if (type.is_primitive() || interface.enumerations.contains(type.name()) || interface.dictionaries.contains(type.name())) {
  1545. scoped_generator.append(R"~~~(
  1546. if (!@value@.has_value()) {
  1547. @result_expression@ JS::js_null();
  1548. } else {
  1549. )~~~");
  1550. } else {
  1551. scoped_generator.append(R"~~~(
  1552. if (!@value@) {
  1553. @result_expression@ JS::js_null();
  1554. } else {
  1555. )~~~");
  1556. }
  1557. }
  1558. if (type.is_string()) {
  1559. if (type.is_nullable()) {
  1560. scoped_generator.append(R"~~~(
  1561. @result_expression@ JS::PrimitiveString::create(vm, @value@.release_value());
  1562. )~~~");
  1563. } else {
  1564. scoped_generator.append(R"~~~(
  1565. @result_expression@ JS::PrimitiveString::create(vm, @value@);
  1566. )~~~");
  1567. }
  1568. } else if (type.name() == "sequence") {
  1569. // https://webidl.spec.whatwg.org/#es-sequence
  1570. auto& sequence_generic_type = verify_cast<IDL::ParameterizedType>(type);
  1571. scoped_generator.append(R"~~~(
  1572. auto new_array@recursion_depth@ = MUST(JS::Array::create(realm, 0));
  1573. )~~~");
  1574. if (!type.is_nullable()) {
  1575. scoped_generator.append(R"~~~(
  1576. for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@.size(); ++i@recursion_depth@) {
  1577. auto& element@recursion_depth@ = @value@.at(i@recursion_depth@);
  1578. )~~~");
  1579. } else {
  1580. scoped_generator.append(R"~~~(
  1581. auto& @value@_non_optional = @value@.value();
  1582. for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@_non_optional.size(); ++i@recursion_depth@) {
  1583. auto& element@recursion_depth@ = @value@_non_optional.at(i@recursion_depth@);
  1584. )~~~");
  1585. }
  1586. // If the type is a platform object we currently return a Vector<GC::Root<T>> from the
  1587. // C++ implementation, thus allowing us to unwrap the element (a handle) like below.
  1588. // This might need to change if we switch to a MarkedVector.
  1589. if (is_platform_object(sequence_generic_type.parameters().first())) {
  1590. scoped_generator.append(R"~~~(
  1591. auto* wrapped_element@recursion_depth@ = &(*element@recursion_depth@);
  1592. )~~~");
  1593. } else {
  1594. generate_wrap_statement(scoped_generator, ByteString::formatted("element{}", recursion_depth), sequence_generic_type.parameters().first(), interface, ByteString::formatted("auto wrapped_element{} =", recursion_depth), WrappingReference::Yes, recursion_depth + 1);
  1595. }
  1596. scoped_generator.append(R"~~~(
  1597. auto property_index@recursion_depth@ = JS::PropertyKey { i@recursion_depth@ };
  1598. MUST(new_array@recursion_depth@->create_data_property(property_index@recursion_depth@, wrapped_element@recursion_depth@));
  1599. }
  1600. @result_expression@ new_array@recursion_depth@;
  1601. )~~~");
  1602. } else if (type.name() == "boolean" || type.is_floating_point()) {
  1603. if (type.is_nullable()) {
  1604. scoped_generator.append(R"~~~(
  1605. @result_expression@ JS::Value(@value@.release_value());
  1606. )~~~");
  1607. } else {
  1608. scoped_generator.append(R"~~~(
  1609. @result_expression@ JS::Value(@value@);
  1610. )~~~");
  1611. }
  1612. } else if (type.is_integer()) {
  1613. generate_from_integral(scoped_generator, type);
  1614. } else if (type.name() == "Location" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") {
  1615. scoped_generator.append(R"~~~(
  1616. @result_expression@ @value@;
  1617. )~~~");
  1618. } else if (type.name() == "Promise") {
  1619. scoped_generator.append(R"~~~(
  1620. @result_expression@ GC::Ref { verify_cast<JS::Promise>(*@value@->promise()) };
  1621. )~~~");
  1622. } else if (type.name() == "ArrayBufferView" || type.name() == "BufferSource") {
  1623. scoped_generator.append(R"~~~(
  1624. @result_expression@ JS::Value(@value@->raw_object());
  1625. )~~~");
  1626. } else if (is<IDL::UnionType>(type)) {
  1627. auto& union_type = verify_cast<IDL::UnionType>(type);
  1628. auto union_types = union_type.flattened_member_types();
  1629. auto union_generator = scoped_generator.fork();
  1630. union_generator.append(R"~~~(
  1631. @result_expression@ @value@.visit(
  1632. )~~~");
  1633. for (size_t current_union_type_index = 0; current_union_type_index < union_types.size(); ++current_union_type_index) {
  1634. auto& current_union_type = union_types.at(current_union_type_index);
  1635. auto cpp_type = IDL::idl_type_name_to_cpp_type(current_union_type, interface);
  1636. union_generator.set("current_type", cpp_type.name);
  1637. union_generator.append(R"~~~(
  1638. [&vm, &realm]([[maybe_unused]] @current_type@ const& visited_union_value@recursion_depth@) -> JS::Value {
  1639. // These may be unused.
  1640. (void)vm;
  1641. (void)realm;
  1642. )~~~");
  1643. // NOTE: While we are using const&, the underlying type for wrappable types in unions is (Nonnull)RefPtr, which are not references.
  1644. generate_wrap_statement(union_generator, ByteString::formatted("visited_union_value{}", recursion_depth), current_union_type, interface, "return"sv, WrappingReference::No, recursion_depth + 1);
  1645. // End of current visit lambda.
  1646. // The last lambda cannot have a trailing comma on the closing brace, unless the type is nullable, where an extra lambda will be generated for the Empty case.
  1647. if (current_union_type_index != union_types.size() - 1 || type.is_nullable()) {
  1648. union_generator.append(R"~~~(
  1649. },
  1650. )~~~");
  1651. } else {
  1652. union_generator.append(R"~~~(
  1653. }
  1654. )~~~");
  1655. }
  1656. }
  1657. if (type.is_nullable()) {
  1658. union_generator.append(R"~~~(
  1659. [](Empty) -> JS::Value {
  1660. return JS::js_null();
  1661. }
  1662. )~~~");
  1663. }
  1664. // End of visit.
  1665. union_generator.append(R"~~~(
  1666. );
  1667. )~~~");
  1668. } else if (interface.enumerations.contains(type.name())) {
  1669. // Handle Enum? values, which were null-checked above
  1670. if (type.is_nullable())
  1671. scoped_generator.set("value", ByteString::formatted("{}.value()", value));
  1672. scoped_generator.append(R"~~~(
  1673. @result_expression@ JS::PrimitiveString::create(vm, Bindings::idl_enum_to_string(@value@));
  1674. )~~~");
  1675. } else if (interface.callback_functions.contains(type.name())) {
  1676. // https://webidl.spec.whatwg.org/#es-callback-function
  1677. auto& callback_function = interface.callback_functions.find(type.name())->value;
  1678. // The result of converting an IDL callback function type value to an ECMAScript value is a reference to the same object that the IDL callback function type value represents.
  1679. if (callback_function.is_legacy_treat_non_object_as_null && !type.is_nullable()) {
  1680. scoped_generator.append(R"~~~(
  1681. if (!@value@) {
  1682. @result_expression@ JS::js_null();
  1683. } else {
  1684. @result_expression@ @value@->callback;
  1685. }
  1686. )~~~");
  1687. } else {
  1688. scoped_generator.append(R"~~~(
  1689. @result_expression@ @value@->callback;
  1690. )~~~");
  1691. }
  1692. } else if (interface.dictionaries.contains(type.name())) {
  1693. // https://webidl.spec.whatwg.org/#es-dictionary
  1694. auto dictionary_generator = scoped_generator.fork();
  1695. dictionary_generator.append(R"~~~(
  1696. auto dictionary_object@recursion_depth@ = JS::Object::create(realm, realm.intrinsics().object_prototype());
  1697. )~~~");
  1698. auto* current_dictionary = &interface.dictionaries.find(type.name())->value;
  1699. while (true) {
  1700. for (auto& member : current_dictionary->members) {
  1701. dictionary_generator.set("member_key", member.name);
  1702. auto member_key_js_name = ByteString::formatted("{}{}", make_input_acceptable_cpp(member.name.to_snakecase()), recursion_depth);
  1703. dictionary_generator.set("member_name", member_key_js_name);
  1704. auto member_value_js_name = ByteString::formatted("{}_value", member_key_js_name);
  1705. dictionary_generator.set("member_value", member_value_js_name);
  1706. auto wrapped_value_name = ByteString::formatted("wrapped_{}", member_value_js_name);
  1707. dictionary_generator.set("wrapped_value_name", wrapped_value_name);
  1708. dictionary_generator.append(R"~~~(
  1709. JS::Value @wrapped_value_name@;
  1710. )~~~");
  1711. generate_wrap_statement(dictionary_generator, ByteString::formatted("{}{}{}", value, type.is_nullable() ? "->" : ".", member.name.to_snakecase()), member.type, interface, ByteString::formatted("{} =", wrapped_value_name), WrappingReference::No, recursion_depth + 1);
  1712. dictionary_generator.append(R"~~~(
  1713. MUST(dictionary_object@recursion_depth@->create_data_property("@member_key@", @wrapped_value_name@));
  1714. )~~~");
  1715. }
  1716. if (current_dictionary->parent_name.is_empty())
  1717. break;
  1718. VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
  1719. current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
  1720. }
  1721. dictionary_generator.append(R"~~~(
  1722. @result_expression@ dictionary_object@recursion_depth@;
  1723. )~~~");
  1724. } else if (type.name() == "object") {
  1725. scoped_generator.append(R"~~~(
  1726. @result_expression@ JS::Value(const_cast<JS::Object*>(@value@));
  1727. )~~~");
  1728. } else {
  1729. if (wrapping_reference == WrappingReference::No) {
  1730. scoped_generator.append(R"~~~(
  1731. @result_expression@ &const_cast<@type@&>(*@value@);
  1732. )~~~");
  1733. } else {
  1734. scoped_generator.append(R"~~~(
  1735. @result_expression@ &const_cast<@type@&>(@value@);
  1736. )~~~");
  1737. }
  1738. }
  1739. if (type.is_nullable() && !is<UnionType>(type)) {
  1740. scoped_generator.append(R"~~~(
  1741. }
  1742. )~~~");
  1743. }
  1744. }
  1745. enum class StaticFunction {
  1746. No,
  1747. Yes,
  1748. };
  1749. enum class IsConstructor {
  1750. No,
  1751. Yes
  1752. };
  1753. static void generate_return_statement(SourceGenerator& generator, IDL::Type const& return_type, IDL::Interface const& interface)
  1754. {
  1755. return generate_wrap_statement(generator, "retval", return_type, interface, "return"sv);
  1756. }
  1757. static void generate_variable_statement(SourceGenerator& generator, ByteString const& variable_name, IDL::Type const& value_type, ByteString const& value_name, IDL::Interface const& interface)
  1758. {
  1759. auto variable_generator = generator.fork();
  1760. variable_generator.set("variable_name", variable_name);
  1761. variable_generator.append(R"~~~(
  1762. JS::Value @variable_name@;
  1763. )~~~");
  1764. return generate_wrap_statement(generator, value_name, value_type, interface, ByteString::formatted("{} = ", variable_name));
  1765. }
  1766. static void generate_function(SourceGenerator& generator, IDL::Function const& function, StaticFunction is_static_function, ByteString const& class_name, ByteString const& interface_fully_qualified_name, IDL::Interface const& interface)
  1767. {
  1768. auto function_generator = generator.fork();
  1769. function_generator.set("class_name", class_name);
  1770. function_generator.set("interface_fully_qualified_name", interface_fully_qualified_name);
  1771. function_generator.set("function.name", function.name);
  1772. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(function.name.to_snakecase()));
  1773. function_generator.set("overload_suffix", function.is_overloaded ? ByteString::number(function.overload_index) : ByteString::empty());
  1774. if (function.extended_attributes.contains("ImplementedAs")) {
  1775. auto implemented_as = function.extended_attributes.get("ImplementedAs").value();
  1776. function_generator.set("function.cpp_name", implemented_as);
  1777. } else {
  1778. function_generator.set("function.cpp_name", make_input_acceptable_cpp(function.name.to_snakecase()));
  1779. }
  1780. function_generator.append(R"~~~(
  1781. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffix@)
  1782. {
  1783. WebIDL::log_trace(vm, "@class_name@::@function.name:snakecase@@overload_suffix@");
  1784. [[maybe_unused]] auto& realm = *vm.current_realm();
  1785. )~~~");
  1786. // NOTE: Create a wrapper lambda so that if the function steps return an exception, we can return that in a rejected promise.
  1787. if (function.return_type->name() == "Promise"sv) {
  1788. function_generator.append(R"~~~(
  1789. auto steps = [&realm, &vm]() -> JS::ThrowCompletionOr<GC::Ref<WebIDL::Promise>> {
  1790. (void)realm;
  1791. )~~~");
  1792. }
  1793. if (is_static_function == StaticFunction::No) {
  1794. function_generator.append(R"~~~(
  1795. auto* impl = TRY(impl_from(vm));
  1796. )~~~");
  1797. }
  1798. // Optimization: overloaded functions' arguments count is checked by the overload arbiter
  1799. if (!function.is_overloaded)
  1800. generate_argument_count_check(generator, function.name, function.shortest_length());
  1801. StringBuilder arguments_builder;
  1802. generate_arguments(generator, function.parameters, arguments_builder, interface);
  1803. function_generator.set(".arguments", arguments_builder.string_view());
  1804. if (is_static_function == StaticFunction::No) {
  1805. // For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
  1806. if (function.extended_attributes.contains("CEReactions")) {
  1807. // 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
  1808. function_generator.append(R"~~~(
  1809. auto& relevant_agent = HTML::relevant_agent(*impl);
  1810. auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
  1811. auto& reactions_stack = custom_data->custom_element_reactions_stack;
  1812. reactions_stack.element_queue_stack.append({});
  1813. )~~~");
  1814. }
  1815. if (!function.extended_attributes.contains("CEReactions")) {
  1816. function_generator.append(R"~~~(
  1817. [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@function.cpp_name@(@.arguments@); }));
  1818. )~~~");
  1819. } else {
  1820. // 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
  1821. // 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
  1822. // 4. Invoke custom element reactions in queue.
  1823. // 5. If an exception exception was thrown by the original steps, rethrow exception.
  1824. // 6. If a value value was returned from the original steps, return value.
  1825. function_generator.append(R"~~~(
  1826. auto retval_or_exception = throw_dom_exception_if_needed(vm, [&] { return impl->@function.cpp_name@(@.arguments@); });
  1827. auto queue = reactions_stack.element_queue_stack.take_last();
  1828. Bindings::invoke_custom_element_reactions(queue);
  1829. if (retval_or_exception.is_error())
  1830. return retval_or_exception.release_error();
  1831. [[maybe_unused]] auto retval = retval_or_exception.release_value();
  1832. )~~~");
  1833. }
  1834. } else {
  1835. // Make sure first argument for static functions is the Realm.
  1836. if (arguments_builder.is_empty())
  1837. function_generator.set(".arguments", "vm");
  1838. else
  1839. function_generator.set(".arguments", ByteString::formatted("vm, {}", arguments_builder.string_view()));
  1840. function_generator.append(R"~~~(
  1841. [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return @interface_fully_qualified_name@::@function.cpp_name@(@.arguments@); }));
  1842. )~~~");
  1843. }
  1844. if (function.return_type->name() == "Promise"sv) {
  1845. // https://webidl.spec.whatwg.org/#dfn-create-operation-function
  1846. // If we had an exception running the steps and are meant to return a Promise, wrap that exception in a rejected promise.
  1847. function_generator.append(R"~~~(
  1848. return retval;
  1849. };
  1850. auto maybe_retval = steps();
  1851. // And then, if an exception E was thrown:
  1852. // 1. If op has a return type that is a promise type, then return ! Call(%Promise.reject%, %Promise%, «E»).
  1853. // 2. Otherwise, end these steps and allow the exception to propagate.
  1854. // NOTE: We know that this is a Promise return type statically by the IDL.
  1855. if (maybe_retval.is_throw_completion())
  1856. return WebIDL::create_rejected_promise(realm, maybe_retval.error_value())->promise();
  1857. auto retval = maybe_retval.release_value();
  1858. )~~~");
  1859. }
  1860. generate_return_statement(generator, *function.return_type, interface);
  1861. function_generator.append(R"~~~(
  1862. }
  1863. )~~~");
  1864. }
  1865. // https://webidl.spec.whatwg.org/#compute-the-effective-overload-set
  1866. static Vector<EffectiveOverloadSet::Item> compute_the_effective_overload_set(auto const& overload_set)
  1867. {
  1868. // 1. Let S be an ordered set.
  1869. Vector<EffectiveOverloadSet::Item> overloads;
  1870. // 2. Let F be an ordered set with items as follows, according to the kind of effective overload set:
  1871. // Note: This is determined by the caller of generate_overload_arbiter()
  1872. // 3. Let maxarg be the maximum number of arguments the operations, legacy factory functions, or
  1873. // callback functions in F are declared to take. For variadic operations and legacy factory functions,
  1874. // the argument on which the ellipsis appears counts as a single argument.
  1875. auto overloaded_functions = overload_set.value;
  1876. auto maximum_arguments = 0;
  1877. for (auto const& function : overloaded_functions)
  1878. maximum_arguments = max(maximum_arguments, static_cast<int>(function.parameters.size()));
  1879. // 4. Let max be max(maxarg, N).
  1880. // NOTE: We don't do this step. `N` is a runtime value, so we just use `maxarg` here instead.
  1881. // Later, `generate_overload_arbiter()` produces individual overload sets for each possible N.
  1882. // 5. For each operation or extended attribute X in F:
  1883. auto overload_id = 0;
  1884. for (auto const& overload : overloaded_functions) {
  1885. // 1. Let arguments be the list of arguments X is declared to take.
  1886. auto const& arguments = overload.parameters;
  1887. // 2. Let n be the size of arguments.
  1888. int argument_count = (int)arguments.size();
  1889. // 3. Let types be a type list.
  1890. Vector<NonnullRefPtr<Type const>> types;
  1891. // 4. Let optionalityValues be an optionality list.
  1892. Vector<Optionality> optionality_values;
  1893. bool overload_is_variadic = false;
  1894. // 5. For each argument in arguments:
  1895. for (auto const& argument : arguments) {
  1896. // 1. Append the type of argument to types.
  1897. types.append(argument.type);
  1898. // 2. Append "variadic" to optionalityValues if argument is a final, variadic argument, "optional" if argument is optional, and "required" otherwise.
  1899. if (argument.variadic) {
  1900. optionality_values.append(Optionality::Variadic);
  1901. overload_is_variadic = true;
  1902. } else if (argument.optional) {
  1903. optionality_values.append(Optionality::Optional);
  1904. } else {
  1905. optionality_values.append(Optionality::Required);
  1906. }
  1907. }
  1908. // 6. Append the tuple (X, types, optionalityValues) to S.
  1909. overloads.empend(overload_id, types, optionality_values);
  1910. // 7. If X is declared to be variadic, then:
  1911. if (overload_is_variadic) {
  1912. // 1. For each i in the range n to max − 1, inclusive:
  1913. for (auto i = argument_count; i < maximum_arguments; ++i) {
  1914. // 1. Let t be a type list.
  1915. // 2. Let o be an optionality list.
  1916. // NOTE: We hold both of these in an Item instead.
  1917. EffectiveOverloadSet::Item item;
  1918. item.callable_id = overload_id;
  1919. // 3. For each j in the range 0 to n − 1, inclusive:
  1920. for (auto j = 0; j < argument_count; ++j) {
  1921. // 1. Append types[j] to t.
  1922. item.types.append(types[j]);
  1923. // 2. Append optionalityValues[j] to o.
  1924. item.optionality_values.append(optionality_values[j]);
  1925. }
  1926. // 4. For each j in the range n to i, inclusive:
  1927. for (auto j = argument_count; j <= i; ++j) {
  1928. // 1. Append types[n − 1] to t.
  1929. item.types.append(types[argument_count - 1]);
  1930. // 2. Append "variadic" to o.
  1931. item.optionality_values.append(Optionality::Variadic);
  1932. }
  1933. // 5. Append the tuple (X, t, o) to S.
  1934. overloads.append(move(item));
  1935. }
  1936. }
  1937. // 8. Let i be n − 1.
  1938. auto i = argument_count - 1;
  1939. // 9. While i ≥ 0:
  1940. while (i >= 0) {
  1941. // 1. If arguments[i] is not optional (i.e., it is not marked as "optional" and is not a final, variadic argument), then break.
  1942. if (!arguments[i].optional && !arguments[i].variadic)
  1943. break;
  1944. // 2. Let t be a type list.
  1945. // 3. Let o be an optionality list.
  1946. // NOTE: We hold both of these in an Item instead.
  1947. EffectiveOverloadSet::Item item;
  1948. item.callable_id = overload_id;
  1949. // 4. For each j in the range 0 to i − 1, inclusive:
  1950. for (auto j = 0; j < i; ++j) {
  1951. // 1. Append types[j] to t.
  1952. item.types.append(types[j]);
  1953. // 2. Append optionalityValues[j] to o.
  1954. item.optionality_values.append(optionality_values[j]);
  1955. }
  1956. // 5. Append the tuple (X, t, o) to S.
  1957. overloads.append(move(item));
  1958. // 6. Set i to i − 1.
  1959. --i;
  1960. }
  1961. overload_id++;
  1962. }
  1963. return overloads;
  1964. }
  1965. static ByteString generate_constructor_for_idl_type(Type const& type)
  1966. {
  1967. auto append_type_list = [](auto& builder, auto const& type_list) {
  1968. bool first = true;
  1969. for (auto const& child_type : type_list) {
  1970. if (first) {
  1971. first = false;
  1972. } else {
  1973. builder.append(", "sv);
  1974. }
  1975. builder.append(generate_constructor_for_idl_type(child_type));
  1976. }
  1977. };
  1978. switch (type.kind()) {
  1979. case Type::Kind::Plain:
  1980. return ByteString::formatted("make_ref_counted<IDL::Type>(\"{}\", {})", type.name(), type.is_nullable());
  1981. case Type::Kind::Parameterized: {
  1982. auto const& parameterized_type = type.as_parameterized();
  1983. StringBuilder builder;
  1984. builder.appendff("make_ref_counted<IDL::ParameterizedType>(\"{}\", {}, Vector<NonnullRefPtr<IDL::Type const>> {{", type.name(), type.is_nullable());
  1985. append_type_list(builder, parameterized_type.parameters());
  1986. builder.append("})"sv);
  1987. return builder.to_byte_string();
  1988. }
  1989. case Type::Kind::Union: {
  1990. auto const& union_type = type.as_union();
  1991. StringBuilder builder;
  1992. builder.appendff("make_ref_counted<IDL::UnionType>(\"{}\", {}, Vector<NonnullRefPtr<IDL::Type const>> {{", type.name(), type.is_nullable());
  1993. append_type_list(builder, union_type.member_types());
  1994. builder.append("})"sv);
  1995. return builder.to_byte_string();
  1996. }
  1997. }
  1998. VERIFY_NOT_REACHED();
  1999. }
  2000. // https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index
  2001. static size_t resolve_distinguishing_argument_index(Interface const& interface, Vector<EffectiveOverloadSet::Item> const& items, size_t argument_count)
  2002. {
  2003. for (auto argument_index = 0u; argument_index < argument_count; ++argument_index) {
  2004. bool found_indistinguishable = false;
  2005. for (auto first_item_index = 0u; first_item_index < items.size(); ++first_item_index) {
  2006. for (auto second_item_index = first_item_index + 1; second_item_index < items.size(); ++second_item_index) {
  2007. if (!items[first_item_index].types[argument_index]->is_distinguishable_from(interface, items[second_item_index].types[argument_index])) {
  2008. found_indistinguishable = true;
  2009. break;
  2010. }
  2011. }
  2012. if (found_indistinguishable)
  2013. break;
  2014. }
  2015. if (!found_indistinguishable)
  2016. return argument_index;
  2017. }
  2018. VERIFY_NOT_REACHED();
  2019. }
  2020. static void generate_dictionary_types(SourceGenerator& generator, Vector<ByteString> const& dictionary_types)
  2021. {
  2022. generator.append(R"~~~(
  2023. Vector<StringView> dictionary_types {
  2024. )~~~");
  2025. for (auto const& dictionary : dictionary_types) {
  2026. generator.append(" \"");
  2027. generator.append(dictionary);
  2028. generator.appendln("\"sv,");
  2029. }
  2030. generator.append("};\n");
  2031. }
  2032. static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, IDL::Interface const& interface, ByteString const& class_name, IsConstructor is_constructor)
  2033. {
  2034. auto function_generator = generator.fork();
  2035. if (is_constructor == IsConstructor::Yes)
  2036. function_generator.set("constructor_class", class_name);
  2037. else
  2038. function_generator.set("class_name", class_name);
  2039. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  2040. HashTable<ByteString> dictionary_types;
  2041. if (is_constructor == IsConstructor::Yes) {
  2042. function_generator.append(R"~~~(
  2043. JS::ThrowCompletionOr<GC::Ref<JS::Object>> @constructor_class@::construct(JS::FunctionObject& new_target)
  2044. {
  2045. auto& vm = this->vm();
  2046. WebIDL::log_trace(vm, "@constructor_class@::construct");
  2047. )~~~");
  2048. } else {
  2049. function_generator.append(R"~~~(
  2050. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
  2051. {
  2052. WebIDL::log_trace(vm, "@class_name@::@function.name:snakecase@");
  2053. )~~~");
  2054. }
  2055. function_generator.append(R"~~~(
  2056. Optional<IDL::EffectiveOverloadSet> effective_overload_set;
  2057. )~~~");
  2058. auto overloads_set = compute_the_effective_overload_set(overload_set);
  2059. auto maximum_argument_count = 0u;
  2060. for (auto const& overload : overloads_set)
  2061. maximum_argument_count = max(maximum_argument_count, overload.types.size());
  2062. function_generator.set("max_argument_count", ByteString::number(maximum_argument_count));
  2063. function_generator.appendln(" switch (min(@max_argument_count@, vm.argument_count())) {");
  2064. // Generate the effective overload set for each argument count.
  2065. // This skips part of the Overload Resolution Algorithm https://webidl.spec.whatwg.org/#es-overloads
  2066. // Namely, since that discards any overloads that don't have the exact number of arguments that were given,
  2067. // we simply only provide the overloads that do have that number of arguments.
  2068. for (auto argument_count = 0u; argument_count <= maximum_argument_count; ++argument_count) {
  2069. Vector<EffectiveOverloadSet::Item> effective_overload_set;
  2070. for (auto const& overload : overloads_set) {
  2071. if (overload.types.size() == argument_count)
  2072. effective_overload_set.append(overload);
  2073. }
  2074. if (effective_overload_set.size() == 0)
  2075. continue;
  2076. auto distinguishing_argument_index = 0u;
  2077. if (effective_overload_set.size() > 1)
  2078. distinguishing_argument_index = resolve_distinguishing_argument_index(interface, effective_overload_set, argument_count);
  2079. function_generator.set("current_argument_count", ByteString::number(argument_count));
  2080. function_generator.set("overload_count", ByteString::number(effective_overload_set.size()));
  2081. function_generator.appendln(R"~~~(
  2082. case @current_argument_count@: {
  2083. Vector<IDL::EffectiveOverloadSet::Item> overloads;
  2084. overloads.ensure_capacity(@overload_count@);
  2085. )~~~");
  2086. for (auto& overload : effective_overload_set) {
  2087. StringBuilder types_builder;
  2088. types_builder.append("Vector<NonnullRefPtr<IDL::Type const>> { "sv);
  2089. StringBuilder optionality_builder;
  2090. optionality_builder.append("Vector<IDL::Optionality> { "sv);
  2091. for (auto i = 0u; i < overload.types.size(); ++i) {
  2092. if (i > 0) {
  2093. types_builder.append(", "sv);
  2094. optionality_builder.append(", "sv);
  2095. }
  2096. auto const& type = overload.types[i];
  2097. if (interface.dictionaries.contains(type->name()))
  2098. dictionary_types.set(type->name());
  2099. types_builder.append(generate_constructor_for_idl_type(overload.types[i]));
  2100. optionality_builder.append("IDL::Optionality::"sv);
  2101. switch (overload.optionality_values[i]) {
  2102. case Optionality::Required:
  2103. optionality_builder.append("Required"sv);
  2104. break;
  2105. case Optionality::Optional:
  2106. optionality_builder.append("Optional"sv);
  2107. break;
  2108. case Optionality::Variadic:
  2109. optionality_builder.append("Variadic"sv);
  2110. break;
  2111. }
  2112. }
  2113. types_builder.append("}"sv);
  2114. optionality_builder.append("}"sv);
  2115. function_generator.set("overload.callable_id", ByteString::number(overload.callable_id));
  2116. function_generator.set("overload.types", types_builder.to_byte_string());
  2117. function_generator.set("overload.optionality_values", optionality_builder.to_byte_string());
  2118. function_generator.appendln(" overloads.empend(@overload.callable_id@, @overload.types@, @overload.optionality_values@);");
  2119. }
  2120. function_generator.set("overload_set.distinguishing_argument_index", ByteString::number(distinguishing_argument_index));
  2121. function_generator.append(R"~~~(
  2122. effective_overload_set.emplace(move(overloads), @overload_set.distinguishing_argument_index@);
  2123. break;
  2124. }
  2125. )~~~");
  2126. }
  2127. function_generator.append(R"~~~(
  2128. }
  2129. )~~~");
  2130. generate_dictionary_types(function_generator, dictionary_types.values());
  2131. function_generator.append(R"~~~(
  2132. if (!effective_overload_set.has_value())
  2133. return vm.throw_completion<JS::TypeError>(JS::ErrorType::OverloadResolutionFailed);
  2134. auto chosen_overload = TRY(WebIDL::resolve_overload(vm, effective_overload_set.value(), dictionary_types));
  2135. switch (chosen_overload.callable_id) {
  2136. )~~~");
  2137. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  2138. function_generator.set("overload_id", ByteString::number(i));
  2139. function_generator.append(R"~~~(
  2140. case @overload_id@:
  2141. )~~~");
  2142. if (is_constructor == IsConstructor::Yes) {
  2143. function_generator.append(R"~~~(
  2144. return construct@overload_id@(new_target);
  2145. )~~~");
  2146. } else {
  2147. function_generator.append(R"~~~(
  2148. return @function.name:snakecase@@overload_id@(vm);
  2149. )~~~");
  2150. }
  2151. }
  2152. function_generator.append(R"~~~(
  2153. default:
  2154. VERIFY_NOT_REACHED();
  2155. }
  2156. }
  2157. )~~~");
  2158. }
  2159. static void generate_html_constructor(SourceGenerator& generator, IDL::Constructor const& constructor, IDL::Interface const& interface)
  2160. {
  2161. auto constructor_generator = generator.fork();
  2162. // NOTE: A HTMLConstrcuctor must not have any parameters.
  2163. constructor_generator.set("constructor.length", "0");
  2164. // https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors
  2165. // NOTE: The active function object in this context is always going to be the current constructor that has just been called.
  2166. // The [HTMLConstructor] extended attribute must take no arguments, and must only appear on constructor operations. It must
  2167. // appear only once on a constructor operation, and the interface must contain only the single, annotated constructor
  2168. // operation, and no others
  2169. if (interface.constructors.size() != 1) {
  2170. dbgln("Interface {}'s constructor annotated with [HTMLConstructor] must be the only constructor", interface.name);
  2171. VERIFY_NOT_REACHED();
  2172. }
  2173. if (!constructor.parameters.is_empty()) {
  2174. dbgln("Interface {}'s constructor marked with [HTMLConstructor] must not have any parameters", interface.name);
  2175. VERIFY_NOT_REACHED();
  2176. }
  2177. constructor_generator.append(R"~~~(
  2178. auto& window = verify_cast<HTML::Window>(HTML::current_principal_global_object());
  2179. // 1. Let registry be the current global object's CustomElementRegistry object.
  2180. auto registry = TRY(throw_dom_exception_if_needed(vm, [&] { return window.custom_elements(); }));
  2181. // 2. If NewTarget is equal to the active function object, then throw a TypeError.
  2182. if (&new_target == vm.active_function_object())
  2183. return vm.throw_completion<JS::TypeError>("Cannot directly construct an HTML element, it must be inherited"sv);
  2184. // 3. Let definition be the entry in registry with constructor equal to NewTarget. If there is no such definition, then throw a TypeError.
  2185. auto definition = registry->get_definition_from_new_target(new_target);
  2186. if (!definition)
  2187. return vm.throw_completion<JS::TypeError>("There is no custom element definition assigned to the given constructor"sv);
  2188. // 4. Let is value be null.
  2189. Optional<String> is_value;
  2190. // 5. If definition's local name is equal to definition's name (i.e., definition is for an autonomous custom element), then:
  2191. if (definition->local_name() == definition->name()) {
  2192. // 1. If the active function object is not HTMLElement, then throw a TypeError.
  2193. )~~~");
  2194. if (interface.name != "HTMLElement") {
  2195. constructor_generator.append(R"~~~(
  2196. return vm.throw_completion<JS::TypeError>("Autonomous custom elements can only inherit from HTMLElement"sv);
  2197. )~~~");
  2198. } else {
  2199. constructor_generator.append(R"~~~(
  2200. // Do nothing, as this is the HTMLElement constructor.
  2201. )~~~");
  2202. }
  2203. constructor_generator.append(R"~~~(
  2204. }
  2205. // 6. Otherwise (i.e., if definition is for a customized built-in element):
  2206. else {
  2207. // 1. Let valid local names be the list of local names for elements defined in this specification or in other applicable specifications that use the active function object as their element interface.
  2208. static auto valid_local_names = MUST(DOM::valid_local_names_for_given_html_element_interface("@name@"sv));
  2209. // 2. If valid local names does not contain definition's local name, then throw a TypeError.
  2210. if (!valid_local_names.contains_slow(definition->local_name()))
  2211. return vm.throw_completion<JS::TypeError>(MUST(String::formatted("Local name '{}' of customized built-in element is not a valid local name for @name@"sv, definition->local_name())));
  2212. // 3. Set is value to definition's name.
  2213. is_value = definition->name();
  2214. }
  2215. // 7. If definition's construction stack is empty, then:
  2216. if (definition->construction_stack().is_empty()) {
  2217. // 1. Let element be the result of internally creating a new object implementing the interface to which the active function object corresponds, given the current Realm Record and NewTarget.
  2218. // 2. Set element's node document to the current global object's associated Document.
  2219. // 3. Set element's namespace to the HTML namespace.
  2220. // 4. Set element's namespace prefix to null.
  2221. // 5. Set element's local name to definition's local name.
  2222. auto element = realm.create<@fully_qualified_name@>(window.associated_document(), DOM::QualifiedName { definition->local_name(), {}, Namespace::HTML });
  2223. // https://webidl.spec.whatwg.org/#internally-create-a-new-object-implementing-the-interface
  2224. // Important steps from "internally create a new object implementing the interface"
  2225. // 3.2: Let prototype be ? Get(newTarget, "prototype").
  2226. auto prototype = TRY(new_target.get(vm.names.prototype));
  2227. // 3.3. If Type(prototype) is not Object, then:
  2228. if (!prototype.is_object()) {
  2229. // 1. Let targetRealm be ? GetFunctionRealm(newTarget).
  2230. auto* target_realm = TRY(JS::get_function_realm(vm, new_target));
  2231. // 2. Set prototype to the interface prototype object for interface in targetRealm.
  2232. VERIFY(target_realm);
  2233. prototype = &Bindings::ensure_web_prototype<@prototype_class@>(*target_realm, "@name@"_fly_string);
  2234. }
  2235. // 7. Set instance.[[Prototype]] to prototype.
  2236. VERIFY(prototype.is_object());
  2237. MUST(element->internal_set_prototype_of(&prototype.as_object()));
  2238. // 6. Set element's custom element state to "custom".
  2239. // 7. Set element's custom element definition to definition.
  2240. // 8. Set element's is value to is value.
  2241. element->setup_custom_element_from_constructor(*definition, is_value);
  2242. // 9. Return element.
  2243. return *element;
  2244. }
  2245. // 8. Let prototype be ? Get(NewTarget, "prototype").
  2246. auto prototype = TRY(new_target.get(vm.names.prototype));
  2247. // 9. If Type(prototype) is not Object, then:
  2248. if (!prototype.is_object()) {
  2249. // 1. Let realm be ? GetFunctionRealm(NewTarget).
  2250. auto* function_realm = TRY(JS::get_function_realm(vm, new_target));
  2251. // 2. Set prototype to the interface prototype object of realm whose interface is the same as the interface of the active function object.
  2252. VERIFY(function_realm);
  2253. prototype = &Bindings::ensure_web_prototype<@prototype_class@>(*function_realm, "@name@"_fly_string);
  2254. }
  2255. VERIFY(prototype.is_object());
  2256. // 10. Let element be the last entry in definition's construction stack.
  2257. auto& element = definition->construction_stack().last();
  2258. // 11. If element is an already constructed marker, then throw an "InvalidStateError" DOMException.
  2259. if (element.has<HTML::AlreadyConstructedCustomElementMarker>())
  2260. return JS::throw_completion(WebIDL::InvalidStateError::create(realm, "Custom element has already been constructed"_string));
  2261. // 12. Perform ? element.[[SetPrototypeOf]](prototype).
  2262. auto actual_element = element.get<GC::Root<DOM::Element>>();
  2263. TRY(actual_element->internal_set_prototype_of(&prototype.as_object()));
  2264. // 13. Replace the last entry in definition's construction stack with an already constructed marker.
  2265. definition->construction_stack().last() = HTML::AlreadyConstructedCustomElementMarker {};
  2266. // 14. Return element.
  2267. return *actual_element;
  2268. }
  2269. )~~~");
  2270. }
  2271. static void generate_constructor(SourceGenerator& generator, IDL::Constructor const& constructor, IDL::Interface const& interface, bool is_html_constructor)
  2272. {
  2273. auto constructor_generator = generator.fork();
  2274. constructor_generator.set("constructor_class", interface.constructor_class);
  2275. constructor_generator.set("interface_fully_qualified_name", interface.fully_qualified_name);
  2276. constructor_generator.set("overload_suffix", constructor.is_overloaded ? ByteString::number(constructor.overload_index) : ByteString::empty());
  2277. constructor_generator.append(R"~~~(
  2278. JS::ThrowCompletionOr<GC::Ref<JS::Object>> @constructor_class@::construct@overload_suffix@([[maybe_unused]] FunctionObject& new_target)
  2279. {
  2280. WebIDL::log_trace(vm(), "@constructor_class@::construct@overload_suffix@");
  2281. )~~~");
  2282. generator.append(R"~~~(
  2283. auto& vm = this->vm();
  2284. auto& realm = *vm.current_realm();
  2285. )~~~");
  2286. if (is_html_constructor) {
  2287. generate_html_constructor(generator, constructor, interface);
  2288. } else {
  2289. generator.append(R"~~~(
  2290. // To internally create a new object implementing the interface @name@:
  2291. // 3.2. Let prototype be ? Get(newTarget, "prototype").
  2292. auto prototype = TRY(new_target.get(vm.names.prototype));
  2293. // 3.3. If Type(prototype) is not Object, then:
  2294. if (!prototype.is_object()) {
  2295. // 1. Let targetRealm be ? GetFunctionRealm(newTarget).
  2296. auto* target_realm = TRY(JS::get_function_realm(vm, new_target));
  2297. // 2. Set prototype to the interface prototype object for interface in targetRealm.
  2298. VERIFY(target_realm);
  2299. prototype = &Bindings::ensure_web_prototype<@prototype_class@>(*target_realm, "@name@"_fly_string);
  2300. }
  2301. // 4. Let instance be MakeBasicObject( « [[Prototype]], [[Extensible]], [[Realm]], [[PrimaryInterface]] »).
  2302. // 5. Set instance.[[Realm]] to realm.
  2303. // 6. Set instance.[[PrimaryInterface]] to interface.
  2304. )~~~");
  2305. if (!constructor.parameters.is_empty()) {
  2306. generate_argument_count_check(generator, constructor.name, constructor.shortest_length());
  2307. StringBuilder arguments_builder;
  2308. generate_arguments(generator, constructor.parameters, arguments_builder, interface);
  2309. constructor_generator.set(".constructor_arguments", arguments_builder.string_view());
  2310. constructor_generator.append(R"~~~(
  2311. auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm, @.constructor_arguments@); }));
  2312. )~~~");
  2313. } else {
  2314. constructor_generator.append(R"~~~(
  2315. auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::construct_impl(realm); }));
  2316. )~~~");
  2317. }
  2318. constructor_generator.append(R"~~~(
  2319. // 7. Set instance.[[Prototype]] to prototype.
  2320. VERIFY(prototype.is_object());
  2321. impl->set_prototype(&prototype.as_object());
  2322. // FIXME: Steps 8...11. of the "internally create a new object implementing the interface @name@" algorithm
  2323. // (https://webidl.spec.whatwg.org/#js-platform-objects) are currently not handled, or are handled within @fully_qualified_name@::construct_impl().
  2324. // 8. Let interfaces be the inclusive inherited interfaces of interface.
  2325. // 9. For every interface ancestor interface in interfaces:
  2326. // 9.1. Let unforgeables be the value of the [[Unforgeables]] slot of the interface object of ancestor interface in realm.
  2327. // 9.2. Let keys be ! unforgeables.[[OwnPropertyKeys]]().
  2328. // 9.3. For each element key of keys:
  2329. // 9.3.1. Let descriptor be ! unforgeables.[[GetOwnProperty]](key).
  2330. // 9.3.2. Perform ! DefinePropertyOrThrow(instance, key, descriptor).
  2331. // 10. If interface is declared with the [Global] extended attribute, then:
  2332. // 10.1. Define the regular operations of interface on instance, given realm.
  2333. // 10.2. Define the regular attributes of interface on instance, given realm.
  2334. // 10.3. Define the iteration methods of interface on instance given realm.
  2335. // 10.4. Define the asynchronous iteration methods of interface on instance given realm.
  2336. // 10.5. Define the global property references on instance, given realm.
  2337. // 10.6. Set instance.[[SetPrototypeOf]] as defined in § 3.8.1 [[SetPrototypeOf]].
  2338. // 11. Otherwise, if interfaces contains an interface which supports indexed properties, named properties, or both:
  2339. // 11.1. Set instance.[[GetOwnProperty]] as defined in § 3.9.1 [[GetOwnProperty]].
  2340. // 11.2. Set instance.[[Set]] as defined in § 3.9.2 [[Set]].
  2341. // 11.3. Set instance.[[DefineOwnProperty]] as defined in § 3.9.3 [[DefineOwnProperty]].
  2342. // 11.4. Set instance.[[Delete]] as defined in § 3.9.4 [[Delete]].
  2343. // 11.5. Set instance.[[PreventExtensions]] as defined in § 3.9.5 [[PreventExtensions]].
  2344. // 11.6. Set instance.[[OwnPropertyKeys]] as defined in § 3.9.6 [[OwnPropertyKeys]].
  2345. return *impl;
  2346. }
  2347. )~~~");
  2348. }
  2349. }
  2350. static void generate_constructors(SourceGenerator& generator, IDL::Interface const& interface)
  2351. {
  2352. auto shortest_length = interface.constructors.is_empty() ? 0u : NumericLimits<size_t>::max();
  2353. bool has_html_constructor = false;
  2354. for (auto const& constructor : interface.constructors) {
  2355. shortest_length = min(shortest_length, constructor.shortest_length());
  2356. if (constructor.extended_attributes.contains("HTMLConstructor"sv)) {
  2357. has_html_constructor = true;
  2358. break;
  2359. }
  2360. }
  2361. if (has_html_constructor && interface.constructors.size() != 1) {
  2362. dbgln("Interface {}'s constructor annotated with [HTMLConstructor] must be the only constructor", interface.name);
  2363. VERIFY_NOT_REACHED();
  2364. }
  2365. generator.set("constructor.length", ByteString::number(shortest_length));
  2366. // Implementation: Constructors
  2367. if (interface.constructors.is_empty()) {
  2368. // No constructor
  2369. generator.append(R"~~~(
  2370. JS::ThrowCompletionOr<GC::Ref<JS::Object>> @constructor_class@::construct([[maybe_unused]] FunctionObject& new_target)
  2371. {
  2372. WebIDL::log_trace(vm(), "@constructor_class@::construct");
  2373. )~~~");
  2374. generator.set("constructor.length", "0");
  2375. generator.append(R"~~~(
  2376. return vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "@namespaced_name@");
  2377. }
  2378. )~~~");
  2379. } else {
  2380. for (auto& constructor : interface.constructors) {
  2381. generate_constructor(generator, constructor, interface, has_html_constructor);
  2382. }
  2383. }
  2384. for (auto const& overload_set : interface.constructor_overload_sets) {
  2385. if (overload_set.value.size() == 1)
  2386. continue;
  2387. generate_overload_arbiter(generator, overload_set, interface, interface.constructor_class, IsConstructor::Yes);
  2388. }
  2389. }
  2390. static void generate_enumerations(HashMap<ByteString, Enumeration> const& enumerations, StringBuilder& builder)
  2391. {
  2392. SourceGenerator generator { builder };
  2393. for (auto const& it : enumerations) {
  2394. if (!it.value.is_original_definition)
  2395. continue;
  2396. auto enum_generator = generator.fork();
  2397. enum_generator.set("enum.type.name", it.key);
  2398. enum_generator.append(R"~~~(
  2399. enum class @enum.type.name@ {
  2400. )~~~");
  2401. for (auto const& entry : it.value.translated_cpp_names) {
  2402. enum_generator.set("enum.entry", entry.value);
  2403. enum_generator.append(R"~~~(
  2404. @enum.entry@,
  2405. )~~~");
  2406. }
  2407. enum_generator.append(R"~~~(
  2408. };
  2409. )~~~");
  2410. enum_generator.append(R"~~~(
  2411. inline String idl_enum_to_string(@enum.type.name@ value)
  2412. {
  2413. switch (value) {
  2414. )~~~");
  2415. for (auto const& entry : it.value.translated_cpp_names) {
  2416. enum_generator.set("enum.entry", entry.value);
  2417. enum_generator.set("enum.string", entry.key);
  2418. enum_generator.append(R"~~~(
  2419. case @enum.type.name@::@enum.entry@:
  2420. return "@enum.string@"_string;
  2421. )~~~");
  2422. }
  2423. enum_generator.append(R"~~~(
  2424. }
  2425. VERIFY_NOT_REACHED();
  2426. }
  2427. )~~~");
  2428. }
  2429. }
  2430. static void generate_prototype_or_global_mixin_declarations(IDL::Interface const& interface, StringBuilder& builder)
  2431. {
  2432. SourceGenerator generator { builder };
  2433. for (auto const& overload_set : interface.overload_sets) {
  2434. auto function_generator = generator.fork();
  2435. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  2436. function_generator.append(R"~~~(
  2437. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
  2438. )~~~");
  2439. if (overload_set.value.size() > 1) {
  2440. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  2441. function_generator.set("overload_suffix", ByteString::number(i));
  2442. function_generator.append(R"~~~(
  2443. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
  2444. )~~~");
  2445. }
  2446. }
  2447. }
  2448. if (interface.has_stringifier) {
  2449. auto stringifier_generator = generator.fork();
  2450. stringifier_generator.append(R"~~~(
  2451. JS_DECLARE_NATIVE_FUNCTION(to_string);
  2452. )~~~");
  2453. }
  2454. if (interface.pair_iterator_types.has_value()) {
  2455. auto iterator_generator = generator.fork();
  2456. iterator_generator.append(R"~~~(
  2457. JS_DECLARE_NATIVE_FUNCTION(entries);
  2458. JS_DECLARE_NATIVE_FUNCTION(for_each);
  2459. JS_DECLARE_NATIVE_FUNCTION(keys);
  2460. JS_DECLARE_NATIVE_FUNCTION(values);
  2461. )~~~");
  2462. }
  2463. if (interface.set_entry_type.has_value()) {
  2464. auto setlike_generator = generator.fork();
  2465. setlike_generator.append(R"~~~(
  2466. JS_DECLARE_NATIVE_FUNCTION(get_size);
  2467. JS_DECLARE_NATIVE_FUNCTION(entries);
  2468. JS_DECLARE_NATIVE_FUNCTION(values);
  2469. JS_DECLARE_NATIVE_FUNCTION(for_each);
  2470. JS_DECLARE_NATIVE_FUNCTION(has);
  2471. )~~~");
  2472. if (!interface.overload_sets.contains("add"sv) && !interface.is_set_readonly) {
  2473. setlike_generator.append(R"~~~(
  2474. JS_DECLARE_NATIVE_FUNCTION(add);
  2475. )~~~");
  2476. }
  2477. if (!interface.overload_sets.contains("delete"sv) && !interface.is_set_readonly) {
  2478. setlike_generator.append(R"~~~(
  2479. JS_DECLARE_NATIVE_FUNCTION(delete_);
  2480. )~~~");
  2481. }
  2482. if (!interface.overload_sets.contains("clear"sv) && !interface.is_set_readonly) {
  2483. setlike_generator.append(R"~~~(
  2484. JS_DECLARE_NATIVE_FUNCTION(clear);
  2485. )~~~");
  2486. }
  2487. }
  2488. for (auto& attribute : interface.attributes) {
  2489. if (attribute.extended_attributes.contains("FIXME"))
  2490. continue;
  2491. auto attribute_generator = generator.fork();
  2492. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  2493. attribute_generator.append(R"~~~(
  2494. JS_DECLARE_NATIVE_FUNCTION(@attribute.getter_callback@);
  2495. )~~~");
  2496. if (!attribute.readonly || attribute.extended_attributes.contains("Replaceable"sv) || attribute.extended_attributes.contains("PutForwards"sv)) {
  2497. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  2498. attribute_generator.append(R"~~~(
  2499. JS_DECLARE_NATIVE_FUNCTION(@attribute.setter_callback@);
  2500. )~~~");
  2501. }
  2502. }
  2503. generator.append(R"~~~(
  2504. };
  2505. )~~~");
  2506. generate_enumerations(interface.enumerations, builder);
  2507. }
  2508. // https://webidl.spec.whatwg.org/#create-an-inheritance-stack
  2509. static Vector<Interface const&> create_an_inheritance_stack(IDL::Interface const& start_interface)
  2510. {
  2511. // 1. Let stack be a new stack.
  2512. Vector<Interface const&> inheritance_chain;
  2513. // 2. Push I onto stack.
  2514. inheritance_chain.append(start_interface);
  2515. // 3. While I inherits from an interface,
  2516. auto const* current_interface = &start_interface;
  2517. while (current_interface && !current_interface->parent_name.is_empty()) {
  2518. // 1. Let I be that interface.
  2519. auto imported_interface_iterator = start_interface.imported_modules.find_if([&current_interface](IDL::Interface const& imported_interface) {
  2520. return imported_interface.name == current_interface->parent_name;
  2521. });
  2522. // Inherited interfaces must have their IDL files imported.
  2523. VERIFY(imported_interface_iterator != start_interface.imported_modules.end());
  2524. // 2. Push I onto stack.
  2525. inheritance_chain.append(*imported_interface_iterator);
  2526. current_interface = &*imported_interface_iterator;
  2527. }
  2528. // 4. Return stack.
  2529. return inheritance_chain;
  2530. }
  2531. // https://webidl.spec.whatwg.org/#collect-attribute-values-of-an-inheritance-stack
  2532. static void collect_attribute_values_of_an_inheritance_stack(SourceGenerator& function_generator, Vector<Interface const&> const& inheritance_chain)
  2533. {
  2534. // 1. Let I be the result of popping from stack.
  2535. // 3. If stack is not empty, then invoke collect attribute values of an inheritance stack given object, stack, and map.
  2536. for (auto const& interface_in_chain : inheritance_chain.in_reverse()) {
  2537. // 2. Invoke collect attribute values given object, I, and map.
  2538. // https://webidl.spec.whatwg.org/#collect-attribute-values
  2539. // 1. If a toJSON operation with a [Default] extended attribute is declared on I, then for each exposed regular attribute attr that is an interface member of I, in order:
  2540. auto to_json_iterator = interface_in_chain.functions.find_if([](IDL::Function const& function) {
  2541. return function.name == "toJSON" && function.extended_attributes.contains("Default");
  2542. });
  2543. if (to_json_iterator == interface_in_chain.functions.end())
  2544. continue;
  2545. // FIXME: Check if the attributes are exposed.
  2546. // 1. Let id be the identifier of attr.
  2547. // 2. Let value be the result of running the getter steps of attr with object as this.
  2548. // 3. If value is a JSON type, then set map[id] to value.
  2549. // Since we are flatly generating the attributes, the consequent is replaced with these steps from "default toJSON steps":
  2550. // 5. For each key → value of map,
  2551. // 1. Let k be key converted to an ECMAScript value.
  2552. // 2. Let v be value converted to an ECMAScript value.
  2553. // 3. Perform ! CreateDataProperty(result, k, v).
  2554. // NOTE: Functions, constructors and static functions cannot be JSON types, so they're not checked here.
  2555. for (auto& attribute : interface_in_chain.attributes) {
  2556. if (attribute.extended_attributes.contains("FIXME"))
  2557. continue;
  2558. if (!attribute.type->is_json(interface_in_chain))
  2559. continue;
  2560. auto attribute_generator = function_generator.fork();
  2561. auto return_value_name = ByteString::formatted("{}_retval", attribute.name.to_snakecase());
  2562. attribute_generator.set("attribute.name", attribute.name);
  2563. attribute_generator.set("attribute.return_value_name", return_value_name);
  2564. if (attribute.extended_attributes.contains("ImplementedAs")) {
  2565. auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value();
  2566. attribute_generator.set("attribute.cpp_name", implemented_as);
  2567. } else {
  2568. attribute_generator.set("attribute.cpp_name", attribute.name.to_snakecase());
  2569. }
  2570. if (attribute.extended_attributes.contains("Reflect")) {
  2571. auto attribute_name = attribute.extended_attributes.get("Reflect").value();
  2572. if (attribute_name.is_empty())
  2573. attribute_name = attribute.name;
  2574. attribute_name = make_input_acceptable_cpp(attribute_name);
  2575. attribute_generator.set("attribute.reflect_name", attribute_name);
  2576. } else {
  2577. attribute_generator.set("attribute.reflect_name", attribute.name.to_snakecase());
  2578. }
  2579. if (attribute.extended_attributes.contains("Reflect")) {
  2580. if (attribute.type->name() != "boolean") {
  2581. attribute_generator.append(R"~~~(
  2582. auto @attribute.return_value_name@ = impl->get_attribute_value(HTML::AttributeNames::@attribute.reflect_name@);
  2583. )~~~");
  2584. } else {
  2585. attribute_generator.append(R"~~~(
  2586. auto @attribute.return_value_name@ = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  2587. )~~~");
  2588. }
  2589. } else {
  2590. attribute_generator.append(R"~~~(
  2591. auto @attribute.return_value_name@ = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); }));
  2592. )~~~");
  2593. }
  2594. generate_wrap_statement(attribute_generator, return_value_name, attribute.type, interface_in_chain, ByteString::formatted("auto {}_wrapped =", return_value_name));
  2595. attribute_generator.append(R"~~~(
  2596. MUST(result->create_data_property("@attribute.name@", @attribute.return_value_name@_wrapped));
  2597. )~~~");
  2598. }
  2599. for (auto& constant : interface_in_chain.constants) {
  2600. auto constant_generator = function_generator.fork();
  2601. constant_generator.set("constant.name", constant.name);
  2602. generate_wrap_statement(constant_generator, constant.value, constant.type, interface_in_chain, ByteString::formatted("auto constant_{}_value =", constant.name));
  2603. constant_generator.append(R"~~~(
  2604. MUST(result->create_data_property("@constant.name@", constant_@constant.name@_value));
  2605. )~~~");
  2606. }
  2607. }
  2608. }
  2609. // https://webidl.spec.whatwg.org/#default-tojson-steps
  2610. static void generate_default_to_json_function(SourceGenerator& generator, ByteString const& class_name, IDL::Interface const& start_interface)
  2611. {
  2612. // NOTE: This is done heavily out of order since the spec mixes parse time and run time type information together.
  2613. auto function_generator = generator.fork();
  2614. function_generator.set("class_name", class_name);
  2615. // 4. Let result be OrdinaryObjectCreate(%Object.prototype%).
  2616. function_generator.append(R"~~~(
  2617. JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_json)
  2618. {
  2619. WebIDL::log_trace(vm, "@class_name@::to_json");
  2620. auto& realm = *vm.current_realm();
  2621. auto* impl = TRY(impl_from(vm));
  2622. auto result = JS::Object::create(realm, realm.intrinsics().object_prototype());
  2623. )~~~");
  2624. // 1. Let map be a new ordered map.
  2625. // NOTE: Instead of making a map, we flatly generate the attributes.
  2626. // 2. Let stack be the result of creating an inheritance stack for interface I.
  2627. auto inheritance_chain = create_an_inheritance_stack(start_interface);
  2628. // 3. Invoke collect attribute values of an inheritance stack given this, stack, and map.
  2629. collect_attribute_values_of_an_inheritance_stack(function_generator, inheritance_chain);
  2630. // NOTE: Step 5 is done as part of collect_attribute_values_of_an_inheritance_stack, due to us flatly generating the attributes.
  2631. // 6. Return result.
  2632. function_generator.append(R"~~~(
  2633. return result;
  2634. }
  2635. )~~~");
  2636. }
  2637. static void generate_named_properties_object_declarations(IDL::Interface const& interface, StringBuilder& builder)
  2638. {
  2639. SourceGenerator generator { builder };
  2640. generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name));
  2641. generator.append(R"~~~(
  2642. class @named_properties_class@ : public JS::Object {
  2643. JS_OBJECT(@named_properties_class@, JS::Object);
  2644. GC_DECLARE_ALLOCATOR(@named_properties_class@);
  2645. public:
  2646. explicit @named_properties_class@(JS::Realm&);
  2647. virtual void initialize(JS::Realm&) override;
  2648. virtual ~@named_properties_class@() override;
  2649. JS::Realm& realm() const { return m_realm; }
  2650. private:
  2651. virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
  2652. virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional<JS::PropertyDescriptor>* precomputed_get_own_property = nullptr) override;
  2653. virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
  2654. virtual JS::ThrowCompletionOr<bool> internal_set_prototype_of(JS::Object* prototype) override;
  2655. virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
  2656. virtual void visit_edges(Visitor&) override;
  2657. GC::Ref<JS::Realm> m_realm; // [[Realm]]
  2658. };
  2659. )~~~");
  2660. }
  2661. static void generate_named_properties_object_definitions(IDL::Interface const& interface, StringBuilder& builder)
  2662. {
  2663. SourceGenerator generator { builder };
  2664. generator.set("name", interface.name);
  2665. generator.set("parent_name", interface.parent_name);
  2666. generator.set("prototype_base_class", interface.prototype_base_class);
  2667. generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name));
  2668. // https://webidl.spec.whatwg.org/#create-a-named-properties-object
  2669. generator.append(R"~~~(
  2670. #include <LibWeb/WebIDL/AbstractOperations.h>
  2671. GC_DEFINE_ALLOCATOR(@named_properties_class@);
  2672. @named_properties_class@::@named_properties_class@(JS::Realm& realm)
  2673. : JS::Object(realm, nullptr, MayInterfereWithIndexedPropertyAccess::Yes)
  2674. , m_realm(realm)
  2675. {
  2676. }
  2677. @named_properties_class@::~@named_properties_class@()
  2678. {
  2679. }
  2680. void @named_properties_class@::initialize(JS::Realm& realm)
  2681. {
  2682. auto& vm = realm.vm();
  2683. // The class string of a named properties object is the concatenation of the interface's identifier and the string "Properties".
  2684. define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "@named_properties_class@"_string), JS::Attribute::Configurable);
  2685. )~~~");
  2686. // 1. Let proto be null
  2687. // 2. If interface is declared to inherit from another interface, then set proto to the interface prototype object in realm for the inherited interface.
  2688. // 3. Otherwise, set proto to realm.[[Intrinsics]].[[%Object.prototype%]].
  2689. // NOTE: Steps 4-9 handled by constructor + other overridden functions
  2690. // 10. Set obj.[[Prototype]] to proto.
  2691. if (interface.prototype_base_class == "ObjectPrototype") {
  2692. generator.append(R"~~~(
  2693. set_prototype(realm.intrinsics().object_prototype());
  2694. )~~~");
  2695. } else {
  2696. generator.append(R"~~~(
  2697. set_prototype(&ensure_web_prototype<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
  2698. )~~~");
  2699. }
  2700. generator.append(R"~~~(
  2701. };
  2702. // https://webidl.spec.whatwg.org/#named-properties-object-getownproperty
  2703. JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> @named_properties_class@::internal_get_own_property(JS::PropertyKey const& property_name) const
  2704. {
  2705. auto& realm = this->realm();
  2706. // 1. Let A be the interface for the named properties object O.
  2707. using A = @name@;
  2708. // 2. Let object be O.[[Realm]]'s global object.
  2709. // 3. Assert: object implements A.
  2710. auto& object = verify_cast<A>(realm.global_object());
  2711. // 4. If the result of running the named property visibility algorithm with property name P and object object is true, then:
  2712. if (TRY(object.is_named_property_exposed_on_object(property_name))) {
  2713. auto property_name_string = MUST(FlyString::from_deprecated_fly_string(property_name.to_string()));
  2714. // 1. Let operation be the operation used to declare the named property getter.
  2715. // 2. Let value be an uninitialized variable.
  2716. // 3. If operation was defined without an identifier, then set value to the result of performing the steps listed in the interface description to determine the value of a named property with P as the name.
  2717. // 4. Otherwise, operation was defined with an identifier. Set value to the result of performing the method steps of operation with « P » as the only argument value.
  2718. auto value = object.named_item_value(property_name_string);
  2719. // 5. Let desc be a newly created Property Descriptor with no fields.
  2720. JS::PropertyDescriptor descriptor;
  2721. // 6. Set desc.[[Value]] to the result of converting value to an ECMAScript value.
  2722. descriptor.value = value;
  2723. )~~~");
  2724. if (interface.extended_attributes.contains("LegacyUnenumerableNamedProperties"))
  2725. generator.append(R"~~~(
  2726. // 7. If A implements an interface with the [LegacyUnenumerableNamedProperties] extended attribute, then set desc.[[Enumerable]] to false, otherwise set it to true.
  2727. descriptor.enumerable = true;
  2728. )~~~");
  2729. else {
  2730. generator.append(R"~~~(
  2731. // 7. If A implements an interface with the [LegacyUnenumerableNamedProperties] extended attribute, then set desc.[[Enumerable]] to false, otherwise set it to true.
  2732. descriptor.enumerable = false;
  2733. )~~~");
  2734. }
  2735. generator.append(R"~~~(
  2736. // 8. Set desc.[[Writable]] to true and desc.[[Configurable]] to true.
  2737. descriptor.writable = true;
  2738. descriptor.configurable = true;
  2739. // 9. Return desc.
  2740. return descriptor;
  2741. }
  2742. // 5. Return OrdinaryGetOwnProperty(O, P).
  2743. return JS::Object::internal_get_own_property(property_name);
  2744. }
  2745. // https://webidl.spec.whatwg.org/#named-properties-object-defineownproperty
  2746. JS::ThrowCompletionOr<bool> @named_properties_class@::internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional<JS::PropertyDescriptor>*)
  2747. {
  2748. // 1. Return false.
  2749. return false;
  2750. }
  2751. // https://webidl.spec.whatwg.org/#named-properties-object-delete
  2752. JS::ThrowCompletionOr<bool> @named_properties_class@::internal_delete(JS::PropertyKey const&)
  2753. {
  2754. // 1. Return false.
  2755. return false;
  2756. }
  2757. // https://webidl.spec.whatwg.org/#named-properties-object-setprototypeof
  2758. JS::ThrowCompletionOr<bool> @named_properties_class@::internal_set_prototype_of(JS::Object* prototype)
  2759. {
  2760. // 1. Return ? SetImmutablePrototype(O, V).
  2761. return set_immutable_prototype(prototype);
  2762. }
  2763. // https://webidl.spec.whatwg.org/#named-properties-object-preventextensions
  2764. JS::ThrowCompletionOr<bool> @named_properties_class@::internal_prevent_extensions()
  2765. {
  2766. // 1. Return false.
  2767. // Note: this keeps named properties object extensible by making [[PreventExtensions]] fail.
  2768. return false;
  2769. }
  2770. void @named_properties_class@::visit_edges(Visitor& visitor)
  2771. {
  2772. Base::visit_edges(visitor);
  2773. visitor.visit(m_realm);
  2774. }
  2775. )~~~");
  2776. }
  2777. // https://webidl.spec.whatwg.org/#interface-prototype-object
  2778. static void generate_prototype_or_global_mixin_definitions(IDL::Interface const& interface, StringBuilder& builder)
  2779. {
  2780. SourceGenerator generator { builder };
  2781. auto is_global_interface = interface.extended_attributes.contains("Global");
  2782. auto class_name = is_global_interface ? interface.global_mixin_class : interface.prototype_class;
  2783. generator.set("name", interface.name);
  2784. generator.set("namespaced_name", interface.namespaced_name);
  2785. generator.set("class_name", class_name);
  2786. generator.set("fully_qualified_name", interface.fully_qualified_name);
  2787. generator.set("parent_name", interface.parent_name);
  2788. generator.set("prototype_base_class", interface.prototype_base_class);
  2789. generator.set("prototype_name", interface.prototype_class); // Used for Global Mixin
  2790. if (interface.pair_iterator_types.has_value()) {
  2791. generator.set("iterator_name", ByteString::formatted("{}Iterator", interface.name));
  2792. }
  2793. if (is_global_interface) {
  2794. generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name));
  2795. // Doing this with macros is not super nice, but simplifies codegen a lot.
  2796. generator.append(R"~~~(
  2797. #define define_direct_property (object.define_direct_property)
  2798. #define define_native_accessor (object.define_native_accessor)
  2799. #define define_native_function (object.define_native_function)
  2800. #define set_prototype (object.set_prototype)
  2801. void @class_name@::initialize(JS::Realm& realm, JS::Object& object)
  2802. {
  2803. )~~~");
  2804. } else {
  2805. generator.append(R"~~~(
  2806. void @class_name@::initialize(JS::Realm& realm)
  2807. {
  2808. )~~~");
  2809. }
  2810. // FIXME: Currently almost everything gets default_attributes but it should be configurable per attribute.
  2811. // See the spec links for details
  2812. generator.append(R"~~~(
  2813. [[maybe_unused]] auto& vm = realm.vm();
  2814. [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;
  2815. )~~~");
  2816. if (interface.name == "DOMException"sv) {
  2817. generator.append(R"~~~(
  2818. set_prototype(realm.intrinsics().error_prototype());
  2819. )~~~");
  2820. }
  2821. else if (interface.prototype_base_class == "ObjectPrototype") {
  2822. generator.append(R"~~~(
  2823. set_prototype(realm.intrinsics().object_prototype());
  2824. )~~~");
  2825. } else if (is_global_interface) {
  2826. generator.append(R"~~~(
  2827. set_prototype(&ensure_web_prototype<@prototype_name@>(realm, "@name@"_fly_string));
  2828. )~~~");
  2829. } else {
  2830. generator.append(R"~~~(
  2831. set_prototype(&ensure_web_prototype<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
  2832. )~~~");
  2833. }
  2834. if (interface.has_unscopable_member) {
  2835. generator.append(R"~~~(
  2836. auto unscopable_object = JS::Object::create(realm, nullptr);
  2837. )~~~");
  2838. }
  2839. // https://webidl.spec.whatwg.org/#es-attributes
  2840. for (auto& attribute : interface.attributes) {
  2841. if (attribute.extended_attributes.contains("FIXME")) {
  2842. auto fixme_attribute_generator = generator.fork();
  2843. fixme_attribute_generator.set("attribute.name", attribute.name);
  2844. fixme_attribute_generator.append(R"~~~(
  2845. define_direct_property("@attribute.name@", JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
  2846. )~~~");
  2847. continue;
  2848. }
  2849. auto attribute_generator = generator.fork();
  2850. attribute_generator.set("attribute.name", attribute.name);
  2851. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  2852. if (!attribute.readonly || attribute.extended_attributes.contains("Replaceable"sv) || attribute.extended_attributes.contains("PutForwards"sv))
  2853. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  2854. else
  2855. attribute_generator.set("attribute.setter_callback", "nullptr");
  2856. if (attribute.extended_attributes.contains("Unscopable")) {
  2857. attribute_generator.append(R"~~~(
  2858. MUST(unscopable_object->create_data_property("@attribute.name@", JS::Value(true)));
  2859. )~~~");
  2860. }
  2861. attribute_generator.append(R"~~~(
  2862. define_native_accessor(realm, "@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
  2863. )~~~");
  2864. }
  2865. for (auto& function : interface.functions) {
  2866. if (function.extended_attributes.contains("FIXME")) {
  2867. auto fixme_function_generator = generator.fork();
  2868. fixme_function_generator.set("function.name", function.name);
  2869. fixme_function_generator.append(R"~~~(
  2870. define_direct_property("@function.name@", JS::js_undefined(), default_attributes | JS::Attribute::Unimplemented);
  2871. )~~~");
  2872. }
  2873. }
  2874. // https://webidl.spec.whatwg.org/#es-constants
  2875. for (auto& constant : interface.constants) {
  2876. // FIXME: Do constants need to be added to the unscopable list?
  2877. auto constant_generator = generator.fork();
  2878. constant_generator.set("constant.name", constant.name);
  2879. generate_wrap_statement(constant_generator, constant.value, constant.type, interface, ByteString::formatted("auto constant_{}_value =", constant.name));
  2880. constant_generator.append(R"~~~(
  2881. define_direct_property("@constant.name@", constant_@constant.name@_value, JS::Attribute::Enumerable);
  2882. )~~~");
  2883. }
  2884. // https://webidl.spec.whatwg.org/#es-operations
  2885. for (auto const& overload_set : interface.overload_sets) {
  2886. auto function_generator = generator.fork();
  2887. function_generator.set("function.name", overload_set.key);
  2888. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  2889. function_generator.set("function.length", ByteString::number(get_shortest_function_length(overload_set.value)));
  2890. if (any_of(overload_set.value, [](auto const& function) { return function.extended_attributes.contains("Unscopable"); })) {
  2891. VERIFY(all_of(overload_set.value, [](auto const& function) { return function.extended_attributes.contains("Unscopable"); }));
  2892. function_generator.append(R"~~~(
  2893. MUST(unscopable_object->create_data_property("@function.name@", JS::Value(true)));
  2894. )~~~");
  2895. }
  2896. function_generator.append(R"~~~(
  2897. define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, default_attributes);
  2898. )~~~");
  2899. }
  2900. if (interface.has_stringifier) {
  2901. // FIXME: Do stringifiers need to be added to the unscopable list?
  2902. auto stringifier_generator = generator.fork();
  2903. stringifier_generator.append(R"~~~(
  2904. define_native_function(realm, "toString", to_string, 0, default_attributes);
  2905. )~~~");
  2906. }
  2907. // https://webidl.spec.whatwg.org/#define-the-iteration-methods
  2908. // This applies to this if block and the following if block.
  2909. if (interface.indexed_property_getter.has_value()) {
  2910. auto iterator_generator = generator.fork();
  2911. iterator_generator.append(R"~~~(
  2912. define_direct_property(vm.well_known_symbol_iterator(), realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
  2913. )~~~");
  2914. if (interface.value_iterator_type.has_value()) {
  2915. iterator_generator.append(R"~~~(
  2916. define_direct_property(vm.names.entries, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.entries), default_attributes);
  2917. define_direct_property(vm.names.keys, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.keys), default_attributes);
  2918. define_direct_property(vm.names.values, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), default_attributes);
  2919. define_direct_property(vm.names.forEach, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.forEach), default_attributes);
  2920. )~~~");
  2921. }
  2922. }
  2923. if (interface.pair_iterator_types.has_value()) {
  2924. // FIXME: Do pair iterators need to be added to the unscopable list?
  2925. auto iterator_generator = generator.fork();
  2926. iterator_generator.append(R"~~~(
  2927. define_native_function(realm, vm.names.entries, entries, 0, default_attributes);
  2928. define_native_function(realm, vm.names.forEach, for_each, 1, default_attributes);
  2929. define_native_function(realm, vm.names.keys, keys, 0, default_attributes);
  2930. define_native_function(realm, vm.names.values, values, 0, default_attributes);
  2931. define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.entries), JS::Attribute::Configurable | JS::Attribute::Writable);
  2932. )~~~");
  2933. }
  2934. // https://webidl.spec.whatwg.org/#js-setlike
  2935. if (interface.set_entry_type.has_value()) {
  2936. auto setlike_generator = generator.fork();
  2937. setlike_generator.append(R"~~~(
  2938. define_native_accessor(realm, vm.names.size, get_size, nullptr, JS::Attribute::Enumerable | JS::Attribute::Configurable);
  2939. define_native_function(realm, vm.names.entries, entries, 0, default_attributes);
  2940. // NOTE: Keys intentionally returns values for setlike
  2941. define_native_function(realm, vm.names.keys, values, 0, default_attributes);
  2942. define_native_function(realm, vm.names.values, values, 0, default_attributes);
  2943. define_direct_property(vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.values), JS::Attribute::Configurable | JS::Attribute::Writable);
  2944. define_native_function(realm, vm.names.forEach, for_each, 1, default_attributes);
  2945. define_native_function(realm, vm.names.has, has, 1, default_attributes);
  2946. )~~~");
  2947. if (!interface.overload_sets.contains("add"sv) && !interface.is_set_readonly) {
  2948. setlike_generator.append(R"~~~(
  2949. define_native_function(realm, vm.names.add, add, 1, default_attributes);
  2950. )~~~");
  2951. }
  2952. if (!interface.overload_sets.contains("delete"sv) && !interface.is_set_readonly) {
  2953. setlike_generator.append(R"~~~(
  2954. define_native_function(realm, vm.names.delete_, delete_, 1, default_attributes);
  2955. )~~~");
  2956. }
  2957. if (!interface.overload_sets.contains("clear"sv) && !interface.is_set_readonly) {
  2958. setlike_generator.append(R"~~~(
  2959. define_native_function(realm, vm.names.clear, clear, 0, default_attributes);
  2960. )~~~");
  2961. }
  2962. }
  2963. if (interface.has_unscopable_member) {
  2964. generator.append(R"~~~(
  2965. define_direct_property(vm.well_known_symbol_unscopables(), unscopable_object, JS::Attribute::Configurable);
  2966. )~~~");
  2967. }
  2968. generator.append(R"~~~(
  2969. define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "@namespaced_name@"_string), JS::Attribute::Configurable);
  2970. )~~~");
  2971. if (!is_global_interface) {
  2972. generator.append(R"~~~(
  2973. Base::initialize(realm);
  2974. )~~~");
  2975. }
  2976. generator.append(R"~~~(
  2977. }
  2978. )~~~");
  2979. if (!interface.attributes.is_empty() || !interface.functions.is_empty() || interface.has_stringifier) {
  2980. generator.append(R"~~~(
  2981. [[maybe_unused]] static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
  2982. {
  2983. auto this_value = vm.this_value();
  2984. JS::Object* this_object = nullptr;
  2985. if (this_value.is_nullish())
  2986. this_object = &vm.current_realm()->global_object();
  2987. else
  2988. this_object = TRY(this_value.to_object(vm));
  2989. )~~~");
  2990. if (interface.name.is_one_of("EventTarget", "Window")) {
  2991. generator.append(R"~~~(
  2992. if (is<HTML::Window>(this_object)) {
  2993. return static_cast<HTML::Window*>(this_object);
  2994. }
  2995. if (is<HTML::WindowProxy>(this_object)) {
  2996. return static_cast<HTML::WindowProxy*>(this_object)->window().ptr();
  2997. }
  2998. )~~~");
  2999. }
  3000. generator.append(R"~~~(
  3001. if (!is<@fully_qualified_name@>(this_object))
  3002. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@namespaced_name@");
  3003. return static_cast<@fully_qualified_name@*>(this_object);
  3004. }
  3005. )~~~");
  3006. }
  3007. for (auto& attribute : interface.attributes) {
  3008. if (attribute.extended_attributes.contains("FIXME"))
  3009. continue;
  3010. auto attribute_generator = generator.fork();
  3011. attribute_generator.set("attribute.name", attribute.name);
  3012. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  3013. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  3014. if (attribute.extended_attributes.contains("ImplementedAs")) {
  3015. auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value();
  3016. attribute_generator.set("attribute.cpp_name", implemented_as);
  3017. } else {
  3018. attribute_generator.set("attribute.cpp_name", attribute.name.to_snakecase());
  3019. }
  3020. if (attribute.extended_attributes.contains("Reflect")) {
  3021. auto attribute_name = attribute.extended_attributes.get("Reflect").value();
  3022. if (attribute_name.is_empty())
  3023. attribute_name = attribute.name;
  3024. attribute_name = make_input_acceptable_cpp(attribute_name);
  3025. attribute_generator.set("attribute.reflect_name", attribute_name);
  3026. } else {
  3027. attribute_generator.set("attribute.reflect_name", attribute.name.to_snakecase());
  3028. }
  3029. // For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
  3030. attribute_generator.append(R"~~~(
  3031. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@)
  3032. {
  3033. WebIDL::log_trace(vm, "@class_name@::@attribute.getter_callback@");
  3034. [[maybe_unused]] auto& realm = *vm.current_realm();
  3035. [[maybe_unused]] auto* impl = TRY(impl_from(vm));
  3036. )~~~");
  3037. if (attribute.extended_attributes.contains("CEReactions")) {
  3038. // 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
  3039. attribute_generator.append(R"~~~(
  3040. auto& relevant_agent = HTML::relevant_agent(*impl);
  3041. auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
  3042. auto& reactions_stack = custom_data->custom_element_reactions_stack;
  3043. reactions_stack.element_queue_stack.append({});
  3044. )~~~");
  3045. }
  3046. // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes
  3047. if (attribute.extended_attributes.contains("Reflect")) {
  3048. if (attribute.type->name() == "DOMString") {
  3049. if (!attribute.type->is_nullable()) {
  3050. // If a reflected IDL attribute has the type DOMString:
  3051. // * The getter steps are:
  3052. // 1. Let element be the result of running this's get the element.
  3053. // NOTE: this is "impl" above
  3054. // 2. Let contentAttributeValue be the result of running this's get the content attribute.
  3055. attribute_generator.append(R"~~~(
  3056. auto contentAttributeValue = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3057. )~~~");
  3058. // 3. Let attributeDefinition be the attribute definition of element's content attribute whose namespace is null
  3059. // and local name is the reflected content attribute name.
  3060. // NOTE: this is "attribute" above
  3061. // NOTE: We do steps 5 and 6 here to have a field to assign to
  3062. // 5. If contentAttributeValue is null, then return the empty string.
  3063. // 6. Return contentAttributeValue.
  3064. attribute_generator.append(R"~~~(
  3065. auto retval = contentAttributeValue.value_or(String {});
  3066. )~~~");
  3067. // 4. If attributeDefinition indicates it is an enumerated attribute and the reflected IDL attribute is defined to be limited to only known values:
  3068. if (attribute.extended_attributes.contains("Enumerated")) {
  3069. auto valid_enumerations_type = attribute.extended_attributes.get("Enumerated").value();
  3070. auto valid_enumerations = interface.enumerations.get(valid_enumerations_type).value();
  3071. auto missing_value_default = valid_enumerations.extended_attributes.get("MissingValueDefault");
  3072. auto invalid_value_default = valid_enumerations.extended_attributes.get("InvalidValueDefault");
  3073. attribute_generator.set("missing_enum_default_value", missing_value_default.has_value() ? missing_value_default.value().view() : ""sv);
  3074. attribute_generator.set("invalid_enum_default_value", invalid_value_default.has_value() ? invalid_value_default.value().view() : ""sv);
  3075. attribute_generator.set("valid_enum_values", MUST(String::join(", "sv, valid_enumerations.values.values(), "\"{}\"_string"sv)));
  3076. // 1. If contentAttributeValue does not correspond to any state of attributeDefinition (e.g., it is null and there is no missing value default),
  3077. // or that it is in a state of attributeDefinition with no associated keyword value, then return the empty string.
  3078. // NOTE: @invalid_enum_default_value@ is set to the empty string if it isn't present.
  3079. attribute_generator.append(R"~~~(
  3080. auto did_set_to_missing_value = false;
  3081. if (!contentAttributeValue.has_value()) {
  3082. retval = "@missing_enum_default_value@"_string;
  3083. did_set_to_missing_value = true;
  3084. }
  3085. Array valid_values { @valid_enum_values@ };
  3086. auto has_keyword = false;
  3087. for (auto const& value : valid_values) {
  3088. if (value.equals_ignoring_ascii_case(retval)) {
  3089. has_keyword = true;
  3090. retval = value;
  3091. break;
  3092. }
  3093. }
  3094. if (!has_keyword && !did_set_to_missing_value)
  3095. retval = "@invalid_enum_default_value@"_string;
  3096. )~~~");
  3097. // 2. Return the canonical keyword for the state of attributeDefinition that contentAttributeValue corresponds to.
  3098. // NOTE: This is known to be a valid keyword at this point, so we can just return "retval"
  3099. }
  3100. } else {
  3101. // If a reflected IDL attribute has the type DOMString?:
  3102. // * The getter steps are:
  3103. // 1. Let element be the result of running this's get the element.
  3104. // NOTE: this is "impl" above
  3105. // 2. Let contentAttributeValue be the result of running this's get the content attribute.
  3106. // 8. Return the canonical keyword for the state of attributeDefinition that contentAttributeValue corresponds to.
  3107. // NOTE: We run step 8 here to have a field to assign to
  3108. attribute_generator.append(R"~~~(
  3109. auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3110. )~~~");
  3111. // 3. Let attributeDefinition be the attribute definition of element's content attribute whose namespace is null
  3112. // and local name is the reflected content attribute name.
  3113. // NOTE: this is "attribute" above
  3114. // 4. Assert: attributeDefinition indicates it is an enumerated attribute.
  3115. // 5. Assert: the reflected IDL attribute is limited to only known values.
  3116. // NOTE: This is checked by the "Enumerated" extended attribute
  3117. auto is_enumerated = attribute.extended_attributes.contains("Enumerated");
  3118. VERIFY(is_enumerated);
  3119. // 6. Assert: contentAttributeValue corresponds to a state of attributeDefinition.
  3120. auto valid_enumerations_type = attribute.extended_attributes.get("Enumerated").value();
  3121. auto valid_enumerations = interface.enumerations.get(valid_enumerations_type).value();
  3122. auto missing_value_default = valid_enumerations.extended_attributes.get("MissingValueDefault");
  3123. auto invalid_value_default = valid_enumerations.extended_attributes.get("InvalidValueDefault");
  3124. attribute_generator.set("missing_enum_default_value", missing_value_default.has_value() ? missing_value_default.value().view() : ""sv);
  3125. attribute_generator.set("invalid_enum_default_value", invalid_value_default.has_value() ? invalid_value_default.value().view() : ""sv);
  3126. attribute_generator.set("valid_enum_values", MUST(String::join(", "sv, valid_enumerations.values.values(), "\"{}\"_string"sv)));
  3127. attribute_generator.append(R"~~~(
  3128. Array valid_values { @valid_enum_values@ };
  3129. )~~~");
  3130. if (invalid_value_default.has_value()) {
  3131. attribute_generator.append(R"~~~(
  3132. if (retval.has_value()) {
  3133. auto found = false;
  3134. for (auto const& value : valid_values) {
  3135. if (value.equals_ignoring_ascii_case(retval.value())) {
  3136. found = true;
  3137. retval = value;
  3138. break;
  3139. }
  3140. }
  3141. if (!found)
  3142. retval = "@invalid_enum_default_value@"_string;
  3143. }
  3144. )~~~");
  3145. }
  3146. if (missing_value_default.has_value()) {
  3147. attribute_generator.append(R"~~~(
  3148. if (!retval.has_value())
  3149. retval = "@missing_enum_default_value@"_string;
  3150. )~~~");
  3151. }
  3152. attribute_generator.append(R"~~~(
  3153. VERIFY(!retval.has_value() || valid_values.contains_slow(retval.value()));
  3154. )~~~");
  3155. // FIXME: 7. If contentAttributeValue corresponds to a state of attributeDefinition with no associated keyword value, then return null.
  3156. }
  3157. }
  3158. // If a reflected IDL attribute has the type boolean:
  3159. else if (attribute.type->name() == "boolean") {
  3160. // The getter steps are:
  3161. // 1. Let contentAttributeValue be the result of running this's get the content attribute.
  3162. // 2. If contentAttributeValue is null, then return false
  3163. attribute_generator.append(R"~~~(
  3164. auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3165. )~~~");
  3166. }
  3167. // If a reflected IDL attribute has the type long:
  3168. else if (attribute.type->name() == "long") {
  3169. // The getter steps are:
  3170. // 1. Let contentAttributeValue be the result of running this's get the content attribute.
  3171. // 2. If contentAttributeValue is not null:
  3172. // 1. Let parsedValue be the result of integer parsing contentAttributeValue if the reflected IDL attribute is not limited to only non-negative numbers;
  3173. // otherwise the result of non-negative integer parsing contentAttributeValue.
  3174. // 2. If parsedValue is not an error and is within the long range, then return parsedValue.
  3175. attribute_generator.append(R"~~~(
  3176. i32 retval = 0;
  3177. auto content_attribute_value = impl->get_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3178. if (content_attribute_value.has_value()) {
  3179. auto maybe_parsed_value = Web::HTML::parse_integer(*content_attribute_value);
  3180. if (maybe_parsed_value.has_value())
  3181. retval = *maybe_parsed_value;
  3182. }
  3183. )~~~");
  3184. }
  3185. // If a reflected IDL attribute has the type unsigned long,
  3186. // FIXME: optionally limited to only positive numbers, limited to only positive numbers with fallback, or clamped to the range [clampedMin, clampedMax], and optionally with a default value defaultValue:
  3187. else if (attribute.type->name() == "unsigned long") {
  3188. // The getter steps are:
  3189. // 1. Let contentAttributeValue be the result of running this's get the content attribute.
  3190. // 2. Let minimum be 0.
  3191. // FIXME: 3. If the reflected IDL attribute is limited to only positive numbers or limited to only positive numbers with fallback, then set minimum to 1.
  3192. // FIXME: 4. If the reflected IDL attribute is clamped to the range, then set minimum to clampedMin.
  3193. // 5. Let maximum be 2147483647 if the reflected IDL attribute is not clamped to the range; otherwise clampedMax.
  3194. // 6. If contentAttributeValue is not null:
  3195. // 1. Let parsedValue be the result of non-negative integer parsing contentAttributeValue.
  3196. // 2. If parsedValue is not an error and is in the range minimum to maximum, inclusive, then return parsedValue.
  3197. // FIXME: 3. If parsedValue is not an error and the reflected IDL attribute is clamped to the range:
  3198. // FIXME: 1. If parsedValue is less than minimum, then return minimum.
  3199. // FIXME: 2. Return maximum.
  3200. attribute_generator.append(R"~~~(
  3201. u32 retval = 0;
  3202. auto content_attribute_value = impl->get_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3203. u32 minimum = 0;
  3204. u32 maximum = 2147483647;
  3205. if (content_attribute_value.has_value()) {
  3206. auto parsed_value = Web::HTML::parse_non_negative_integer(*content_attribute_value);
  3207. if (parsed_value.has_value()) {
  3208. if (*parsed_value >= minimum && *parsed_value <= maximum) {
  3209. retval = *parsed_value;
  3210. }
  3211. }
  3212. }
  3213. )~~~");
  3214. }
  3215. // If a reflected IDL attribute has the type USVString:
  3216. else if (attribute.type->name() == "USVString") {
  3217. // The getter steps are:
  3218. // 1. Let element be the result of running this's get the element.
  3219. // NOTE: this is "impl" above
  3220. // 2. Let contentAttributeValue be the result of running this's get the content attribute.
  3221. attribute_generator.append(R"~~~(
  3222. auto content_attribute_value = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3223. )~~~");
  3224. // 3. Let attributeDefinition be the attribute definition of element's content attribute whose namespace is null and local name is the reflected content attribute name.
  3225. // NOTE: this is "attribute" above
  3226. // 4. If attributeDefinition indicates it contains a URL:
  3227. if (attribute.extended_attributes.contains("URL")) {
  3228. // 1. If contentAttributeValue is null, then return the empty string.
  3229. // 2. Let urlString be the result of encoding-parsing-and-serializing a URL given contentAttributeValue, relative to element's node document.
  3230. // 3. If urlString is not failure, then return urlString.
  3231. attribute_generator.append(R"~~~(
  3232. if (!content_attribute_value.has_value())
  3233. return JS::PrimitiveString::create(vm, String {});
  3234. auto url_string = impl->document().encoding_parse_and_serialize_url(*content_attribute_value);
  3235. if (url_string.has_value())
  3236. return JS::PrimitiveString::create(vm, url_string.release_value());
  3237. )~~~");
  3238. }
  3239. // 5. Return contentAttributeValue, converted to a scalar value string.
  3240. attribute_generator.append(R"~~~(
  3241. String retval;
  3242. if (content_attribute_value.has_value())
  3243. retval = MUST(Infra::convert_to_scalar_value_string(*content_attribute_value));
  3244. )~~~");
  3245. } else {
  3246. attribute_generator.append(R"~~~(
  3247. auto retval = impl->get_attribute_value(HTML::AttributeNames::@attribute.reflect_name@);
  3248. )~~~");
  3249. }
  3250. if (attribute.extended_attributes.contains("CEReactions")) {
  3251. // 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
  3252. // 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
  3253. // 4. Invoke custom element reactions in queue.
  3254. // 5. If an exception exception was thrown by the original steps, rethrow exception.
  3255. // 6. If a value value was returned from the original steps, return value.
  3256. attribute_generator.append(R"~~~(
  3257. auto queue = reactions_stack.element_queue_stack.take_last();
  3258. Bindings::invoke_custom_element_reactions(queue);
  3259. )~~~");
  3260. }
  3261. } else {
  3262. if (!attribute.extended_attributes.contains("CEReactions")) {
  3263. attribute_generator.append(R"~~~(
  3264. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); }));
  3265. )~~~");
  3266. } else {
  3267. // 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
  3268. // 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
  3269. // 4. Invoke custom element reactions in queue.
  3270. // 5. If an exception exception was thrown by the original steps, rethrow exception.
  3271. // 6. If a value value was returned from the original steps, return value.
  3272. attribute_generator.append(R"~~~(
  3273. auto retval_or_exception = throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); });
  3274. auto queue = reactions_stack.element_queue_stack.take_last();
  3275. Bindings::invoke_custom_element_reactions(queue);
  3276. if (retval_or_exception.is_error())
  3277. return retval_or_exception.release_error();
  3278. auto retval = retval_or_exception.release_value();
  3279. )~~~");
  3280. }
  3281. }
  3282. generate_return_statement(generator, *attribute.type, interface);
  3283. attribute_generator.append(R"~~~(
  3284. }
  3285. )~~~");
  3286. if (!attribute.readonly) {
  3287. // For [CEReactions]: https://html.spec.whatwg.org/multipage/custom-elements.html#cereactions
  3288. attribute_generator.append(R"~~~(
  3289. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
  3290. {
  3291. WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
  3292. [[maybe_unused]] auto& realm = *vm.current_realm();
  3293. auto* impl = TRY(impl_from(vm));
  3294. auto value = vm.argument(0);
  3295. )~~~");
  3296. if (attribute.extended_attributes.contains("CEReactions")) {
  3297. // 1. Push a new element queue onto this object's relevant agent's custom element reactions stack.
  3298. attribute_generator.append(R"~~~(
  3299. auto& relevant_agent = HTML::relevant_agent(*impl);
  3300. auto* custom_data = verify_cast<Bindings::WebEngineCustomData>(relevant_agent.custom_data());
  3301. auto& reactions_stack = custom_data->custom_element_reactions_stack;
  3302. reactions_stack.element_queue_stack.append({});
  3303. )~~~");
  3304. }
  3305. generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
  3306. if (attribute.extended_attributes.contains("Reflect")) {
  3307. if (attribute.type->name() == "boolean") {
  3308. attribute_generator.append(R"~~~(
  3309. if (!cpp_value)
  3310. impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3311. else
  3312. MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String {}));
  3313. )~~~");
  3314. } else if (attribute.type->name() == "unsigned long") {
  3315. // The setter steps are:
  3316. // FIXME: 1. If the reflected IDL attribute is limited to only positive numbers and the given value is 0, then throw an "IndexSizeError" DOMException.
  3317. // 2. Let minimum be 0.
  3318. // FIXME: 3. If the reflected IDL attribute is limited to only positive numbers or limited to only positive numbers with fallback, then set minimum to 1.
  3319. // 4. Let newValue be minimum.
  3320. // FIXME: 5. If the reflected IDL attribute has a default value, then set newValue to defaultValue.
  3321. // 6. If the given value is in the range minimum to 2147483647, inclusive, then set newValue to it.
  3322. // 7. Run this's set the content attribute with newValue converted to the shortest possible string representing the number as a valid non-negative integer.
  3323. attribute_generator.append(R"~~~(
  3324. u32 minimum = 0;
  3325. u32 new_value = minimum;
  3326. if (cpp_value >= minimum && cpp_value <= 2147483647)
  3327. new_value = cpp_value;
  3328. MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String::number(new_value)));
  3329. )~~~");
  3330. } else if (attribute.type->is_integer() && !attribute.type->is_nullable()) {
  3331. attribute_generator.append(R"~~~(
  3332. MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String::number(cpp_value)));
  3333. )~~~");
  3334. } else if (attribute.type->is_nullable()) {
  3335. attribute_generator.append(R"~~~(
  3336. if (!cpp_value.has_value())
  3337. impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  3338. else
  3339. MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value.value()));
  3340. )~~~");
  3341. } else {
  3342. attribute_generator.append(R"~~~(
  3343. MUST(impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value));
  3344. )~~~");
  3345. }
  3346. if (attribute.extended_attributes.contains("CEReactions")) {
  3347. // 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
  3348. // 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
  3349. // 4. Invoke custom element reactions in queue.
  3350. // 5. If an exception exception was thrown by the original steps, rethrow exception.
  3351. // 6. If a value value was returned from the original steps, return value.
  3352. attribute_generator.append(R"~~~(
  3353. auto queue = reactions_stack.element_queue_stack.take_last();
  3354. Bindings::invoke_custom_element_reactions(queue);
  3355. )~~~");
  3356. }
  3357. } else {
  3358. if (!attribute.extended_attributes.contains("CEReactions")) {
  3359. attribute_generator.append(R"~~~(
  3360. TRY(throw_dom_exception_if_needed(vm, [&] { return impl->set_@attribute.cpp_name@(cpp_value); }));
  3361. )~~~");
  3362. } else {
  3363. // 2. Run the originally-specified steps for this construct, catching any exceptions. If the steps return a value, let value be the returned value. If they throw an exception, let exception be the thrown exception.
  3364. // 3. Let queue be the result of popping from this object's relevant agent's custom element reactions stack.
  3365. // 4. Invoke custom element reactions in queue.
  3366. // 5. If an exception exception was thrown by the original steps, rethrow exception.
  3367. // 6. If a value value was returned from the original steps, return value.
  3368. attribute_generator.append(R"~~~(
  3369. auto maybe_exception = throw_dom_exception_if_needed(vm, [&] { return impl->set_@attribute.cpp_name@(cpp_value); });
  3370. auto queue = reactions_stack.element_queue_stack.take_last();
  3371. Bindings::invoke_custom_element_reactions(queue);
  3372. if (maybe_exception.is_error())
  3373. return maybe_exception.release_error();
  3374. )~~~");
  3375. }
  3376. }
  3377. attribute_generator.append(R"~~~(
  3378. return JS::js_undefined();
  3379. }
  3380. )~~~");
  3381. } else if (attribute.extended_attributes.contains("Replaceable"sv)) {
  3382. if (interface.name == "Window"sv) {
  3383. attribute_generator.append(R"~~~(
  3384. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
  3385. {
  3386. WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
  3387. auto this_value = vm.this_value();
  3388. GC::Ptr<Window> window;
  3389. if (this_value.is_object()) {
  3390. if (is<WindowProxy>(this_value.as_object())) {
  3391. auto& window_proxy = static_cast<WindowProxy&>(this_value.as_object());
  3392. window = window_proxy.window();
  3393. } else if (is<Window>(this_value.as_object())) {
  3394. window = &static_cast<Window&>(this_value.as_object());
  3395. }
  3396. }
  3397. if (window) {
  3398. TRY(window->internal_define_own_property("@attribute.name@", JS::PropertyDescriptor { .value = vm.argument(0), .writable = true }));
  3399. return JS::js_undefined();
  3400. }
  3401. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@namespaced_name@");
  3402. }
  3403. )~~~");
  3404. } else {
  3405. attribute_generator.append(R"~~~(
  3406. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
  3407. {
  3408. WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
  3409. auto this_value = vm.this_value();
  3410. if (!this_value.is_object() || !is<@fully_qualified_name@>(this_value.as_object()))
  3411. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@namespaced_name@");
  3412. TRY(this_value.as_object().internal_define_own_property("@attribute.name@", JS::PropertyDescriptor { .value = vm.argument(0), .writable = true }));
  3413. return JS::js_undefined();
  3414. }
  3415. )~~~");
  3416. }
  3417. } else if (auto put_forwards_identifier = attribute.extended_attributes.get("PutForwards"sv); put_forwards_identifier.has_value()) {
  3418. attribute_generator.set("put_forwards_identifier"sv, *put_forwards_identifier);
  3419. VERIFY(!put_forwards_identifier->is_empty() && !is_ascii_digit(put_forwards_identifier->byte_at(0))); // Ensure `PropertyKey`s are not Numbers.
  3420. attribute_generator.append(R"~~~(
  3421. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
  3422. {
  3423. WebIDL::log_trace(vm, "@class_name@::@attribute.setter_callback@");
  3424. auto* impl = TRY(impl_from(vm));
  3425. auto value = vm.argument(0);
  3426. auto receiver = TRY(throw_dom_exception_if_needed(vm, [&]() { return impl->@attribute.cpp_name@(); }));
  3427. TRY(receiver->set(JS::PropertyKey { "@put_forwards_identifier@", JS::PropertyKey::StringMayBeNumber::No }, value, JS::Object::ShouldThrowExceptions::Yes));
  3428. return JS::js_undefined();
  3429. }
  3430. )~~~");
  3431. }
  3432. }
  3433. // Implementation: Functions
  3434. for (auto& function : interface.functions) {
  3435. if (function.extended_attributes.contains("FIXME"))
  3436. continue;
  3437. if (function.extended_attributes.contains("Default")) {
  3438. if (function.name == "toJSON"sv && function.return_type->name() == "object"sv) {
  3439. generate_default_to_json_function(generator, class_name, interface);
  3440. continue;
  3441. }
  3442. dbgln("Unknown default operation: {} {}()", function.return_type->name(), function.name);
  3443. VERIFY_NOT_REACHED();
  3444. }
  3445. generate_function(generator, function, StaticFunction::No, class_name, interface.fully_qualified_name, interface);
  3446. }
  3447. for (auto const& overload_set : interface.overload_sets) {
  3448. if (overload_set.value.size() == 1)
  3449. continue;
  3450. generate_overload_arbiter(generator, overload_set, interface, class_name, IsConstructor::No);
  3451. }
  3452. if (interface.has_stringifier) {
  3453. auto stringifier_generator = generator.fork();
  3454. stringifier_generator.set("class_name", class_name);
  3455. if (interface.stringifier_attribute.has_value())
  3456. stringifier_generator.set("attribute.cpp_getter_name", interface.stringifier_attribute->to_snakecase());
  3457. stringifier_generator.append(R"~~~(
  3458. JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
  3459. {
  3460. WebIDL::log_trace(vm, "@class_name@::to_string");
  3461. [[maybe_unused]] auto& realm = *vm.current_realm();
  3462. auto* impl = TRY(impl_from(vm));
  3463. )~~~");
  3464. if (interface.stringifier_attribute.has_value()) {
  3465. stringifier_generator.append(R"~~~(
  3466. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_getter_name@(); }));
  3467. )~~~");
  3468. } else {
  3469. stringifier_generator.append(R"~~~(
  3470. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->to_string(); }));
  3471. )~~~");
  3472. }
  3473. stringifier_generator.append(R"~~~(
  3474. return JS::PrimitiveString::create(vm, move(retval));
  3475. }
  3476. )~~~");
  3477. }
  3478. if (interface.pair_iterator_types.has_value()) {
  3479. auto iterator_generator = generator.fork();
  3480. iterator_generator.append(R"~~~(
  3481. JS_DEFINE_NATIVE_FUNCTION(@class_name@::entries)
  3482. {
  3483. WebIDL::log_trace(vm, "@class_name@::entries");
  3484. auto* impl = TRY(impl_from(vm));
  3485. return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::KeyAndValue); }));
  3486. }
  3487. JS_DEFINE_NATIVE_FUNCTION(@class_name@::for_each)
  3488. {
  3489. WebIDL::log_trace(vm, "@class_name@::for_each");
  3490. [[maybe_unused]] auto& realm = *vm.current_realm();
  3491. auto* impl = TRY(impl_from(vm));
  3492. auto callback = vm.argument(0);
  3493. if (!callback.is_function())
  3494. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, callback.to_string_without_side_effects());
  3495. auto this_value = vm.this_value();
  3496. TRY(impl->for_each([&](auto key, auto value) -> JS::ThrowCompletionOr<void> {
  3497. )~~~");
  3498. generate_variable_statement(iterator_generator, "wrapped_key", interface.pair_iterator_types->get<0>(), "key", interface);
  3499. generate_variable_statement(iterator_generator, "wrapped_value", interface.pair_iterator_types->get<1>(), "value", interface);
  3500. iterator_generator.append(R"~~~(
  3501. TRY(JS::call(vm, callback.as_function(), vm.argument(1), wrapped_value, wrapped_key, this_value));
  3502. return {};
  3503. }));
  3504. return JS::js_undefined();
  3505. }
  3506. JS_DEFINE_NATIVE_FUNCTION(@class_name@::keys)
  3507. {
  3508. WebIDL::log_trace(vm, "@class_name@::keys");
  3509. auto* impl = TRY(impl_from(vm));
  3510. return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::Key); }));
  3511. }
  3512. JS_DEFINE_NATIVE_FUNCTION(@class_name@::values)
  3513. {
  3514. WebIDL::log_trace(vm, "@class_name@::values");
  3515. auto* impl = TRY(impl_from(vm));
  3516. return TRY(throw_dom_exception_if_needed(vm, [&] { return @iterator_name@::create(*impl, Object::PropertyKind::Value); }));
  3517. }
  3518. )~~~");
  3519. }
  3520. if (interface.set_entry_type.has_value()) {
  3521. auto setlike_generator = generator.fork();
  3522. setlike_generator.set("value_type", interface.set_entry_type.value()->name());
  3523. setlike_generator.append(R"~~~(
  3524. // https://webidl.spec.whatwg.org/#js-set-size
  3525. JS_DEFINE_NATIVE_FUNCTION(@class_name@::get_size)
  3526. {
  3527. WebIDL::log_trace(vm, "@class_name@::size");
  3528. auto* impl = TRY(impl_from(vm));
  3529. GC::Ref<JS::Set> set = impl->set_entries();
  3530. return set->set_size();
  3531. }
  3532. // https://webidl.spec.whatwg.org/#js-set-entries
  3533. JS_DEFINE_NATIVE_FUNCTION(@class_name@::entries)
  3534. {
  3535. WebIDL::log_trace(vm, "@class_name@::entries");
  3536. auto& realm = *vm.current_realm();
  3537. auto* impl = TRY(impl_from(vm));
  3538. GC::Ref<JS::Set> set = impl->set_entries();
  3539. return TRY(throw_dom_exception_if_needed(vm, [&] { return JS::SetIterator::create(realm, *set, Object::PropertyKind::KeyAndValue); }));
  3540. }
  3541. // https://webidl.spec.whatwg.org/#js-set-values
  3542. JS_DEFINE_NATIVE_FUNCTION(@class_name@::values)
  3543. {
  3544. WebIDL::log_trace(vm, "@class_name@::values");
  3545. auto& realm = *vm.current_realm();
  3546. auto* impl = TRY(impl_from(vm));
  3547. GC::Ref<JS::Set> set = impl->set_entries();
  3548. return TRY(throw_dom_exception_if_needed(vm, [&] { return JS::SetIterator::create(realm, *set, Object::PropertyKind::Value); }));
  3549. }
  3550. // https://webidl.spec.whatwg.org/#js-set-forEach
  3551. JS_DEFINE_NATIVE_FUNCTION(@class_name@::for_each)
  3552. {
  3553. WebIDL::log_trace(vm, "@class_name@::for_each");
  3554. auto* impl = TRY(impl_from(vm));
  3555. GC::Ref<JS::Set> set = impl->set_entries();
  3556. auto callback = vm.argument(0);
  3557. if (!callback.is_function())
  3558. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, callback.to_string_without_side_effects());
  3559. for (auto& entry : *set) {
  3560. auto value = entry.key;
  3561. TRY(JS::call(vm, callback.as_function(), vm.argument(1), value, value, impl));
  3562. }
  3563. return JS::js_undefined();
  3564. }
  3565. // https://webidl.spec.whatwg.org/#js-set-has
  3566. JS_DEFINE_NATIVE_FUNCTION(@class_name@::has)
  3567. {
  3568. WebIDL::log_trace(vm, "@class_name@::has");
  3569. auto* impl = TRY(impl_from(vm));
  3570. GC::Ref<JS::Set> set = impl->set_entries();
  3571. auto value_arg = vm.argument(0);
  3572. if (!value_arg.is_object() && !is<@value_type@>(value_arg.as_object())) {
  3573. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@value_type@");
  3574. }
  3575. // FIXME: If value is -0, set value to +0.
  3576. // What? Which interfaces have a number as their set type?
  3577. return set->set_has(value_arg);
  3578. }
  3579. )~~~");
  3580. if (!interface.overload_sets.contains("add"sv) && !interface.is_set_readonly) {
  3581. setlike_generator.append(R"~~~(
  3582. // https://webidl.spec.whatwg.org/#js-set-add
  3583. JS_DEFINE_NATIVE_FUNCTION(@class_name@::add)
  3584. {
  3585. WebIDL::log_trace(vm, "@class_name@::add");
  3586. auto* impl = TRY(impl_from(vm));
  3587. GC::Ref<JS::Set> set = impl->set_entries();
  3588. auto value_arg = vm.argument(0);
  3589. if (!value_arg.is_object() && !is<@value_type@>(value_arg.as_object())) {
  3590. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@value_type@");
  3591. }
  3592. // FIXME: If value is -0, set value to +0.
  3593. // What? Which interfaces have a number as their set type?
  3594. set->set_add(value_arg);
  3595. return impl;
  3596. }
  3597. )~~~");
  3598. }
  3599. if (!interface.overload_sets.contains("delete"sv) && !interface.is_set_readonly) {
  3600. setlike_generator.append(R"~~~(
  3601. // https://webidl.spec.whatwg.org/#js-set-delete
  3602. JS_DEFINE_NATIVE_FUNCTION(@class_name@::delete_)
  3603. {
  3604. WebIDL::log_trace(vm, "@class_name@::delete_");
  3605. auto* impl = TRY(impl_from(vm));
  3606. GC::Ref<JS::Set> set = impl->set_entries();
  3607. auto value_arg = vm.argument(0);
  3608. if (!value_arg.is_object() && !is<@value_type@>(value_arg.as_object())) {
  3609. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@value_type@");
  3610. }
  3611. // FIXME: If value is -0, set value to +0.
  3612. // What? Which interfaces have a number as their set type?
  3613. return set->set_remove(value_arg);
  3614. }
  3615. )~~~");
  3616. }
  3617. if (!interface.overload_sets.contains("clear"sv) && !interface.is_set_readonly) {
  3618. setlike_generator.append(R"~~~(
  3619. // https://webidl.spec.whatwg.org/#js-set-clear
  3620. JS_DEFINE_NATIVE_FUNCTION(@class_name@::clear)
  3621. {
  3622. WebIDL::log_trace(vm, "@class_name@::clear");
  3623. auto* impl = TRY(impl_from(vm));
  3624. GC::Ref<JS::Set> set = impl->set_entries();
  3625. set->set_clear();
  3626. return JS::js_undefined();
  3627. }
  3628. )~~~");
  3629. }
  3630. }
  3631. }
  3632. void generate_namespace_header(IDL::Interface const& interface, StringBuilder& builder)
  3633. {
  3634. SourceGenerator generator { builder };
  3635. generator.set("namespace_class", interface.namespace_class);
  3636. generator.append(R"~~~(
  3637. #pragma once
  3638. #include <LibJS/Runtime/Object.h>
  3639. namespace Web::Bindings {
  3640. class @namespace_class@ final : public JS::Object {
  3641. JS_OBJECT(@namespace_class@, JS::Object);
  3642. GC_DECLARE_ALLOCATOR(@namespace_class@);
  3643. public:
  3644. explicit @namespace_class@(JS::Realm&);
  3645. virtual void initialize(JS::Realm&) override;
  3646. virtual ~@namespace_class@() override;
  3647. private:
  3648. )~~~");
  3649. if (interface.extended_attributes.contains("WithGCVisitor"sv)) {
  3650. generator.append(R"~~~(
  3651. virtual void visit_edges(JS::Cell::Visitor&) override;
  3652. )~~~");
  3653. }
  3654. if (interface.extended_attributes.contains("WithFinalizer"sv)) {
  3655. generator.append(R"~~~(
  3656. virtual void finalize() override;
  3657. )~~~");
  3658. }
  3659. for (auto const& overload_set : interface.overload_sets) {
  3660. auto function_generator = generator.fork();
  3661. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  3662. function_generator.append(R"~~~(
  3663. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
  3664. )~~~");
  3665. if (overload_set.value.size() > 1) {
  3666. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  3667. function_generator.set("overload_suffix", ByteString::number(i));
  3668. function_generator.append(R"~~~(
  3669. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
  3670. )~~~");
  3671. }
  3672. }
  3673. }
  3674. generator.append(R"~~~(
  3675. };
  3676. } // namespace Web::Bindings
  3677. )~~~");
  3678. }
  3679. static void generate_using_namespace_definitions(SourceGenerator& generator)
  3680. {
  3681. generator.append(R"~~~(
  3682. // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
  3683. using namespace Web::Animations;
  3684. using namespace Web::Clipboard;
  3685. using namespace Web::Crypto;
  3686. using namespace Web::CSS;
  3687. using namespace Web::DOM;
  3688. using namespace Web::DOMParsing;
  3689. using namespace Web::DOMURL;
  3690. using namespace Web::Encoding;
  3691. using namespace Web::EntriesAPI;
  3692. using namespace Web::EventTiming;
  3693. using namespace Web::Fetch;
  3694. using namespace Web::FileAPI;
  3695. using namespace Web::Geometry;
  3696. using namespace Web::HighResolutionTime;
  3697. using namespace Web::HTML;
  3698. using namespace Web::IndexedDB;
  3699. using namespace Web::Internals;
  3700. using namespace Web::IntersectionObserver;
  3701. using namespace Web::MediaCapabilitiesAPI;
  3702. using namespace Web::MediaSourceExtensions;
  3703. using namespace Web::NavigationTiming;
  3704. using namespace Web::PerformanceTimeline;
  3705. using namespace Web::RequestIdleCallback;
  3706. using namespace Web::ResizeObserver;
  3707. using namespace Web::Selection;
  3708. using namespace Web::ServiceWorker;
  3709. using namespace Web::StorageAPI;
  3710. using namespace Web::Streams;
  3711. using namespace Web::SVG;
  3712. using namespace Web::UIEvents;
  3713. using namespace Web::UserTiming;
  3714. using namespace Web::WebAssembly;
  3715. using namespace Web::WebAudio;
  3716. using namespace Web::WebGL;
  3717. using namespace Web::WebIDL;
  3718. using namespace Web::WebVTT;
  3719. using namespace Web::XHR;
  3720. )~~~"sv);
  3721. }
  3722. void generate_namespace_implementation(IDL::Interface const& interface, StringBuilder& builder)
  3723. {
  3724. SourceGenerator generator { builder };
  3725. generator.set("name", interface.name);
  3726. generator.set("namespace_class", interface.namespace_class);
  3727. generator.set("interface_name", interface.name);
  3728. generator.append(R"~~~(
  3729. #include <AK/Function.h>
  3730. #include <LibIDL/Types.h>
  3731. #include <LibJS/Runtime/ArrayBuffer.h>
  3732. #include <LibJS/Runtime/DataView.h>
  3733. #include <LibJS/Runtime/Error.h>
  3734. #include <LibJS/Runtime/PrimitiveString.h>
  3735. #include <LibJS/Runtime/PromiseConstructor.h>
  3736. #include <LibJS/Runtime/TypedArray.h>
  3737. #include <LibJS/Runtime/Value.h>
  3738. #include <LibJS/Runtime/ValueInlines.h>
  3739. #include <LibWeb/Bindings/@namespace_class@.h>
  3740. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  3741. #include <LibWeb/Bindings/Intrinsics.h>
  3742. #include <LibWeb/HTML/Window.h>
  3743. #include <LibWeb/HTML/WindowProxy.h>
  3744. #include <LibWeb/WebIDL/AbstractOperations.h>
  3745. #include <LibWeb/WebIDL/Buffers.h>
  3746. #include <LibWeb/WebIDL/OverloadResolution.h>
  3747. #include <LibWeb/WebIDL/Promise.h>
  3748. #include <LibWeb/WebIDL/Tracing.h>
  3749. #include <LibWeb/WebIDL/Types.h>
  3750. )~~~");
  3751. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  3752. generate_using_namespace_definitions(generator);
  3753. generator.append(R"~~~(
  3754. namespace Web::Bindings {
  3755. GC_DEFINE_ALLOCATOR(@namespace_class@);
  3756. @namespace_class@::@namespace_class@(JS::Realm& realm)
  3757. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  3758. {
  3759. }
  3760. @namespace_class@::~@namespace_class@()
  3761. {
  3762. }
  3763. void @namespace_class@::initialize(JS::Realm& realm)
  3764. {
  3765. [[maybe_unused]] auto& vm = this->vm();
  3766. [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
  3767. Base::initialize(realm);
  3768. define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "@interface_name@"_string), JS::Attribute::Configurable);
  3769. )~~~");
  3770. // https://webidl.spec.whatwg.org/#es-operations
  3771. for (auto const& overload_set : interface.overload_sets) {
  3772. auto function_generator = generator.fork();
  3773. function_generator.set("function.name", overload_set.key);
  3774. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  3775. function_generator.set("function.length", ByteString::number(get_shortest_function_length(overload_set.value)));
  3776. function_generator.append(R"~~~(
  3777. define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, default_attributes);
  3778. )~~~");
  3779. }
  3780. generator.append(R"~~~(
  3781. }
  3782. )~~~");
  3783. if (interface.extended_attributes.contains("WithGCVisitor"sv)) {
  3784. generator.append(R"~~~(
  3785. void @namespace_class@::visit_edges(JS::Cell::Visitor& visitor)
  3786. {
  3787. Base::visit_edges(visitor);
  3788. @name@::visit_edges(*this, visitor);
  3789. }
  3790. )~~~");
  3791. }
  3792. if (interface.extended_attributes.contains("WithFinalizer"sv)) {
  3793. generator.append(R"~~~(
  3794. void @namespace_class@::finalize()
  3795. {
  3796. @name@::finalize(*this);
  3797. }
  3798. )~~~");
  3799. }
  3800. for (auto const& function : interface.functions) {
  3801. if (function.extended_attributes.contains("FIXME"))
  3802. continue;
  3803. generate_function(generator, function, StaticFunction::Yes, interface.namespace_class, interface.name, interface);
  3804. }
  3805. for (auto const& overload_set : interface.overload_sets) {
  3806. if (overload_set.value.size() == 1)
  3807. continue;
  3808. generate_overload_arbiter(generator, overload_set, interface, interface.namespace_class, IsConstructor::No);
  3809. }
  3810. generator.append(R"~~~(
  3811. } // namespace Web::Bindings
  3812. )~~~");
  3813. }
  3814. void generate_constructor_header(IDL::Interface const& interface, StringBuilder& builder)
  3815. {
  3816. SourceGenerator generator { builder };
  3817. generator.set("constructor_class", interface.constructor_class);
  3818. generator.append(R"~~~(
  3819. #pragma once
  3820. #include <LibJS/Runtime/NativeFunction.h>
  3821. namespace Web::Bindings {
  3822. class @constructor_class@ : public JS::NativeFunction {
  3823. JS_OBJECT(@constructor_class@, JS::NativeFunction);
  3824. GC_DECLARE_ALLOCATOR(@constructor_class@);
  3825. public:
  3826. explicit @constructor_class@(JS::Realm&);
  3827. virtual void initialize(JS::Realm&) override;
  3828. virtual ~@constructor_class@() override;
  3829. virtual JS::ThrowCompletionOr<JS::Value> call() override;
  3830. virtual JS::ThrowCompletionOr<GC::Ref<JS::Object>> construct(JS::FunctionObject& new_target) override;
  3831. private:
  3832. virtual bool has_constructor() const override { return true; }
  3833. )~~~");
  3834. for (auto& attribute : interface.static_attributes) {
  3835. auto attribute_generator = generator.fork();
  3836. attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase());
  3837. attribute_generator.append(R"~~~(
  3838. JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_getter);
  3839. )~~~");
  3840. if (!attribute.readonly) {
  3841. attribute_generator.append(R"~~~(
  3842. JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_setter);
  3843. )~~~");
  3844. }
  3845. }
  3846. for (auto const& overload_set : interface.constructor_overload_sets) {
  3847. auto constructor_generator = generator.fork();
  3848. if (overload_set.value.size() > 1) {
  3849. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  3850. constructor_generator.set("overload_suffix", ByteString::number(i));
  3851. constructor_generator.append(R"~~~(
  3852. JS::ThrowCompletionOr<GC::Ref<JS::Object>> construct@overload_suffix@(JS::FunctionObject& new_target);
  3853. )~~~");
  3854. }
  3855. }
  3856. }
  3857. for (auto const& overload_set : interface.static_overload_sets) {
  3858. auto function_generator = generator.fork();
  3859. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  3860. function_generator.append(R"~~~(
  3861. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
  3862. )~~~");
  3863. if (overload_set.value.size() > 1) {
  3864. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  3865. function_generator.set("overload_suffix", ByteString::number(i));
  3866. function_generator.append(R"~~~(
  3867. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
  3868. )~~~");
  3869. }
  3870. }
  3871. }
  3872. generator.append(R"~~~(
  3873. };
  3874. } // namespace Web::Bindings
  3875. )~~~");
  3876. }
  3877. // https://webidl.spec.whatwg.org/#define-the-operations
  3878. static void define_the_operations(SourceGenerator& generator, HashMap<ByteString, Vector<Function&>> const& operations)
  3879. {
  3880. for (auto const& operation : operations) {
  3881. auto function_generator = generator.fork();
  3882. function_generator.set("function.name", operation.key);
  3883. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(operation.key.to_snakecase()));
  3884. function_generator.set("function.length", ByteString::number(get_shortest_function_length(operation.value)));
  3885. // NOTE: This assumes that every function in the overload set has the same attribute set.
  3886. if (operation.value[0].extended_attributes.contains("LegacyUnforgable"sv))
  3887. function_generator.set("function.attributes", "JS::Attribute::Enumerable");
  3888. else
  3889. function_generator.set("function.attributes", "JS::Attribute::Writable | JS::Attribute::Enumerable | JS::Attribute::Configurable");
  3890. function_generator.append(R"~~~(
  3891. define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, @function.attributes@);
  3892. )~~~");
  3893. }
  3894. }
  3895. void generate_constructor_implementation(IDL::Interface const& interface, StringBuilder& builder)
  3896. {
  3897. SourceGenerator generator { builder };
  3898. generator.set("name", interface.name);
  3899. generator.set("namespaced_name", interface.namespaced_name);
  3900. generator.set("prototype_class", interface.prototype_class);
  3901. generator.set("constructor_class", interface.constructor_class);
  3902. generator.set("fully_qualified_name", interface.fully_qualified_name);
  3903. generator.set("parent_name", interface.parent_name);
  3904. generator.set("prototype_base_class", interface.prototype_base_class);
  3905. generator.append(R"~~~(
  3906. #include <LibIDL/Types.h>
  3907. #include <LibGC/Heap.h>
  3908. #include <LibJS/Runtime/ArrayBuffer.h>
  3909. #include <LibJS/Runtime/DataView.h>
  3910. #include <LibJS/Runtime/GlobalObject.h>
  3911. #include <LibJS/Runtime/Iterator.h>
  3912. #include <LibJS/Runtime/ValueInlines.h>
  3913. #include <LibJS/Runtime/TypedArray.h>
  3914. #include <LibWeb/Bindings/@constructor_class@.h>
  3915. #include <LibWeb/Bindings/@prototype_class@.h>
  3916. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  3917. #include <LibWeb/Bindings/Intrinsics.h>
  3918. #include <LibWeb/HTML/WindowProxy.h>
  3919. #include <LibWeb/WebIDL/AbstractOperations.h>
  3920. #include <LibWeb/WebIDL/Buffers.h>
  3921. #include <LibWeb/WebIDL/CallbackType.h>
  3922. #include <LibWeb/WebIDL/OverloadResolution.h>
  3923. #include <LibWeb/WebIDL/Tracing.h>
  3924. #include <LibWeb/WebIDL/Types.h>
  3925. #if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)
  3926. # include <LibWeb/Bindings/@prototype_base_class@.h>
  3927. #endif
  3928. )~~~");
  3929. if (interface.constructors.size() == 1) {
  3930. auto& constructor = interface.constructors[0];
  3931. if (constructor.extended_attributes.contains("HTMLConstructor"sv)) {
  3932. generator.append(R"~~~(
  3933. #include <LibJS/Runtime/AbstractOperations.h>
  3934. #include <LibWeb/DOM/ElementFactory.h>
  3935. #include <LibWeb/HTML/CustomElements/CustomElementRegistry.h>
  3936. #include <LibWeb/HTML/CustomElements/CustomElementDefinition.h>
  3937. #include <LibWeb/HTML/Window.h>
  3938. #include <LibWeb/Namespace.h>
  3939. )~~~");
  3940. }
  3941. }
  3942. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  3943. generate_using_namespace_definitions(generator);
  3944. generator.append(R"~~~(
  3945. namespace Web::Bindings {
  3946. GC_DEFINE_ALLOCATOR(@constructor_class@);
  3947. @constructor_class@::@constructor_class@(JS::Realm& realm)
  3948. : NativeFunction("@name@"sv, realm.intrinsics().function_prototype())
  3949. {
  3950. }
  3951. @constructor_class@::~@constructor_class@()
  3952. {
  3953. }
  3954. JS::ThrowCompletionOr<JS::Value> @constructor_class@::call()
  3955. {
  3956. return vm().throw_completion<JS::TypeError>(JS::ErrorType::ConstructorWithoutNew, "@namespaced_name@");
  3957. }
  3958. )~~~");
  3959. generate_constructors(generator, interface);
  3960. generator.append(R"~~~(
  3961. void @constructor_class@::initialize(JS::Realm& realm)
  3962. {
  3963. auto& vm = this->vm();
  3964. [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
  3965. Base::initialize(realm);
  3966. )~~~");
  3967. if (interface.prototype_base_class != "ObjectPrototype") {
  3968. generator.append(R"~~~(
  3969. set_prototype(&ensure_web_constructor<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
  3970. )~~~");
  3971. }
  3972. generator.append(R"~~~(
  3973. define_direct_property(vm.names.prototype, &ensure_web_prototype<@prototype_class@>(realm, "@namespaced_name@"_fly_string), 0);
  3974. define_direct_property(vm.names.length, JS::Value(@constructor.length@), JS::Attribute::Configurable);
  3975. )~~~");
  3976. for (auto& constant : interface.constants) {
  3977. auto constant_generator = generator.fork();
  3978. constant_generator.set("constant.name", constant.name);
  3979. generate_wrap_statement(constant_generator, constant.value, constant.type, interface, ByteString::formatted("auto constant_{}_value =", constant.name));
  3980. constant_generator.append(R"~~~(
  3981. define_direct_property("@constant.name@", constant_@constant.name@_value, JS::Attribute::Enumerable);
  3982. )~~~");
  3983. }
  3984. for (auto& attribute : interface.static_attributes) {
  3985. auto attribute_generator = generator.fork();
  3986. attribute_generator.set("attribute.name", attribute.name);
  3987. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  3988. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  3989. if (!attribute.readonly)
  3990. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  3991. else
  3992. attribute_generator.set("attribute.setter_callback", "nullptr");
  3993. attribute_generator.append(R"~~~(
  3994. define_native_accessor(realm, "@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
  3995. )~~~");
  3996. }
  3997. define_the_operations(generator, interface.static_overload_sets);
  3998. generator.append(R"~~~(
  3999. }
  4000. )~~~");
  4001. // Implementation: Static Attributes
  4002. for (auto& attribute : interface.static_attributes) {
  4003. auto attribute_generator = generator.fork();
  4004. attribute_generator.set("attribute.name", attribute.name);
  4005. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  4006. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  4007. if (attribute.extended_attributes.contains("ImplementedAs")) {
  4008. auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value();
  4009. attribute_generator.set("attribute.cpp_name", implemented_as);
  4010. } else {
  4011. attribute_generator.set("attribute.cpp_name", attribute.name.to_snakecase());
  4012. }
  4013. attribute_generator.append(R"~~~(
  4014. JS_DEFINE_NATIVE_FUNCTION(@constructor_class@::@attribute.getter_callback@)
  4015. {
  4016. WebIDL::log_trace(vm, "@constructor_class@::@attribute.getter_callback@");
  4017. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::@attribute.cpp_name@(vm); }));
  4018. )~~~");
  4019. generate_return_statement(generator, *attribute.type, interface);
  4020. attribute_generator.append(R"~~~(
  4021. }
  4022. )~~~");
  4023. // FIXME: Add support for static attribute setters.
  4024. }
  4025. // Implementation: Static Functions
  4026. for (auto& function : interface.static_functions) {
  4027. if (function.extended_attributes.contains("FIXME"))
  4028. continue;
  4029. generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface);
  4030. }
  4031. for (auto const& overload_set : interface.static_overload_sets) {
  4032. if (overload_set.value.size() == 1)
  4033. continue;
  4034. generate_overload_arbiter(generator, overload_set, interface, interface.constructor_class, IsConstructor::No);
  4035. }
  4036. generator.append(R"~~~(
  4037. } // namespace Web::Bindings
  4038. )~~~");
  4039. }
  4040. void generate_prototype_header(IDL::Interface const& interface, StringBuilder& builder)
  4041. {
  4042. SourceGenerator generator { builder };
  4043. generator.set("prototype_class", interface.prototype_class);
  4044. generator.append(R"~~~(
  4045. #pragma once
  4046. #include <LibJS/Runtime/Object.h>
  4047. namespace Web::Bindings {
  4048. class @prototype_class@ : public JS::Object {
  4049. JS_OBJECT(@prototype_class@, JS::Object);
  4050. GC_DECLARE_ALLOCATOR(@prototype_class@);
  4051. public:
  4052. explicit @prototype_class@(JS::Realm&);
  4053. virtual void initialize(JS::Realm&) override;
  4054. virtual ~@prototype_class@() override;
  4055. private:
  4056. )~~~");
  4057. // Generate an empty prototype object for global interfaces.
  4058. auto is_global_interface = interface.extended_attributes.contains("Global");
  4059. if (is_global_interface) {
  4060. generator.append(R"~~~(
  4061. };
  4062. )~~~");
  4063. if (interface.supports_named_properties()) {
  4064. generate_named_properties_object_declarations(interface, builder);
  4065. }
  4066. } else {
  4067. generate_prototype_or_global_mixin_declarations(interface, builder);
  4068. }
  4069. generator.append(R"~~~(
  4070. } // namespace Web::Bindings
  4071. )~~~");
  4072. }
  4073. void generate_prototype_implementation(IDL::Interface const& interface, StringBuilder& builder)
  4074. {
  4075. SourceGenerator generator { builder };
  4076. generator.set("parent_name", interface.parent_name);
  4077. generator.set("prototype_class", interface.prototype_class);
  4078. generator.set("prototype_base_class", interface.prototype_base_class);
  4079. generator.append(R"~~~(
  4080. #include <AK/Function.h>
  4081. #include <LibIDL/Types.h>
  4082. #include <LibJS/Runtime/Array.h>
  4083. #include <LibJS/Runtime/ArrayBuffer.h>
  4084. #include <LibJS/Runtime/DataView.h>
  4085. #include <LibJS/Runtime/Error.h>
  4086. #include <LibJS/Runtime/FunctionObject.h>
  4087. #include <LibJS/Runtime/GlobalObject.h>
  4088. #include <LibJS/Runtime/Iterator.h>
  4089. #include <LibJS/Runtime/PromiseConstructor.h>
  4090. #include <LibJS/Runtime/TypedArray.h>
  4091. #include <LibJS/Runtime/Value.h>
  4092. #include <LibJS/Runtime/ValueInlines.h>
  4093. #include <LibURL/Origin.h>
  4094. #include <LibWeb/Bindings/@prototype_class@.h>
  4095. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  4096. #include <LibWeb/Bindings/Intrinsics.h>
  4097. #include <LibWeb/DOM/Element.h>
  4098. #include <LibWeb/DOM/Event.h>
  4099. #include <LibWeb/DOM/IDLEventListener.h>
  4100. #include <LibWeb/DOM/NodeFilter.h>
  4101. #include <LibWeb/DOM/Range.h>
  4102. #include <LibWeb/HTML/Numbers.h>
  4103. #include <LibWeb/HTML/Scripting/Environments.h>
  4104. #include <LibWeb/HTML/Window.h>
  4105. #include <LibWeb/HTML/WindowProxy.h>
  4106. #include <LibWeb/Infra/Strings.h>
  4107. #include <LibWeb/WebIDL/AbstractOperations.h>
  4108. #include <LibWeb/WebIDL/Buffers.h>
  4109. #include <LibWeb/WebIDL/OverloadResolution.h>
  4110. #include <LibWeb/WebIDL/Promise.h>
  4111. #include <LibWeb/WebIDL/Tracing.h>
  4112. #include <LibWeb/WebIDL/Types.h>
  4113. #if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)
  4114. # include <LibWeb/Bindings/@prototype_base_class@.h>
  4115. #endif
  4116. )~~~");
  4117. bool has_ce_reactions = false;
  4118. for (auto const& function : interface.functions) {
  4119. if (function.extended_attributes.contains("FIXME"))
  4120. continue;
  4121. if (function.extended_attributes.contains("CEReactions")) {
  4122. has_ce_reactions = true;
  4123. break;
  4124. }
  4125. }
  4126. if (!has_ce_reactions) {
  4127. for (auto const& attribute : interface.attributes) {
  4128. if (attribute.extended_attributes.contains("CEReactions")) {
  4129. has_ce_reactions = true;
  4130. break;
  4131. }
  4132. }
  4133. }
  4134. if (!has_ce_reactions && interface.indexed_property_setter.has_value() && interface.indexed_property_setter->extended_attributes.contains("CEReactions"))
  4135. has_ce_reactions = true;
  4136. if (!has_ce_reactions && interface.named_property_setter.has_value() && interface.named_property_setter->extended_attributes.contains("CEReactions"))
  4137. has_ce_reactions = true;
  4138. if (!has_ce_reactions && interface.named_property_deleter.has_value() && interface.named_property_deleter->extended_attributes.contains("CEReactions"))
  4139. has_ce_reactions = true;
  4140. if (has_ce_reactions) {
  4141. generator.append(R"~~~(
  4142. #include <LibWeb/Bindings/MainThreadVM.h>
  4143. )~~~");
  4144. }
  4145. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  4146. generate_using_namespace_definitions(generator);
  4147. generator.append(R"~~~(
  4148. namespace Web::Bindings {
  4149. GC_DEFINE_ALLOCATOR(@prototype_class@);
  4150. @prototype_class@::@prototype_class@([[maybe_unused]] JS::Realm& realm))~~~");
  4151. if (interface.name == "DOMException") {
  4152. // https://webidl.spec.whatwg.org/#es-DOMException-specialness
  4153. // Object.getPrototypeOf(DOMException.prototype) === Error.prototype
  4154. generator.append(R"~~~(
  4155. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().error_prototype())
  4156. )~~~");
  4157. } else if (!interface.parent_name.is_empty()) {
  4158. generator.append(R"~~~(
  4159. : Object(realm, nullptr)
  4160. )~~~");
  4161. } else {
  4162. generator.append(R"~~~(
  4163. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  4164. )~~~");
  4165. }
  4166. generator.append(R"~~~(
  4167. {
  4168. }
  4169. @prototype_class@::~@prototype_class@()
  4170. {
  4171. }
  4172. )~~~");
  4173. // Generate a mostly empty prototype object for global interfaces.
  4174. auto is_global_interface = interface.extended_attributes.contains("Global");
  4175. if (is_global_interface) {
  4176. generator.append(R"~~~(
  4177. void @prototype_class@::initialize(JS::Realm& realm)
  4178. {
  4179. Base::initialize(realm);
  4180. )~~~");
  4181. if (interface.supports_named_properties()) {
  4182. generator.set("named_properties_class", ByteString::formatted("{}Properties", interface.name));
  4183. generator.set("namespaced_name", interface.namespaced_name);
  4184. generator.append(R"~~~(
  4185. define_direct_property(vm().well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm(), "@namespaced_name@"_string), JS::Attribute::Configurable);
  4186. set_prototype(&ensure_web_prototype<@prototype_class@>(realm, "@named_properties_class@"_fly_string));
  4187. )~~~");
  4188. } else {
  4189. generator.append(R"~~~(
  4190. set_prototype(&ensure_web_prototype<@prototype_base_class@>(realm, "@parent_name@"_fly_string));
  4191. )~~~");
  4192. }
  4193. generator.append(R"~~~(
  4194. }
  4195. )~~~");
  4196. if (interface.supports_named_properties())
  4197. generate_named_properties_object_definitions(interface, builder);
  4198. } else {
  4199. generate_prototype_or_global_mixin_definitions(interface, builder);
  4200. }
  4201. generator.append(R"~~~(
  4202. } // namespace Web::Bindings
  4203. )~~~");
  4204. }
  4205. void generate_iterator_prototype_header(IDL::Interface const& interface, StringBuilder& builder)
  4206. {
  4207. VERIFY(interface.pair_iterator_types.has_value());
  4208. SourceGenerator generator { builder };
  4209. generator.set("prototype_class", ByteString::formatted("{}IteratorPrototype", interface.name));
  4210. generator.append(R"~~~(
  4211. #pragma once
  4212. #include <LibJS/Runtime/Object.h>
  4213. namespace Web::Bindings {
  4214. class @prototype_class@ : public JS::Object {
  4215. JS_OBJECT(@prototype_class@, JS::Object);
  4216. GC_DECLARE_ALLOCATOR(@prototype_class@);
  4217. public:
  4218. explicit @prototype_class@(JS::Realm&);
  4219. virtual void initialize(JS::Realm&) override;
  4220. virtual ~@prototype_class@() override;
  4221. private:
  4222. JS_DECLARE_NATIVE_FUNCTION(next);
  4223. };
  4224. } // namespace Web::Bindings
  4225. )~~~");
  4226. }
  4227. void generate_iterator_prototype_implementation(IDL::Interface const& interface, StringBuilder& builder)
  4228. {
  4229. VERIFY(interface.pair_iterator_types.has_value());
  4230. SourceGenerator generator { builder };
  4231. generator.set("name", ByteString::formatted("{}Iterator", interface.name));
  4232. generator.set("parent_name", interface.parent_name);
  4233. generator.set("prototype_class", ByteString::formatted("{}IteratorPrototype", interface.name));
  4234. generator.set("prototype_base_class", interface.prototype_base_class);
  4235. generator.set("fully_qualified_name", ByteString::formatted("{}Iterator", interface.fully_qualified_name));
  4236. generator.set("possible_include_path", ByteString::formatted("{}Iterator", interface.name.replace("::"sv, "/"sv, ReplaceMode::All)));
  4237. generator.append(R"~~~(
  4238. #include <AK/Function.h>
  4239. #include <AK/TypeCasts.h>
  4240. #include <LibJS/Runtime/Array.h>
  4241. #include <LibJS/Runtime/Error.h>
  4242. #include <LibJS/Runtime/FunctionObject.h>
  4243. #include <LibJS/Runtime/GlobalObject.h>
  4244. #include <LibJS/Runtime/TypedArray.h>
  4245. #include <LibWeb/Bindings/@prototype_class@.h>
  4246. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  4247. #include <LibWeb/Bindings/Intrinsics.h>
  4248. #include <LibWeb/WebIDL/Tracing.h>
  4249. )~~~");
  4250. emit_includes_for_all_imports(interface, generator, true);
  4251. generate_using_namespace_definitions(generator);
  4252. generator.append(R"~~~(
  4253. namespace Web::Bindings {
  4254. GC_DEFINE_ALLOCATOR(@prototype_class@);
  4255. @prototype_class@::@prototype_class@(JS::Realm& realm)
  4256. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().iterator_prototype())
  4257. {
  4258. }
  4259. @prototype_class@::~@prototype_class@()
  4260. {
  4261. }
  4262. void @prototype_class@::initialize(JS::Realm& realm)
  4263. {
  4264. auto& vm = this->vm();
  4265. Base::initialize(realm);
  4266. define_native_function(realm, vm.names.next, next, 0, JS::Attribute::Writable | JS::Attribute::Enumerable | JS::Attribute::Configurable);
  4267. define_direct_property(vm.well_known_symbol_to_string_tag(), JS::PrimitiveString::create(vm, "Iterator"_string), JS::Attribute::Configurable);
  4268. }
  4269. static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
  4270. {
  4271. auto this_object = TRY(vm.this_value().to_object(vm));
  4272. if (!is<@fully_qualified_name@>(*this_object))
  4273. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@name@");
  4274. return static_cast<@fully_qualified_name@*>(this_object.ptr());
  4275. }
  4276. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::next)
  4277. {
  4278. WebIDL::log_trace(vm, "@prototype_class@::next");
  4279. auto* impl = TRY(impl_from(vm));
  4280. return TRY(throw_dom_exception_if_needed(vm, [&] { return impl->next(); }));
  4281. }
  4282. } // namespace Web::Bindings
  4283. )~~~");
  4284. }
  4285. void generate_global_mixin_header(IDL::Interface const& interface, StringBuilder& builder)
  4286. {
  4287. SourceGenerator generator { builder };
  4288. generator.set("class_name", interface.global_mixin_class);
  4289. generator.append(R"~~~(
  4290. #pragma once
  4291. #include <LibJS/Runtime/Object.h>
  4292. namespace Web::Bindings {
  4293. class @class_name@ {
  4294. public:
  4295. void initialize(JS::Realm&, JS::Object&);
  4296. @class_name@();
  4297. virtual ~@class_name@();
  4298. private:
  4299. )~~~");
  4300. generate_prototype_or_global_mixin_declarations(interface, builder);
  4301. generator.append(R"~~~(
  4302. } // namespace Web::Bindings
  4303. )~~~");
  4304. }
  4305. void generate_global_mixin_implementation(IDL::Interface const& interface, StringBuilder& builder)
  4306. {
  4307. SourceGenerator generator { builder };
  4308. generator.set("class_name", interface.global_mixin_class);
  4309. generator.set("prototype_name", interface.prototype_class);
  4310. generator.append(R"~~~(
  4311. #include <AK/Function.h>
  4312. #include <LibIDL/Types.h>
  4313. #include <LibJS/Runtime/Array.h>
  4314. #include <LibJS/Runtime/DataView.h>
  4315. #include <LibJS/Runtime/Error.h>
  4316. #include <LibJS/Runtime/FunctionObject.h>
  4317. #include <LibJS/Runtime/GlobalObject.h>
  4318. #include <LibJS/Runtime/Iterator.h>
  4319. #include <LibJS/Runtime/TypedArray.h>
  4320. #include <LibJS/Runtime/Value.h>
  4321. #include <LibJS/Runtime/ValueInlines.h>
  4322. #include <LibURL/Origin.h>
  4323. #include <LibWeb/Bindings/@class_name@.h>
  4324. #include <LibWeb/Bindings/@prototype_name@.h>
  4325. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  4326. #include <LibWeb/Bindings/Intrinsics.h>
  4327. #include <LibWeb/DOM/Element.h>
  4328. #include <LibWeb/DOM/Event.h>
  4329. #include <LibWeb/DOM/IDLEventListener.h>
  4330. #include <LibWeb/DOM/NodeFilter.h>
  4331. #include <LibWeb/DOM/Range.h>
  4332. #include <LibWeb/HTML/Scripting/Environments.h>
  4333. #include <LibWeb/HTML/Window.h>
  4334. #include <LibWeb/HTML/WindowProxy.h>
  4335. #include <LibWeb/WebIDL/AbstractOperations.h>
  4336. #include <LibWeb/WebIDL/OverloadResolution.h>
  4337. #include <LibWeb/WebIDL/Tracing.h>
  4338. #include <LibWeb/WebIDL/Types.h>
  4339. )~~~");
  4340. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  4341. generate_using_namespace_definitions(generator);
  4342. generator.append(R"~~~(
  4343. namespace Web::Bindings {
  4344. @class_name@::@class_name@() = default;
  4345. @class_name@::~@class_name@() = default;
  4346. )~~~");
  4347. generate_prototype_or_global_mixin_definitions(interface, builder);
  4348. generator.append(R"~~~(
  4349. } // namespace Web::Bindings
  4350. )~~~");
  4351. }
  4352. }