IDLGenerators.cpp 112 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845
  1. /*
  2. * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  5. * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include "IDLTypes.h"
  10. #include <AK/LexicalPath.h>
  11. #include <AK/Queue.h>
  12. #include <AK/QuickSort.h>
  13. Vector<StringView> s_header_search_paths;
  14. namespace IDL {
  15. static bool is_wrappable_type(Type const& type)
  16. {
  17. if (type.name == "EventTarget")
  18. return true;
  19. if (type.name == "Node")
  20. return true;
  21. if (type.name == "Document")
  22. return true;
  23. if (type.name == "Text")
  24. return true;
  25. if (type.name == "DocumentType")
  26. return true;
  27. if (type.name.ends_with("Element"sv))
  28. return true;
  29. if (type.name.ends_with("Event"sv))
  30. return true;
  31. if (type.name == "ImageData")
  32. return true;
  33. if (type.name == "Window")
  34. return true;
  35. if (type.name == "Range")
  36. return true;
  37. if (type.name == "Selection")
  38. return true;
  39. if (type.name == "Attribute")
  40. return true;
  41. if (type.name == "NamedNodeMap")
  42. return true;
  43. if (type.name == "TextMetrics")
  44. return true;
  45. if (type.name == "AbortSignal")
  46. return true;
  47. if (type.name == "CanvasRenderingContext2D")
  48. return true;
  49. if (type.name == "WebGLRenderingContext")
  50. return true;
  51. if (type.name == "URLSearchParams")
  52. return true;
  53. if (type.name == "Blob")
  54. return true;
  55. if (type.name == "Path2D")
  56. return true;
  57. return false;
  58. }
  59. static StringView sequence_storage_type_to_cpp_storage_type_name(SequenceStorageType sequence_storage_type)
  60. {
  61. switch (sequence_storage_type) {
  62. case SequenceStorageType::Vector:
  63. return "Vector"sv;
  64. case SequenceStorageType::MarkedVector:
  65. return "JS::MarkedVector"sv;
  66. default:
  67. VERIFY_NOT_REACHED();
  68. }
  69. }
  70. static bool impl_is_wrapper(Type const& type)
  71. {
  72. if (type.name == "StyleSheet"sv)
  73. return true;
  74. if (type.name == "CSSStyleSheet"sv)
  75. return true;
  76. if (type.name == "StyleSheetList"sv)
  77. return true;
  78. if (type.name == "CSSRuleList"sv)
  79. return true;
  80. if (type.name == "CSSRule"sv)
  81. return true;
  82. if (type.name == "CSSStyleRule"sv)
  83. return true;
  84. if (type.name == "CSSFontFaceRule"sv)
  85. return true;
  86. if (type.name == "CSSConditionRule"sv)
  87. return true;
  88. if (type.name == "CSSGroupingRule"sv)
  89. return true;
  90. if (type.name == "CSSMediaRule"sv)
  91. return true;
  92. if (type.name == "CSSImportRule"sv)
  93. return true;
  94. if (type.name == "EventTarget"sv)
  95. return true;
  96. if (type.name == "Node"sv)
  97. return true;
  98. if (type.name == "ShadowRoot"sv)
  99. return true;
  100. if (type.name == "DocumentTemporary"sv)
  101. return true;
  102. if (type.name == "Text"sv)
  103. return true;
  104. if (type.name == "Document"sv)
  105. return true;
  106. if (type.name == "DocumentType"sv)
  107. return true;
  108. if (type.name.ends_with("Element"sv))
  109. return true;
  110. if (type.name == "XMLHttpRequest"sv)
  111. return true;
  112. if (type.name == "XMLHttpRequestEventTarget"sv)
  113. return true;
  114. if (type.name == "AbortSignal"sv)
  115. return true;
  116. if (type.name == "WebSocket"sv)
  117. return true;
  118. if (type.name == "Worker"sv)
  119. return true;
  120. if (type.name == "NodeIterator"sv)
  121. return true;
  122. if (type.name == "TreeWalker"sv)
  123. return true;
  124. if (type.name == "MediaQueryList"sv)
  125. return true;
  126. if (type.name == "MessagePort"sv)
  127. return true;
  128. if (type.name == "NodeFilter"sv)
  129. return true;
  130. if (type.name == "DOMTokenList"sv)
  131. return true;
  132. if (type.name == "DOMStringMap"sv)
  133. return true;
  134. if (type.name == "MutationRecord"sv)
  135. return true;
  136. if (type.name == "CanvasRenderingContext2D"sv)
  137. return true;
  138. if (type.name == "WebGLRenderingContext"sv)
  139. return true;
  140. if (type.name == "Path2D"sv)
  141. return true;
  142. if (type.name == "Storage"sv)
  143. return true;
  144. if (type.name == "File"sv)
  145. return true;
  146. if (type.name == "Blob"sv)
  147. return true;
  148. if (type.name == "URL"sv)
  149. return true;
  150. if (type.name == "URLSearchParams"sv)
  151. return true;
  152. if (type.name == "DOMException"sv)
  153. return true;
  154. return false;
  155. }
  156. CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface)
  157. {
  158. if (is_wrappable_type(type)) {
  159. if (impl_is_wrapper(type)) {
  160. return { .name = String::formatted("JS::Handle<{}>", type.name), .sequence_storage_type = SequenceStorageType::MarkedVector };
  161. }
  162. if (type.nullable)
  163. return { .name = String::formatted("RefPtr<{}>", type.name), .sequence_storage_type = SequenceStorageType::Vector };
  164. return { .name = String::formatted("NonnullRefPtr<{}>", type.name), .sequence_storage_type = SequenceStorageType::Vector };
  165. }
  166. if (type.is_string())
  167. return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector };
  168. if (type.name == "double" && !type.nullable)
  169. return { .name = "double", .sequence_storage_type = SequenceStorageType::Vector };
  170. if (type.name == "float" && !type.nullable)
  171. return { .name = "float", .sequence_storage_type = SequenceStorageType::Vector };
  172. if (type.name == "boolean" && !type.nullable)
  173. return { .name = "bool", .sequence_storage_type = SequenceStorageType::Vector };
  174. if (type.name == "unsigned long" && !type.nullable)
  175. return { .name = "u32", .sequence_storage_type = SequenceStorageType::Vector };
  176. if (type.name == "unsigned short" && !type.nullable)
  177. return { .name = "u16", .sequence_storage_type = SequenceStorageType::Vector };
  178. if (type.name == "long long" && !type.nullable)
  179. return { .name = "i64", .sequence_storage_type = SequenceStorageType::Vector };
  180. if (type.name == "unsigned long long" && !type.nullable)
  181. return { .name = "u64", .sequence_storage_type = SequenceStorageType::Vector };
  182. if (type.name == "long" && !type.nullable)
  183. return { .name = "i32", .sequence_storage_type = SequenceStorageType::Vector };
  184. if (type.name == "any")
  185. return { .name = "JS::Value", .sequence_storage_type = SequenceStorageType::MarkedVector };
  186. if (type.name == "BufferSource")
  187. return { .name = "JS::Handle<JS::Object>", .sequence_storage_type = SequenceStorageType::MarkedVector };
  188. if (type.name == "sequence") {
  189. auto& parameterized_type = verify_cast<ParameterizedType>(type);
  190. auto& sequence_type = parameterized_type.parameters.first();
  191. auto sequence_cpp_type = idl_type_name_to_cpp_type(sequence_type, interface);
  192. auto storage_type_name = sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type);
  193. if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::MarkedVector)
  194. return { .name = storage_type_name, .sequence_storage_type = SequenceStorageType::Vector };
  195. return { .name = String::formatted("{}<{}>", storage_type_name, sequence_cpp_type.name), .sequence_storage_type = SequenceStorageType::Vector };
  196. }
  197. if (type.name == "record") {
  198. auto& parameterized_type = verify_cast<ParameterizedType>(type);
  199. auto& record_key_type = parameterized_type.parameters[0];
  200. auto& record_value_type = parameterized_type.parameters[1];
  201. auto record_key_cpp_type = idl_type_name_to_cpp_type(record_key_type, interface);
  202. auto record_value_cpp_type = idl_type_name_to_cpp_type(record_value_type, interface);
  203. return { .name = String::formatted("OrderedHashMap<{}, {}>", record_key_cpp_type.name, record_value_cpp_type.name), .sequence_storage_type = SequenceStorageType::Vector };
  204. }
  205. if (is<UnionType>(type)) {
  206. auto& union_type = verify_cast<UnionType>(type);
  207. return { .name = union_type.to_variant(interface), .sequence_storage_type = SequenceStorageType::Vector };
  208. }
  209. if (!type.nullable) {
  210. for (auto& dictionary : interface.dictionaries) {
  211. if (type.name == dictionary.key)
  212. return { .name = type.name, .sequence_storage_type = SequenceStorageType::Vector };
  213. }
  214. }
  215. dbgln("Unimplemented type for idl_type_name_to_cpp_type: {}{}", type.name, type.nullable ? "?" : "");
  216. TODO();
  217. }
  218. static String make_input_acceptable_cpp(String const& input)
  219. {
  220. if (input.is_one_of("class", "template", "for", "default", "char", "namespace", "delete")) {
  221. StringBuilder builder;
  222. builder.append(input);
  223. builder.append('_');
  224. return builder.to_string();
  225. }
  226. return input.replace("-"sv, "_"sv, ReplaceMode::All);
  227. }
  228. static void generate_include_for_wrapper(auto& generator, auto& wrapper_name)
  229. {
  230. auto wrapper_generator = generator.fork();
  231. wrapper_generator.set("wrapper_class", wrapper_name);
  232. // FIXME: These may or may not exist, because REASONS.
  233. wrapper_generator.append(R"~~~(
  234. #if __has_include(<LibWeb/Bindings/@wrapper_class@.h>)
  235. # include <LibWeb/Bindings/@wrapper_class@.h>
  236. #endif
  237. #if __has_include(<LibWeb/Bindings/@wrapper_class@Factory.h>)
  238. # include <LibWeb/Bindings/@wrapper_class@Factory.h>
  239. #endif
  240. )~~~");
  241. }
  242. static void generate_include_for_iterator(auto& generator, auto& iterator_path, auto& iterator_name)
  243. {
  244. auto iterator_generator = generator.fork();
  245. iterator_generator.set("iterator_class.path", iterator_path);
  246. iterator_generator.set("iterator_class.name", iterator_name);
  247. // FIXME: These may or may not exist, because REASONS.
  248. iterator_generator.append(R"~~~(
  249. //#if __has_include(<LibWeb/@iterator_class.path@.h>)
  250. # include <LibWeb/@iterator_class.path@.h>
  251. //#endif
  252. #if __has_include(<LibWeb/@iterator_class.path@Factory.h>)
  253. # include <LibWeb/@iterator_class.path@Factory.h>
  254. #endif
  255. #if __has_include(<LibWeb/Bindings/@iterator_class.name@Wrapper.h>)
  256. # include <LibWeb/Bindings/@iterator_class.name@Wrapper.h>
  257. #endif
  258. #if __has_include(<LibWeb/Bindings/@iterator_class.name@WrapperFactory.h>)
  259. # include <LibWeb/Bindings/@iterator_class.name@WrapperFactory.h>
  260. #endif
  261. )~~~");
  262. }
  263. static void generate_include_for(auto& generator, auto& path)
  264. {
  265. auto forked_generator = generator.fork();
  266. auto path_string = path;
  267. for (auto& search_path : s_header_search_paths) {
  268. if (!path.starts_with(search_path))
  269. continue;
  270. auto relative_path = LexicalPath::relative_path(path, search_path);
  271. if (relative_path.length() < path_string.length())
  272. path_string = relative_path;
  273. }
  274. LexicalPath include_path { path_string };
  275. forked_generator.set("include.path", String::formatted("{}/{}.h", include_path.dirname(), include_path.title()));
  276. forked_generator.append(R"~~~(
  277. #include <@include.path@>
  278. )~~~");
  279. }
  280. static void emit_includes_for_all_imports(auto& interface, auto& generator, bool is_iterator = false)
  281. {
  282. Queue<RemoveCVReference<decltype(interface)> const*> interfaces;
  283. HashTable<String> paths_imported;
  284. interfaces.enqueue(&interface);
  285. while (!interfaces.is_empty()) {
  286. auto interface = interfaces.dequeue();
  287. if (paths_imported.contains(interface->module_own_path))
  288. continue;
  289. paths_imported.set(interface->module_own_path);
  290. for (auto& imported_interface : interface->imported_modules) {
  291. if (!paths_imported.contains(imported_interface.module_own_path))
  292. interfaces.enqueue(&imported_interface);
  293. }
  294. if (!interface->will_generate_code())
  295. continue;
  296. generate_include_for(generator, interface->module_own_path);
  297. if (is_iterator) {
  298. auto iterator_name = String::formatted("{}Iterator", interface->name);
  299. auto iterator_path = String::formatted("{}Iterator", interface->fully_qualified_name.replace("::"sv, "/"sv, ReplaceMode::All));
  300. generate_include_for_iterator(generator, iterator_path, iterator_name);
  301. }
  302. if (interface->wrapper_class != "Wrapper")
  303. generate_include_for_wrapper(generator, interface->wrapper_class);
  304. }
  305. }
  306. template<typename ParameterType>
  307. static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter, String const& js_name, String const& js_suffix, String const& cpp_name, IDL::Interface const& interface, bool legacy_null_to_empty_string = false, bool optional = false, Optional<String> optional_default_value = {}, bool variadic = false, size_t recursion_depth = 0)
  308. {
  309. auto scoped_generator = generator.fork();
  310. auto acceptable_cpp_name = make_input_acceptable_cpp(cpp_name);
  311. scoped_generator.set("cpp_name", acceptable_cpp_name);
  312. scoped_generator.set("js_name", js_name);
  313. scoped_generator.set("js_suffix", js_suffix);
  314. scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false");
  315. scoped_generator.set("parameter.type.name", parameter.type->name);
  316. if (parameter.type->name == "Window")
  317. scoped_generator.set("wrapper_name", "HTML::Window");
  318. else {
  319. scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type->name));
  320. }
  321. if (optional_default_value.has_value())
  322. scoped_generator.set("parameter.optional_default_value", *optional_default_value);
  323. // FIXME: Add support for optional, variadic, nullable and default values to all types
  324. if (parameter.type->is_string()) {
  325. if (variadic) {
  326. scoped_generator.append(R"~~~(
  327. Vector<String> @cpp_name@;
  328. @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
  329. for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
  330. auto to_string_result = TRY(vm.argument(i).to_string(vm));
  331. @cpp_name@.append(move(to_string_result));
  332. }
  333. )~~~");
  334. } else if (!optional) {
  335. if (!parameter.type->nullable) {
  336. scoped_generator.append(R"~~~(
  337. String @cpp_name@;
  338. if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) {
  339. @cpp_name@ = String::empty();
  340. } else {
  341. @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm));
  342. }
  343. )~~~");
  344. } else {
  345. scoped_generator.append(R"~~~(
  346. String @cpp_name@;
  347. if (!@js_name@@js_suffix@.is_nullish())
  348. @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm));
  349. )~~~");
  350. }
  351. } else {
  352. scoped_generator.append(R"~~~(
  353. String @cpp_name@;
  354. if (!@js_name@@js_suffix@.is_undefined()) {
  355. if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@)
  356. @cpp_name@ = String::empty();
  357. else
  358. @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm));
  359. })~~~");
  360. if (optional_default_value.has_value() && (!parameter.type->nullable || optional_default_value.value() != "null")) {
  361. scoped_generator.append(R"~~~( else {
  362. @cpp_name@ = @parameter.optional_default_value@;
  363. }
  364. )~~~");
  365. } else {
  366. scoped_generator.append(R"~~~(
  367. )~~~");
  368. }
  369. }
  370. } else if (parameter.type->name.is_one_of("EventListener", "NodeFilter")) {
  371. // FIXME: Replace this with support for callback interfaces. https://heycam.github.io/webidl/#idl-callback-interface
  372. if (parameter.type->name == "EventListener")
  373. scoped_generator.set("cpp_type", "IDLEventListener");
  374. else
  375. scoped_generator.set("cpp_type", parameter.type->name);
  376. if (parameter.type->nullable) {
  377. scoped_generator.append(R"~~~(
  378. @cpp_type@* @cpp_name@ = nullptr;
  379. if (!@js_name@@js_suffix@.is_nullish()) {
  380. if (!@js_name@@js_suffix@.is_object())
  381. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  382. auto* callback_type = vm.heap().allocate_without_realm<CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_settings_object());
  383. @cpp_name@ = @cpp_type@::create(realm, *callback_type).ptr();
  384. }
  385. )~~~");
  386. } else {
  387. scoped_generator.append(R"~~~(
  388. if (!@js_name@@js_suffix@.is_object())
  389. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  390. auto* callback_type = vm.heap().allocate_without_realm<CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_settings_object());
  391. auto @cpp_name@ = adopt_ref(*new @cpp_type@(move(callback_type)));
  392. )~~~");
  393. }
  394. } else if (IDL::is_wrappable_type(*parameter.type)) {
  395. if (!parameter.type->nullable) {
  396. if (!optional) {
  397. scoped_generator.append(R"~~~(
  398. if (!@js_name@@js_suffix@.is_object() || !is<@wrapper_name@>(@js_name@@js_suffix@.as_object()))
  399. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  400. auto& @cpp_name@ = static_cast<@wrapper_name@&>(@js_name@@js_suffix@.as_object()).impl();
  401. )~~~");
  402. } else {
  403. scoped_generator.append(R"~~~(
  404. Optional<JS::NonnullGCPtr<@parameter.type.name@>> @cpp_name@;
  405. if (!@js_name@@js_suffix@.is_undefined()) {
  406. if (!@js_name@@js_suffix@.is_object() || !is<@wrapper_name@>(@js_name@@js_suffix@.as_object()))
  407. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  408. @cpp_name@ = static_cast<@wrapper_name@&>(@js_name@@js_suffix@.as_object()).impl();
  409. }
  410. )~~~");
  411. }
  412. } else {
  413. scoped_generator.append(R"~~~(
  414. @parameter.type.name@* @cpp_name@ = nullptr;
  415. if (!@js_name@@js_suffix@.is_nullish()) {
  416. if (!@js_name@@js_suffix@.is_object() || !is<@wrapper_name@>(@js_name@@js_suffix@.as_object()))
  417. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  418. @cpp_name@ = &static_cast<@wrapper_name@&>(@js_name@@js_suffix@.as_object()).impl();
  419. }
  420. )~~~");
  421. }
  422. } else if (parameter.type->name == "double" || parameter.type->name == "float") {
  423. if (!optional) {
  424. scoped_generator.append(R"~~~(
  425. @parameter.type.name@ @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
  426. )~~~");
  427. } else {
  428. if (optional_default_value.has_value()) {
  429. scoped_generator.append(R"~~~(
  430. @parameter.type.name@ @cpp_name@;
  431. )~~~");
  432. } else {
  433. scoped_generator.append(R"~~~(
  434. Optional<@parameter.type.name@> @cpp_name@;
  435. )~~~");
  436. }
  437. scoped_generator.append(R"~~~(
  438. if (!@js_name@@js_suffix@.is_undefined())
  439. @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm));
  440. )~~~");
  441. if (optional_default_value.has_value()) {
  442. scoped_generator.append(R"~~~(
  443. else
  444. @cpp_name@ = @parameter.optional_default_value@;
  445. )~~~");
  446. } else {
  447. scoped_generator.append(R"~~~(
  448. )~~~");
  449. }
  450. }
  451. } else if (parameter.type->name == "boolean") {
  452. if (!optional || optional_default_value.has_value()) {
  453. scoped_generator.append(R"~~~(
  454. bool @cpp_name@;
  455. )~~~");
  456. } else {
  457. scoped_generator.append(R"~~~(
  458. Optional<bool> @cpp_name@;
  459. )~~~");
  460. }
  461. if (optional) {
  462. scoped_generator.append(R"~~~(
  463. if (!@js_name@@js_suffix@.is_undefined())
  464. )~~~");
  465. }
  466. scoped_generator.append(R"~~~(
  467. @cpp_name@ = @js_name@@js_suffix@.to_boolean();
  468. )~~~");
  469. if (optional_default_value.has_value()) {
  470. scoped_generator.append(R"~~~(
  471. else
  472. @cpp_name@ = @parameter.optional_default_value@;
  473. )~~~");
  474. }
  475. } else if (parameter.type->name == "unsigned long") {
  476. if (!optional || optional_default_value.has_value()) {
  477. scoped_generator.append(R"~~~(
  478. u32 @cpp_name@;
  479. )~~~");
  480. } else {
  481. scoped_generator.append(R"~~~(
  482. Optional<u32> @cpp_name@;
  483. )~~~");
  484. }
  485. if (optional) {
  486. scoped_generator.append(R"~~~(
  487. if (!@js_name@@js_suffix@.is_undefined())
  488. )~~~");
  489. }
  490. scoped_generator.append(R"~~~(
  491. @cpp_name@ = TRY(@js_name@@js_suffix@.to_u32(vm));
  492. )~~~");
  493. if (optional_default_value.has_value()) {
  494. scoped_generator.append(R"~~~(
  495. else
  496. @cpp_name@ = @parameter.optional_default_value@UL;
  497. )~~~");
  498. }
  499. } else if (parameter.type->name == "unsigned short") {
  500. if (!optional || optional_default_value.has_value()) {
  501. scoped_generator.append(R"~~~(
  502. u16 @cpp_name@;
  503. )~~~");
  504. } else {
  505. scoped_generator.append(R"~~~(
  506. Optional<u16> @cpp_name@;
  507. )~~~");
  508. }
  509. if (optional) {
  510. scoped_generator.append(R"~~~(
  511. if (!@js_name@@js_suffix@.is_undefined())
  512. )~~~");
  513. }
  514. scoped_generator.append(R"~~~(
  515. @cpp_name@ = TRY(@js_name@@js_suffix@.to_u16(vm));
  516. )~~~");
  517. if (optional_default_value.has_value()) {
  518. scoped_generator.append(R"~~~(
  519. else
  520. @cpp_name@ = @parameter.optional_default_value@;
  521. )~~~");
  522. }
  523. } else if (parameter.type->name == "long") {
  524. if (!optional || optional_default_value.has_value()) {
  525. scoped_generator.append(R"~~~(
  526. i32 @cpp_name@;
  527. )~~~");
  528. } else {
  529. scoped_generator.append(R"~~~(
  530. Optional<i32> @cpp_name@;
  531. )~~~");
  532. }
  533. if (optional) {
  534. scoped_generator.append(R"~~~(
  535. if (!@js_name@@js_suffix@.is_undefined())
  536. )~~~");
  537. }
  538. scoped_generator.append(R"~~~(
  539. @cpp_name@ = TRY(@js_name@@js_suffix@.to_i32(vm));
  540. )~~~");
  541. if (optional_default_value.has_value()) {
  542. scoped_generator.append(R"~~~(
  543. else
  544. @cpp_name@ = @parameter.optional_default_value@L;
  545. )~~~");
  546. }
  547. } else if (parameter.type->name == "long long") {
  548. if (!optional || optional_default_value.has_value()) {
  549. scoped_generator.append(R"~~~(
  550. i64 @cpp_name@;
  551. )~~~");
  552. } else {
  553. scoped_generator.append(R"~~~(
  554. Optional<i64> @cpp_name@;
  555. )~~~");
  556. }
  557. if (optional) {
  558. scoped_generator.append(R"~~~(
  559. if (!@js_name@@js_suffix@.is_undefined())
  560. )~~~");
  561. }
  562. scoped_generator.append(R"~~~(
  563. @cpp_name@ = TRY(@js_name@@js_suffix@.to_bigint_int64(vm));
  564. )~~~");
  565. if (optional_default_value.has_value()) {
  566. scoped_generator.append(R"~~~(
  567. else
  568. @cpp_name@ = @parameter.optional_default_value@L;
  569. )~~~");
  570. }
  571. } else if (parameter.type->name == "Promise") {
  572. // NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved
  573. // Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say
  574. // anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct.
  575. scoped_generator.append(R"~~~(
  576. if (!@js_name@@js_suffix@.is_object() || !is<JS::Promise>(@js_name@@js_suffix@.as_object())) {
  577. auto* new_promise = JS::Promise::create(realm);
  578. new_promise->fulfill(@js_name@@js_suffix@);
  579. @js_name@@js_suffix@ = new_promise;
  580. }
  581. auto @cpp_name@ = JS::make_handle(&static_cast<JS::Promise&>(@js_name@@js_suffix@.as_object()));
  582. )~~~");
  583. } else if (parameter.type->name == "BufferSource") {
  584. scoped_generator.append(R"~~~(
  585. 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())))
  586. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  587. // TODO: Should we make this a Variant?
  588. auto @cpp_name@ = JS::make_handle(&@js_name@@js_suffix@.as_object());
  589. )~~~");
  590. } else if (parameter.type->name == "any") {
  591. if (!optional) {
  592. scoped_generator.append(R"~~~(
  593. auto @cpp_name@ = @js_name@@js_suffix@;
  594. )~~~");
  595. } else {
  596. scoped_generator.append(R"~~~(
  597. JS::Value @cpp_name@ = JS::js_undefined();
  598. if (!@js_name@@js_suffix@.is_undefined())
  599. @cpp_name@ = @js_name@@js_suffix@;
  600. )~~~");
  601. if (optional_default_value.has_value()) {
  602. if (optional_default_value == "null") {
  603. scoped_generator.append(R"~~~(
  604. else
  605. @cpp_name@ = JS::js_null();
  606. )~~~");
  607. } else if (optional_default_value->to_int().has_value() || optional_default_value->to_uint().has_value()) {
  608. scoped_generator.append(R"~~~(
  609. else
  610. @cpp_name@ = JS::Value(@parameter.optional_default_value@);
  611. )~~~");
  612. } else {
  613. TODO();
  614. }
  615. }
  616. }
  617. } else if (interface.enumerations.contains(parameter.type->name)) {
  618. auto enum_generator = scoped_generator.fork();
  619. auto& enumeration = interface.enumerations.find(parameter.type->name)->value;
  620. StringView enum_member_name;
  621. if (optional_default_value.has_value()) {
  622. VERIFY(optional_default_value->length() >= 2 && (*optional_default_value)[0] == '"' && (*optional_default_value)[optional_default_value->length() - 1] == '"');
  623. enum_member_name = optional_default_value->substring_view(1, optional_default_value->length() - 2);
  624. } else {
  625. enum_member_name = enumeration.first_member;
  626. }
  627. auto default_value_cpp_name = enumeration.translated_cpp_names.get(enum_member_name);
  628. VERIFY(default_value_cpp_name.has_value());
  629. enum_generator.set("enum.default.cpp_value", *default_value_cpp_name);
  630. enum_generator.set("js_name.as_string", String::formatted("{}{}_string", enum_generator.get("js_name"sv), enum_generator.get("js_suffix"sv)));
  631. enum_generator.append(R"~~~(
  632. @parameter.type.name@ @cpp_name@ { @parameter.type.name@::@enum.default.cpp_value@ };
  633. )~~~");
  634. if (optional) {
  635. enum_generator.append(R"~~~(
  636. if (!@js_name@@js_suffix@.is_undefined()) {
  637. )~~~");
  638. }
  639. enum_generator.append(R"~~~(
  640. auto @js_name.as_string@ = TRY(@js_name@@js_suffix@.to_string(vm));
  641. )~~~");
  642. auto first = true;
  643. for (auto& it : enumeration.translated_cpp_names) {
  644. enum_generator.set("enum.alt.name", it.key);
  645. enum_generator.set("enum.alt.value", it.value);
  646. enum_generator.set("else", first ? "" : "else ");
  647. first = false;
  648. enum_generator.append(R"~~~(
  649. @else@if (@js_name.as_string@ == "@enum.alt.name@"sv)
  650. @cpp_name@ = @parameter.type.name@::@enum.alt.value@;
  651. )~~~");
  652. }
  653. // NOTE: Attribute setters return undefined instead of throwing when the string doesn't match an enum value.
  654. if constexpr (!IsSame<Attribute, RemoveConst<ParameterType>>) {
  655. enum_generator.append(R"~~~(
  656. @else@
  657. return vm.throw_completion<JS::TypeError>(JS::ErrorType::InvalidEnumerationValue, @js_name.as_string@, "@parameter.type.name@");
  658. )~~~");
  659. } else {
  660. enum_generator.append(R"~~~(
  661. @else@
  662. return JS::js_undefined();
  663. )~~~");
  664. }
  665. if (optional) {
  666. enum_generator.append(R"~~~(
  667. }
  668. )~~~");
  669. }
  670. } else if (interface.dictionaries.contains(parameter.type->name)) {
  671. if (optional_default_value.has_value() && optional_default_value != "{}")
  672. TODO();
  673. auto dictionary_generator = scoped_generator.fork();
  674. dictionary_generator.append(R"~~~(
  675. if (!@js_name@@js_suffix@.is_nullish() && !@js_name@@js_suffix@.is_object())
  676. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@");
  677. @parameter.type.name@ @cpp_name@ {};
  678. )~~~");
  679. auto* current_dictionary = &interface.dictionaries.find(parameter.type->name)->value;
  680. while (true) {
  681. for (auto& member : current_dictionary->members) {
  682. dictionary_generator.set("member_key", member.name);
  683. auto member_js_name = make_input_acceptable_cpp(member.name.to_snakecase());
  684. dictionary_generator.set("member_name", member_js_name);
  685. dictionary_generator.append(R"~~~(
  686. JS::Value @member_name@;
  687. if (@js_name@@js_suffix@.is_nullish()) {
  688. @member_name@ = JS::js_undefined();
  689. } else {
  690. @member_name@ = TRY(@js_name@@js_suffix@.as_object().get("@member_key@"));
  691. }
  692. )~~~");
  693. if (member.required) {
  694. dictionary_generator.append(R"~~~(
  695. if (@member_name@.is_undefined())
  696. return vm.throw_completion<JS::TypeError>(JS::ErrorType::MissingRequiredProperty, "@member_key@");
  697. )~~~");
  698. }
  699. auto member_value_name = String::formatted("{}_value", member_js_name);
  700. dictionary_generator.set("member_value_name", member_value_name);
  701. generate_to_cpp(dictionary_generator, member, member_js_name, "", member_value_name, interface, member.extended_attributes.contains("LegacyNullToEmptyString"), !member.required, member.default_value);
  702. dictionary_generator.append(R"~~~(
  703. @cpp_name@.@member_name@ = @member_value_name@;
  704. )~~~");
  705. }
  706. if (current_dictionary->parent_name.is_null())
  707. break;
  708. VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
  709. current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
  710. }
  711. } else if (interface.callback_functions.contains(parameter.type->name)) {
  712. // https://webidl.spec.whatwg.org/#es-callback-function
  713. auto callback_function_generator = scoped_generator.fork();
  714. auto& callback_function = interface.callback_functions.find(parameter.type->name)->value;
  715. // An ECMAScript value V is converted to an IDL callback function type value by running the following algorithm:
  716. // 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.
  717. if (!callback_function.is_legacy_treat_non_object_as_null) {
  718. callback_function_generator.append(R"~~~(
  719. if (!@js_name@@js_suffix@.is_function())
  720. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, @js_name@@js_suffix@.to_string_without_side_effects());
  721. )~~~");
  722. }
  723. // 2. Return the IDL callback function type value that represents a reference to the same object that V represents, with the incumbent settings object as the callback context.
  724. if (callback_function.is_legacy_treat_non_object_as_null) {
  725. callback_function_generator.append(R"~~~(
  726. Bindings::CallbackType* @cpp_name@ = nullptr;
  727. if (@js_name@@js_suffix@.is_object())
  728. @cpp_name@ = vm.heap().allocate_without_realm<CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_settings_object());
  729. )~~~");
  730. } else {
  731. callback_function_generator.append(R"~~~(
  732. auto @cpp_name@ = vm.heap().allocate_without_realm<CallbackType>(@js_name@@js_suffix@.as_object(), HTML::incumbent_settings_object());
  733. )~~~");
  734. }
  735. } else if (parameter.type->name == "sequence") {
  736. // https://webidl.spec.whatwg.org/#es-sequence
  737. auto sequence_generator = scoped_generator.fork();
  738. auto& parameterized_type = verify_cast<IDL::ParameterizedType>(*parameter.type);
  739. sequence_generator.set("recursion_depth", String::number(recursion_depth));
  740. // An ECMAScript value V is converted to an IDL sequence<T> value as follows:
  741. // 1. If Type(V) is not Object, throw a TypeError.
  742. // 2. Let method be ? GetMethod(V, @@iterator).
  743. // 3. If method is undefined, throw a TypeError.
  744. // 4. Return the result of creating a sequence from V and method.
  745. if (optional) {
  746. auto sequence_cpp_type = idl_type_name_to_cpp_type(parameterized_type.parameters.first(), interface);
  747. sequence_generator.set("sequence.type", sequence_cpp_type.name);
  748. sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type));
  749. if (!optional_default_value.has_value()) {
  750. if (sequence_cpp_type.sequence_storage_type == IDL::SequenceStorageType::Vector) {
  751. sequence_generator.append(R"~~~(
  752. Optional<@sequence.storage_type@<@sequence.type@>> @cpp_name@;
  753. )~~~");
  754. } else {
  755. sequence_generator.append(R"~~~(
  756. Optional<@sequence.storage_type@> @cpp_name@;
  757. )~~~");
  758. }
  759. } else {
  760. if (optional_default_value != "[]")
  761. TODO();
  762. if (sequence_cpp_type.sequence_storage_type == IDL::SequenceStorageType::Vector) {
  763. sequence_generator.append(R"~~~(
  764. @sequence.storage_type@<@sequence.type@> @cpp_name@;
  765. )~~~");
  766. } else {
  767. sequence_generator.append(R"~~~(
  768. @sequence.storage_type@ @cpp_name@ { global_object.heap() };
  769. )~~~");
  770. }
  771. }
  772. sequence_generator.append(R"~~~(
  773. if (!@js_name@@js_suffix@.is_undefined()) {
  774. )~~~");
  775. }
  776. sequence_generator.append(R"~~~(
  777. if (!@js_name@@js_suffix@.is_object())
  778. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  779. auto* iterator_method@recursion_depth@ = TRY(@js_name@@js_suffix@.get_method(vm, *vm.well_known_symbol_iterator()));
  780. if (!iterator_method@recursion_depth@)
  781. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotIterable, @js_name@@js_suffix@.to_string_without_side_effects());
  782. )~~~");
  783. parameterized_type.generate_sequence_from_iterable(sequence_generator, String::formatted("{}{}", acceptable_cpp_name, optional ? "_non_optional" : ""), String::formatted("{}{}", js_name, js_suffix), String::formatted("iterator_method{}", recursion_depth), interface, recursion_depth + 1);
  784. if (optional) {
  785. sequence_generator.append(R"~~~(
  786. @cpp_name@ = move(@cpp_name@_non_optional);
  787. }
  788. )~~~");
  789. }
  790. } else if (parameter.type->name == "record") {
  791. // https://webidl.spec.whatwg.org/#es-record
  792. auto record_generator = scoped_generator.fork();
  793. auto& parameterized_type = verify_cast<IDL::ParameterizedType>(*parameter.type);
  794. record_generator.set("recursion_depth", String::number(recursion_depth));
  795. // A record can only have two types: key type and value type.
  796. VERIFY(parameterized_type.parameters.size() == 2);
  797. // A record only allows the key to be a string.
  798. VERIFY(parameterized_type.parameters[0].is_string());
  799. // An ECMAScript value O is converted to an IDL record<K, V> value as follows:
  800. // 1. If Type(O) is not Object, throw a TypeError.
  801. // 2. Let result be a new empty instance of record<K, V>.
  802. // 3. Let keys be ? O.[[OwnPropertyKeys]]().
  803. // 4. For each key of keys:
  804. // 1. Let desc be ? O.[[GetOwnProperty]](key).
  805. // 2. If desc is not undefined and desc.[[Enumerable]] is true:
  806. // 1. Let typedKey be key converted to an IDL value of type K.
  807. // 2. Let value be ? Get(O, key).
  808. // 3. Let typedValue be value converted to an IDL value of type V.
  809. // 4. Set result[typedKey] to typedValue.
  810. // 5. Return result.
  811. auto record_cpp_type = IDL::idl_type_name_to_cpp_type(parameterized_type, interface);
  812. record_generator.set("record.type", record_cpp_type.name);
  813. // 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.
  814. // This affects record types in unions for example.
  815. if (recursion_depth == 0) {
  816. record_generator.append(R"~~~(
  817. if (!@js_name@@js_suffix@.is_object())
  818. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObject, @js_name@@js_suffix@.to_string_without_side_effects());
  819. auto& @js_name@@js_suffix@_object = @js_name@@js_suffix@.as_object();
  820. )~~~");
  821. }
  822. record_generator.append(R"~~~(
  823. @record.type@ @cpp_name@;
  824. auto record_keys@recursion_depth@ = TRY(@js_name@@js_suffix@_object.internal_own_property_keys());
  825. for (auto& key@recursion_depth@ : record_keys@recursion_depth@) {
  826. auto property_key@recursion_depth@ = MUST(JS::PropertyKey::from_value(vm, key@recursion_depth@));
  827. auto descriptor@recursion_depth@ = TRY(@js_name@@js_suffix@_object.internal_get_own_property(property_key@recursion_depth@));
  828. if (!descriptor@recursion_depth@.has_value() || !descriptor@recursion_depth@->enumerable.has_value() || !descriptor@recursion_depth@->enumerable.value())
  829. continue;
  830. )~~~");
  831. IDL::Parameter key_parameter { .type = parameterized_type.parameters[0], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  832. generate_to_cpp(record_generator, key_parameter, "key", String::number(recursion_depth), String::formatted("typed_key{}", recursion_depth), interface, false, false, {}, false, recursion_depth + 1);
  833. record_generator.append(R"~~~(
  834. auto value@recursion_depth@ = TRY(@js_name@@js_suffix@_object.get(property_key@recursion_depth@));
  835. )~~~");
  836. // FIXME: Record value types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here.
  837. IDL::Parameter value_parameter { .type = parameterized_type.parameters[1], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  838. generate_to_cpp(record_generator, value_parameter, "value", String::number(recursion_depth), String::formatted("typed_value{}", recursion_depth), interface, false, false, {}, false, recursion_depth + 1);
  839. record_generator.append(R"~~~(
  840. @cpp_name@.set(typed_key@recursion_depth@, typed_value@recursion_depth@);
  841. }
  842. )~~~");
  843. } else if (is<IDL::UnionType>(*parameter.type)) {
  844. // https://webidl.spec.whatwg.org/#es-union
  845. auto union_generator = scoped_generator.fork();
  846. auto& union_type = verify_cast<IDL::UnionType>(*parameter.type);
  847. union_generator.set("union_type", union_type.to_variant(interface));
  848. union_generator.set("recursion_depth", String::number(recursion_depth));
  849. // NOTE: This is handled out here as we need the dictionary conversion code for the {} optional default value.
  850. // 3. Let types be the flattened member types of the union type.
  851. auto types = union_type.flattened_member_types();
  852. RefPtr<Type> dictionary_type;
  853. for (auto& dictionary : interface.dictionaries) {
  854. for (auto& type : types) {
  855. if (type.name == dictionary.key) {
  856. dictionary_type = type;
  857. break;
  858. }
  859. }
  860. if (dictionary_type)
  861. break;
  862. }
  863. if (dictionary_type) {
  864. auto dictionary_generator = union_generator.fork();
  865. dictionary_generator.set("dictionary.type", dictionary_type->name);
  866. // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic.
  867. dictionary_generator.append(R"~~~(
  868. auto @js_name@@js_suffix@_to_dictionary = [&vm](JS::Value @js_name@@js_suffix@) -> JS::ThrowCompletionOr<@dictionary.type@> {
  869. )~~~");
  870. IDL::Parameter dictionary_parameter { .type = *dictionary_type, .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  871. generate_to_cpp(dictionary_generator, dictionary_parameter, js_name, js_suffix, "dictionary_union_type"sv, interface, false, false, {}, false, recursion_depth + 1);
  872. dictionary_generator.append(R"~~~(
  873. return dictionary_union_type;
  874. };
  875. )~~~");
  876. }
  877. // A lambda is used because Variants without "Empty" can't easily be default initialized.
  878. // Plus, this would require the user of union types to always accept a Variant with an Empty type.
  879. // Additionally, it handles the case of unconditionally throwing a TypeError at the end if none of the types match.
  880. // 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.
  881. // Note that all the other types only throw on a condition.
  882. // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic.
  883. StringBuilder to_variant_captures;
  884. to_variant_captures.append("&vm, &realm"sv);
  885. if (dictionary_type)
  886. to_variant_captures.append(String::formatted(", &{}{}_to_dictionary", js_name, js_suffix));
  887. union_generator.set("to_variant_captures", to_variant_captures.to_string());
  888. union_generator.append(R"~~~(
  889. auto @js_name@@js_suffix@_to_variant = [@to_variant_captures@](JS::Value @js_name@@js_suffix@) -> JS::ThrowCompletionOr<@union_type@> {
  890. // These might be unused.
  891. (void)vm;
  892. (void)realm;
  893. )~~~");
  894. // 1. If the union type includes undefined and V is undefined, then return the unique undefined value.
  895. if (union_type.includes_undefined()) {
  896. scoped_generator.append(R"~~~(
  897. if (@js_name@@js_suffix@.is_undefined())
  898. return Empty {};
  899. )~~~");
  900. }
  901. // FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
  902. if (union_type.includes_nullable_type()) {
  903. TODO();
  904. } else if (dictionary_type) {
  905. // 4. If V is null or undefined, then
  906. // 4.1 If types includes a dictionary type, then return the result of converting V to that dictionary type.
  907. union_generator.append(R"~~~(
  908. if (@js_name@@js_suffix@.is_nullish())
  909. return @union_type@ { TRY(@js_name@@js_suffix@_to_dictionary(@js_name@@js_suffix@)) };
  910. )~~~");
  911. }
  912. bool includes_object = false;
  913. for (auto& type : types) {
  914. if (type.name == "object") {
  915. includes_object = true;
  916. break;
  917. }
  918. }
  919. // FIXME: Don't generate this if the union type doesn't include any object types.
  920. union_generator.append(R"~~~(
  921. if (@js_name@@js_suffix@.is_object()) {
  922. [[maybe_unused]] auto& @js_name@@js_suffix@_object = @js_name@@js_suffix@.as_object();
  923. )~~~");
  924. bool includes_wrappable_type = false;
  925. for (auto& type : types) {
  926. if (IDL::is_wrappable_type(type)) {
  927. includes_wrappable_type = true;
  928. break;
  929. }
  930. }
  931. if (includes_wrappable_type) {
  932. // 5. If V is a platform object, then:
  933. union_generator.append(R"~~~(
  934. if (is<PlatformObject>(@js_name@@js_suffix@_object)) {
  935. )~~~");
  936. // 1. If types includes an interface type that V implements, then return the IDL value that is a reference to the object V.
  937. for (auto& type : types) {
  938. if (!IDL::is_wrappable_type(type))
  939. continue;
  940. auto union_platform_object_type_generator = union_generator.fork();
  941. union_platform_object_type_generator.set("platform_object_type", String::formatted("{}Wrapper", type.name));
  942. auto cpp_type = IDL::idl_type_name_to_cpp_type(type, interface);
  943. union_platform_object_type_generator.set("refptr_type", cpp_type.name);
  944. union_platform_object_type_generator.append(R"~~~(
  945. if (is<@platform_object_type@>(@js_name@@js_suffix@_object))
  946. return @refptr_type@ { static_cast<@platform_object_type@&>(@js_name@@js_suffix@_object).impl() };
  947. )~~~");
  948. }
  949. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  950. if (includes_object) {
  951. union_generator.append(R"~~~(
  952. return @js_name@@js_suffix@_object;
  953. )~~~");
  954. }
  955. union_generator.append(R"~~~(
  956. }
  957. )~~~");
  958. }
  959. // 6. If Type(V) is Object and V has an [[ArrayBufferData]] internal slot, then
  960. // 1. If types includes ArrayBuffer, then return the result of converting V to ArrayBuffer.
  961. for (auto& type : types) {
  962. if (type.name == "BufferSource") {
  963. union_generator.append(R"~~~(
  964. if (is<JS::ArrayBuffer>(@js_name@@js_suffix@_object))
  965. return JS::make_handle(@js_name@@js_suffix@_object);
  966. )~~~");
  967. }
  968. }
  969. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  970. if (includes_object) {
  971. union_generator.append(R"~~~(
  972. return @js_name@@js_suffix@_object;
  973. )~~~");
  974. }
  975. // FIXME: 7. If Type(V) is Object and V has a [[DataView]] internal slot, then:
  976. // 1. If types includes DataView, then return the result of converting V to DataView.
  977. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  978. // FIXME: 8. If Type(V) is Object and V has a [[TypedArrayName]] internal slot, then:
  979. // 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.
  980. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  981. // FIXME: 9. If IsCallable(V) is true, then:
  982. // 1. If types includes a callback function type, then return the result of converting V to that callback function type.
  983. // 2. If types includes object, then return the IDL value that is a reference to the object V.
  984. // 10. If Type(V) is Object, then:
  985. // 1. If types includes a sequence type, then:
  986. RefPtr<IDL::ParameterizedType> sequence_type;
  987. for (auto& type : types) {
  988. if (type.name == "sequence") {
  989. sequence_type = verify_cast<IDL::ParameterizedType>(type);
  990. break;
  991. }
  992. }
  993. if (sequence_type) {
  994. // 1. Let method be ? GetMethod(V, @@iterator).
  995. union_generator.append(R"~~~(
  996. auto* method = TRY(@js_name@@js_suffix@.get_method(vm, *vm.well_known_symbol_iterator()));
  997. )~~~");
  998. // 2. If method is not undefined, return the result of creating a sequence of that type from V and method.
  999. union_generator.append(R"~~~(
  1000. if (method) {
  1001. )~~~");
  1002. sequence_type->generate_sequence_from_iterable(union_generator, acceptable_cpp_name, String::formatted("{}{}", js_name, js_suffix), "method", interface, recursion_depth + 1);
  1003. union_generator.append(R"~~~(
  1004. return @cpp_name@;
  1005. }
  1006. )~~~");
  1007. }
  1008. // FIXME: 2. If types includes a frozen array type, then
  1009. // 1. Let method be ? GetMethod(V, @@iterator).
  1010. // 2. If method is not undefined, return the result of creating a frozen array of that type from V and method.
  1011. // 3. If types includes a dictionary type, then return the result of converting V to that dictionary type.
  1012. if (dictionary_type) {
  1013. union_generator.append(R"~~~(
  1014. return @union_type@ { TRY(@js_name@@js_suffix@_to_dictionary(@js_name@@js_suffix@)) };
  1015. )~~~");
  1016. }
  1017. // 4. If types includes a record type, then return the result of converting V to that record type.
  1018. RefPtr<IDL::ParameterizedType> record_type;
  1019. for (auto& type : types) {
  1020. if (type.name == "record") {
  1021. record_type = verify_cast<IDL::ParameterizedType>(type);
  1022. break;
  1023. }
  1024. }
  1025. if (record_type) {
  1026. IDL::Parameter record_parameter { .type = *record_type, .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  1027. generate_to_cpp(union_generator, record_parameter, js_name, js_suffix, "record_union_type"sv, interface, false, false, {}, false, recursion_depth + 1);
  1028. union_generator.append(R"~~~(
  1029. return record_union_type;
  1030. )~~~");
  1031. }
  1032. // FIXME: 5. If types includes a callback interface type, then return the result of converting V to that callback interface type.
  1033. // 6. If types includes object, then return the IDL value that is a reference to the object V.
  1034. if (includes_object) {
  1035. union_generator.append(R"~~~(
  1036. return @js_name@@js_suffix@_object;
  1037. )~~~");
  1038. }
  1039. // End of is_object.
  1040. union_generator.append(R"~~~(
  1041. }
  1042. )~~~");
  1043. // 11. If Type(V) is Boolean, then:
  1044. // 1. If types includes boolean, then return the result of converting V to boolean.
  1045. bool includes_boolean = false;
  1046. for (auto& type : types) {
  1047. if (type.name == "boolean") {
  1048. includes_boolean = true;
  1049. break;
  1050. }
  1051. }
  1052. if (includes_boolean) {
  1053. union_generator.append(R"~~~(
  1054. if (@js_name@@js_suffix@.is_boolean())
  1055. return @union_type@ { @js_name@@js_suffix@.as_bool() };
  1056. )~~~");
  1057. }
  1058. RefPtr<IDL::Type> numeric_type;
  1059. for (auto& type : types) {
  1060. if (type.is_numeric()) {
  1061. numeric_type = type;
  1062. break;
  1063. }
  1064. }
  1065. // 12. If Type(V) is Number, then:
  1066. // 1. If types includes a numeric type, then return the result of converting V to that numeric type.
  1067. if (numeric_type) {
  1068. union_generator.append(R"~~~(
  1069. if (@js_name@@js_suffix@.is_number()) {
  1070. )~~~");
  1071. // NOTE: generate_to_cpp doesn't use the parameter name.
  1072. // 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.
  1073. IDL::Parameter parameter { .type = *numeric_type, .name = String::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1074. generate_to_cpp(union_generator, parameter, js_name, js_suffix, String::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1);
  1075. union_generator.append(R"~~~(
  1076. return @js_name@@js_suffix@_number;
  1077. }
  1078. )~~~");
  1079. }
  1080. // 13. If Type(V) is BigInt, then:
  1081. // 1. If types includes bigint, then return the result of converting V to bigint
  1082. bool includes_bigint = false;
  1083. for (auto& type : types) {
  1084. if (type.name == "bigint") {
  1085. includes_bigint = true;
  1086. break;
  1087. }
  1088. }
  1089. if (includes_bigint) {
  1090. union_generator.append(R"~~~(
  1091. if (@js_name@@js_suffix@.is_bigint())
  1092. return @js_name@@js_suffix@.as_bigint();
  1093. )~~~");
  1094. }
  1095. bool includes_string = false;
  1096. for (auto& type : types) {
  1097. if (type.is_string()) {
  1098. includes_string = true;
  1099. break;
  1100. }
  1101. }
  1102. if (includes_string) {
  1103. // 14. If types includes a string type, then return the result of converting V to that type.
  1104. // NOTE: Currently all string types are converted to String.
  1105. union_generator.append(R"~~~(
  1106. return TRY(@js_name@@js_suffix@.to_string(vm));
  1107. )~~~");
  1108. } else if (numeric_type && includes_bigint) {
  1109. // 15. If types includes a numeric type and bigint, then return the result of converting V to either that numeric type or bigint.
  1110. // https://webidl.spec.whatwg.org/#converted-to-a-numeric-type-or-bigint
  1111. // NOTE: This algorithm is only used here.
  1112. // An ECMAScript value V is converted to an IDL numeric type T or bigint value by running the following algorithm:
  1113. // 1. Let x be ? ToNumeric(V).
  1114. // 2. If Type(x) is BigInt, then
  1115. // 1. Return the IDL bigint value that represents the same numeric value as x.
  1116. // 3. Assert: Type(x) is Number.
  1117. // 4. Return the result of converting x to T.
  1118. auto union_numeric_type_generator = union_generator.fork();
  1119. auto cpp_type = IDL::idl_type_name_to_cpp_type(*numeric_type, interface);
  1120. union_numeric_type_generator.set("numeric_type", cpp_type.name);
  1121. union_numeric_type_generator.append(R"~~~(
  1122. auto x = TRY(@js_name@@js_suffix@.to_numeric(vm));
  1123. if (x.is_bigint())
  1124. return x.as_bigint();
  1125. VERIFY(x.is_number());
  1126. )~~~");
  1127. // NOTE: generate_to_cpp doesn't use the parameter name.
  1128. // 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.
  1129. IDL::Parameter parameter { .type = *numeric_type, .name = String::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1130. generate_to_cpp(union_numeric_type_generator, parameter, "x", String::empty(), "x_number", interface, false, false, {}, false, recursion_depth + 1);
  1131. union_numeric_type_generator.append(R"~~~(
  1132. return x_number;
  1133. )~~~");
  1134. } else if (numeric_type) {
  1135. // 16. If types includes a numeric type, then return the result of converting V to that numeric type.
  1136. // NOTE: generate_to_cpp doesn't use the parameter name.
  1137. // 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.
  1138. IDL::Parameter parameter { .type = *numeric_type, .name = String::empty(), .optional_default_value = {}, .extended_attributes = {} };
  1139. generate_to_cpp(union_generator, parameter, js_name, js_suffix, String::formatted("{}{}_number", js_name, js_suffix), interface, false, false, {}, false, recursion_depth + 1);
  1140. union_generator.append(R"~~~(
  1141. return @js_name@@js_suffix@_number;
  1142. )~~~");
  1143. } else if (includes_boolean) {
  1144. // 17. If types includes boolean, then return the result of converting V to boolean.
  1145. union_generator.append(R"~~~(
  1146. return @union_type@ { @js_name@@js_suffix@.to_boolean() };
  1147. )~~~");
  1148. } else if (includes_bigint) {
  1149. // 18. If types includes bigint, then return the result of converting V to bigint.
  1150. union_generator.append(R"~~~(
  1151. return TRY(@js_name@@js_suffix@.to_bigint(vm));
  1152. )~~~");
  1153. } else {
  1154. // 19. Throw a TypeError.
  1155. // FIXME: Replace the error message with something more descriptive.
  1156. union_generator.append(R"~~~(
  1157. return vm.throw_completion<JS::TypeError>("No union types matched");
  1158. )~~~");
  1159. }
  1160. // Close the lambda and then perform the conversion.
  1161. union_generator.append(R"~~~(
  1162. };
  1163. )~~~");
  1164. if (!variadic) {
  1165. if (!optional) {
  1166. union_generator.append(R"~~~(
  1167. @union_type@ @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1168. )~~~");
  1169. } else {
  1170. if (!optional_default_value.has_value() || optional_default_value == "null"sv) {
  1171. union_generator.append(R"~~~(
  1172. Optional<@union_type@> @cpp_name@;
  1173. if (!@js_name@@js_suffix@.is_undefined())
  1174. @cpp_name@ = TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1175. )~~~");
  1176. } else {
  1177. if (optional_default_value == "\"\"") {
  1178. union_generator.append(R"~~~(
  1179. @union_type@ @cpp_name@ = @js_name@@js_suffix@.is_undefined() ? String::empty() : TRY(@js_name@@js_suffix@_to_variant(@js_name@@js_suffix@));
  1180. )~~~");
  1181. } else if (optional_default_value == "{}") {
  1182. VERIFY(dictionary_type);
  1183. union_generator.append(R"~~~(
  1184. @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@));
  1185. )~~~");
  1186. } else if (optional_default_value->to_int().has_value() || optional_default_value->to_uint().has_value()) {
  1187. union_generator.append(R"~~~(
  1188. @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@));
  1189. )~~~");
  1190. } else {
  1191. TODO();
  1192. }
  1193. }
  1194. }
  1195. } else {
  1196. union_generator.append(R"~~~(
  1197. Vector<@union_type@> @cpp_name@;
  1198. @cpp_name@.ensure_capacity(vm.argument_count() - @js_suffix@);
  1199. for (size_t i = @js_suffix@; i < vm.argument_count(); ++i) {
  1200. auto result = TRY(@js_name@@js_suffix@_to_variant(vm.argument(i)));
  1201. @cpp_name@.append(move(result));
  1202. }
  1203. )~~~");
  1204. }
  1205. } else {
  1206. dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name);
  1207. VERIFY_NOT_REACHED();
  1208. }
  1209. }
  1210. static void generate_argument_count_check(SourceGenerator& generator, String const& function_name, size_t argument_count)
  1211. {
  1212. if (argument_count == 0)
  1213. return;
  1214. auto argument_count_check_generator = generator.fork();
  1215. argument_count_check_generator.set("function.name", function_name);
  1216. argument_count_check_generator.set("function.nargs", String::number(argument_count));
  1217. if (argument_count == 1) {
  1218. argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountOne");
  1219. argument_count_check_generator.set(".arg_count_suffix", "");
  1220. } else {
  1221. argument_count_check_generator.set(".bad_arg_count", "JS::ErrorType::BadArgCountMany");
  1222. argument_count_check_generator.set(".arg_count_suffix", String::formatted(", \"{}\"", argument_count));
  1223. }
  1224. argument_count_check_generator.append(R"~~~(
  1225. if (vm.argument_count() < @function.nargs@)
  1226. return vm.throw_completion<JS::TypeError>(@.bad_arg_count@, "@function.name@"@.arg_count_suffix@);
  1227. )~~~");
  1228. }
  1229. static void generate_arguments(SourceGenerator& generator, Vector<IDL::Parameter> const& parameters, StringBuilder& arguments_builder, IDL::Interface const& interface)
  1230. {
  1231. auto arguments_generator = generator.fork();
  1232. Vector<String> parameter_names;
  1233. size_t argument_index = 0;
  1234. for (auto& parameter : parameters) {
  1235. parameter_names.append(make_input_acceptable_cpp(parameter.name.to_snakecase()));
  1236. if (!parameter.variadic) {
  1237. arguments_generator.set("argument.index", String::number(argument_index));
  1238. arguments_generator.append(R"~~~(
  1239. auto arg@argument.index@ = vm.argument(@argument.index@);
  1240. )~~~");
  1241. }
  1242. bool legacy_null_to_empty_string = parameter.extended_attributes.contains("LegacyNullToEmptyString");
  1243. generate_to_cpp(generator, parameter, "arg", String::number(argument_index), parameter.name.to_snakecase(), interface, legacy_null_to_empty_string, parameter.optional, parameter.optional_default_value, parameter.variadic, 0);
  1244. ++argument_index;
  1245. }
  1246. arguments_builder.join(", "sv, parameter_names);
  1247. }
  1248. // https://webidl.spec.whatwg.org/#create-sequence-from-iterable
  1249. void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& generator, String const& cpp_name, String const& iterable_cpp_name, String const& iterator_method_cpp_name, IDL::Interface const& interface, size_t recursion_depth) const
  1250. {
  1251. auto sequence_generator = generator.fork();
  1252. sequence_generator.set("cpp_name", cpp_name);
  1253. sequence_generator.set("iterable_cpp_name", iterable_cpp_name);
  1254. sequence_generator.set("iterator_method_cpp_name", iterator_method_cpp_name);
  1255. sequence_generator.set("recursion_depth", String::number(recursion_depth));
  1256. auto sequence_cpp_type = idl_type_name_to_cpp_type(parameters.first(), interface);
  1257. sequence_generator.set("sequence.type", sequence_cpp_type.name);
  1258. sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type));
  1259. // To create an IDL value of type sequence<T> given an iterable iterable and an iterator getter method, perform the following steps:
  1260. // 1. Let iter be ? GetIterator(iterable, sync, method).
  1261. // 2. Initialize i to be 0.
  1262. // 3. Repeat
  1263. // 1. Let next be ? IteratorStep(iter).
  1264. // 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.
  1265. // 3. Let nextItem be ? IteratorValue(next).
  1266. // 4. Initialize Si to the result of converting nextItem to an IDL value of type T.
  1267. // 5. Set i to i + 1.
  1268. sequence_generator.append(R"~~~(
  1269. auto iterator@recursion_depth@ = TRY(JS::get_iterator(vm, @iterable_cpp_name@, JS::IteratorHint::Sync, @iterator_method_cpp_name@));
  1270. )~~~");
  1271. if (sequence_cpp_type.sequence_storage_type == SequenceStorageType::Vector) {
  1272. sequence_generator.append(R"~~~(
  1273. @sequence.storage_type@<@sequence.type@> @cpp_name@;
  1274. )~~~");
  1275. } else {
  1276. sequence_generator.append(R"~~~(
  1277. @sequence.storage_type@ @cpp_name@ { vm.heap() };
  1278. )~~~");
  1279. }
  1280. sequence_generator.append(R"~~~(
  1281. for (;;) {
  1282. auto* next@recursion_depth@ = TRY(JS::iterator_step(vm, iterator@recursion_depth@));
  1283. if (!next@recursion_depth@)
  1284. break;
  1285. auto next_item@recursion_depth@ = TRY(JS::iterator_value(vm, *next@recursion_depth@));
  1286. )~~~");
  1287. // FIXME: Sequences types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here.
  1288. IDL::Parameter parameter { .type = parameters.first(), .name = iterable_cpp_name, .optional_default_value = {}, .extended_attributes = {} };
  1289. generate_to_cpp(sequence_generator, parameter, "next_item", String::number(recursion_depth), String::formatted("sequence_item{}", recursion_depth), interface, false, false, {}, false, recursion_depth);
  1290. sequence_generator.append(R"~~~(
  1291. @cpp_name@.append(sequence_item@recursion_depth@);
  1292. }
  1293. )~~~");
  1294. }
  1295. enum class WrappingReference {
  1296. No,
  1297. Yes,
  1298. };
  1299. static void generate_wrap_statement(SourceGenerator& generator, String const& value, IDL::Type const& type, IDL::Interface const& interface, StringView result_expression, WrappingReference wrapping_reference = WrappingReference::No, size_t recursion_depth = 0)
  1300. {
  1301. auto scoped_generator = generator.fork();
  1302. scoped_generator.set("value", value);
  1303. scoped_generator.set("type", type.name);
  1304. scoped_generator.set("result_expression", result_expression);
  1305. scoped_generator.set("recursion_depth", String::number(recursion_depth));
  1306. if (type.name == "undefined") {
  1307. scoped_generator.append(R"~~~(
  1308. @result_expression@ JS::js_undefined();
  1309. )~~~");
  1310. return;
  1311. }
  1312. if (type.nullable && !is<UnionType>(type)) {
  1313. if (type.is_string()) {
  1314. scoped_generator.append(R"~~~(
  1315. if (@value@.is_null()) {
  1316. @result_expression@ JS::js_null();
  1317. } else {
  1318. )~~~");
  1319. } else if (type.name == "sequence") {
  1320. scoped_generator.append(R"~~~(
  1321. if (!@value@.has_value()) {
  1322. @result_expression@ JS::js_null();
  1323. } else {
  1324. )~~~");
  1325. } else {
  1326. scoped_generator.append(R"~~~(
  1327. if (!@value@) {
  1328. @result_expression@ JS::js_null();
  1329. } else {
  1330. )~~~");
  1331. }
  1332. }
  1333. if (type.is_string()) {
  1334. scoped_generator.append(R"~~~(
  1335. @result_expression@ JS::js_string(vm, @value@);
  1336. )~~~");
  1337. } else if (type.name == "sequence") {
  1338. // https://webidl.spec.whatwg.org/#es-sequence
  1339. auto& sequence_generic_type = verify_cast<IDL::ParameterizedType>(type);
  1340. scoped_generator.append(R"~~~(
  1341. auto* new_array@recursion_depth@ = MUST(JS::Array::create(realm, 0));
  1342. )~~~");
  1343. if (!type.nullable) {
  1344. scoped_generator.append(R"~~~(
  1345. for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@.size(); ++i@recursion_depth@) {
  1346. auto& element@recursion_depth@ = @value@.at(i@recursion_depth@);
  1347. )~~~");
  1348. } else {
  1349. scoped_generator.append(R"~~~(
  1350. auto& @value@_non_optional = @value@.value();
  1351. for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@_non_optional.size(); ++i@recursion_depth@) {
  1352. auto& element@recursion_depth@ = @value@_non_optional.at(i@recursion_depth@);
  1353. )~~~");
  1354. }
  1355. if (impl_is_wrapper(sequence_generic_type.parameters.first())) {
  1356. scoped_generator.append(R"~~~(
  1357. auto* wrapped_element@recursion_depth@ = wrap(realm, *element@recursion_depth@);
  1358. )~~~");
  1359. } else {
  1360. generate_wrap_statement(scoped_generator, String::formatted("element{}", recursion_depth), sequence_generic_type.parameters.first(), interface, String::formatted("auto wrapped_element{} =", recursion_depth), WrappingReference::Yes, recursion_depth + 1);
  1361. }
  1362. scoped_generator.append(R"~~~(
  1363. auto property_index@recursion_depth@ = JS::PropertyKey { i@recursion_depth@ };
  1364. MUST(new_array@recursion_depth@->create_data_property(property_index@recursion_depth@, wrapped_element@recursion_depth@));
  1365. }
  1366. @result_expression@ new_array@recursion_depth@;
  1367. )~~~");
  1368. } else if (type.name == "boolean" || type.name == "double" || type.name == "float") {
  1369. scoped_generator.append(R"~~~(
  1370. @result_expression@ JS::Value(@value@);
  1371. )~~~");
  1372. } else if (type.name == "short" || type.name == "long" || type.name == "unsigned short") {
  1373. scoped_generator.append(R"~~~(
  1374. @result_expression@ JS::Value((i32)@value@);
  1375. )~~~");
  1376. } else if (type.name == "unsigned long") {
  1377. scoped_generator.append(R"~~~(
  1378. @result_expression@ JS::Value((u32)@value@);
  1379. )~~~");
  1380. } else if (type.name == "long long") {
  1381. scoped_generator.append(R"~~~(
  1382. @result_expression@ JS::Value((double)@value@);
  1383. )~~~");
  1384. } else if (type.name == "unsigned long long") {
  1385. scoped_generator.append(R"~~~(
  1386. @result_expression@ JS::Value((double)@value@);
  1387. )~~~");
  1388. } else if (type.name == "Location" || type.name == "Promise" || type.name == "Uint8Array" || type.name == "Uint8ClampedArray" || type.name == "any") {
  1389. scoped_generator.append(R"~~~(
  1390. @result_expression@ @value@;
  1391. )~~~");
  1392. } else if (is<IDL::UnionType>(type)) {
  1393. auto& union_type = verify_cast<IDL::UnionType>(type);
  1394. auto union_types = union_type.flattened_member_types();
  1395. auto union_generator = scoped_generator.fork();
  1396. union_generator.append(R"~~~(
  1397. @result_expression@ @value@.visit(
  1398. )~~~");
  1399. for (size_t current_union_type_index = 0; current_union_type_index < union_types.size(); ++current_union_type_index) {
  1400. auto& current_union_type = union_types.at(current_union_type_index);
  1401. auto cpp_type = IDL::idl_type_name_to_cpp_type(current_union_type, interface);
  1402. union_generator.set("current_type", cpp_type.name);
  1403. union_generator.append(R"~~~(
  1404. [&vm, &realm](@current_type@ const& visited_union_value@recursion_depth@) -> JS::Value {
  1405. // These may be unused.
  1406. (void)vm;
  1407. (void) realm;
  1408. )~~~");
  1409. // NOTE: While we are using const&, the underlying type for wrappable types in unions is (Nonnull)RefPtr, which are not references.
  1410. generate_wrap_statement(union_generator, String::formatted("visited_union_value{}", recursion_depth), current_union_type, interface, "return"sv, WrappingReference::No, recursion_depth + 1);
  1411. // End of current visit lambda.
  1412. // 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.
  1413. if (current_union_type_index != union_types.size() - 1 || type.nullable) {
  1414. union_generator.append(R"~~~(
  1415. },
  1416. )~~~");
  1417. } else {
  1418. union_generator.append(R"~~~(
  1419. }
  1420. )~~~");
  1421. }
  1422. }
  1423. if (type.nullable) {
  1424. union_generator.append(R"~~~(
  1425. [](Empty) -> JS::Value {
  1426. return JS::js_null();
  1427. }
  1428. )~~~");
  1429. }
  1430. // End of visit.
  1431. union_generator.append(R"~~~(
  1432. );
  1433. )~~~");
  1434. } else if (interface.enumerations.contains(type.name)) {
  1435. scoped_generator.append(R"~~~(
  1436. @result_expression@ JS::js_string(vm, Bindings::idl_enum_to_string(@value@));
  1437. )~~~");
  1438. } else if (interface.callback_functions.contains(type.name)) {
  1439. // https://webidl.spec.whatwg.org/#es-callback-function
  1440. auto& callback_function = interface.callback_functions.find(type.name)->value;
  1441. // 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.
  1442. if (callback_function.is_legacy_treat_non_object_as_null && !type.nullable) {
  1443. scoped_generator.append(R"~~~(
  1444. if (!@value@) {
  1445. @result_expression@ JS::js_null();
  1446. } else {
  1447. @result_expression@ &@value@->callback;
  1448. }
  1449. )~~~");
  1450. } else {
  1451. scoped_generator.append(R"~~~(
  1452. @result_expression@ &@value@->callback;
  1453. )~~~");
  1454. }
  1455. } else if (interface.dictionaries.contains(type.name)) {
  1456. // https://webidl.spec.whatwg.org/#es-dictionary
  1457. auto dictionary_generator = scoped_generator.fork();
  1458. dictionary_generator.append(R"~~~(
  1459. auto* dictionary_object@recursion_depth@ = JS::Object::create(realm, realm.intrinsics().object_prototype());
  1460. )~~~");
  1461. auto* current_dictionary = &interface.dictionaries.find(type.name)->value;
  1462. while (true) {
  1463. for (auto& member : current_dictionary->members) {
  1464. dictionary_generator.set("member_key", member.name);
  1465. auto member_key_js_name = String::formatted("{}{}", make_input_acceptable_cpp(member.name.to_snakecase()), recursion_depth);
  1466. dictionary_generator.set("member_name", member_key_js_name);
  1467. auto member_value_js_name = String::formatted("{}_value", member_key_js_name);
  1468. dictionary_generator.set("member_value", member_value_js_name);
  1469. auto wrapped_value_name = String::formatted("auto wrapped_{}", member_value_js_name);
  1470. dictionary_generator.set("wrapped_value_name", wrapped_value_name);
  1471. generate_wrap_statement(dictionary_generator, String::formatted("{}.{}", value, member.name), member.type, interface, wrapped_value_name, WrappingReference::No, recursion_depth + 1);
  1472. dictionary_generator.append(R"~~~(
  1473. MUST(dictionary_object@recursion_depth@->create_data_property("@member_key@", @wrapped_value_name@));
  1474. )~~~");
  1475. }
  1476. if (current_dictionary->parent_name.is_null())
  1477. break;
  1478. VERIFY(interface.dictionaries.contains(current_dictionary->parent_name));
  1479. current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value;
  1480. }
  1481. dictionary_generator.append(R"~~~(
  1482. @result_expression@ dictionary_object@recursion_depth@;
  1483. )~~~");
  1484. } else if (type.name == "object") {
  1485. scoped_generator.append(R"~~~(
  1486. @result_expression@ JS::Value(const_cast<JS::Object*>(@value@));
  1487. )~~~");
  1488. } else {
  1489. if (wrapping_reference == WrappingReference::No) {
  1490. scoped_generator.append(R"~~~(
  1491. @result_expression@ wrap(realm, const_cast<@type@&>(*@value@));
  1492. )~~~");
  1493. } else {
  1494. scoped_generator.append(R"~~~(
  1495. @result_expression@ wrap(realm, const_cast<@type@&>(@value@));
  1496. )~~~");
  1497. }
  1498. }
  1499. if (type.nullable && !is<UnionType>(type)) {
  1500. scoped_generator.append(R"~~~(
  1501. }
  1502. )~~~");
  1503. }
  1504. }
  1505. enum class StaticFunction {
  1506. No,
  1507. Yes,
  1508. };
  1509. static void generate_return_statement(SourceGenerator& generator, IDL::Type const& return_type, IDL::Interface const& interface)
  1510. {
  1511. return generate_wrap_statement(generator, "retval", return_type, interface, "return"sv);
  1512. }
  1513. static void generate_variable_statement(SourceGenerator& generator, String const& variable_name, IDL::Type const& value_type, String const& value_name, IDL::Interface const& interface)
  1514. {
  1515. auto variable_generator = generator.fork();
  1516. variable_generator.set("variable_name", variable_name);
  1517. variable_generator.append(R"~~~(
  1518. JS::Value @variable_name@;
  1519. )~~~");
  1520. return generate_wrap_statement(generator, value_name, value_type, interface, String::formatted("{} = ", variable_name));
  1521. }
  1522. static void generate_function(SourceGenerator& generator, IDL::Function const& function, StaticFunction is_static_function, String const& class_name, String const& interface_fully_qualified_name, IDL::Interface const& interface)
  1523. {
  1524. auto function_generator = generator.fork();
  1525. function_generator.set("class_name", class_name);
  1526. function_generator.set("interface_fully_qualified_name", interface_fully_qualified_name);
  1527. function_generator.set("function.name", function.name);
  1528. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(function.name.to_snakecase()));
  1529. function_generator.set("overload_suffix", function.is_overloaded ? String::number(function.overload_index) : String::empty());
  1530. if (function.extended_attributes.contains("ImplementedAs")) {
  1531. auto implemented_as = function.extended_attributes.get("ImplementedAs").value();
  1532. function_generator.set("function.cpp_name", implemented_as);
  1533. } else {
  1534. function_generator.set("function.cpp_name", make_input_acceptable_cpp(function.name.to_snakecase()));
  1535. }
  1536. function_generator.append(R"~~~(
  1537. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffix@)
  1538. {
  1539. [[maybe_unused]] auto& realm = *vm.current_realm();
  1540. )~~~");
  1541. if (is_static_function == StaticFunction::No) {
  1542. function_generator.append(R"~~~(
  1543. auto* impl = TRY(impl_from(vm));
  1544. )~~~");
  1545. }
  1546. // Optimization: overloaded functions' arguments count is checked by the overload arbiter
  1547. if (!function.is_overloaded)
  1548. generate_argument_count_check(generator, function.name, function.length());
  1549. StringBuilder arguments_builder;
  1550. generate_arguments(generator, function.parameters, arguments_builder, interface);
  1551. function_generator.set(".arguments", arguments_builder.string_view());
  1552. if (is_static_function == StaticFunction::No) {
  1553. function_generator.append(R"~~~(
  1554. [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@function.cpp_name@(@.arguments@); }));
  1555. )~~~");
  1556. } else {
  1557. function_generator.append(R"~~~(
  1558. [[maybe_unused]] auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return @interface_fully_qualified_name@::@function.cpp_name@(@.arguments@); }));
  1559. )~~~");
  1560. }
  1561. generate_return_statement(generator, *function.return_type, interface);
  1562. function_generator.append(R"~~~(
  1563. }
  1564. )~~~");
  1565. }
  1566. // FIXME: This is extremely ad-hoc, implement the WebIDL overload resolution algorithm instead
  1567. static Optional<String> generate_arguments_match_check_for_count(Vector<IDL::Parameter> const& parameters, size_t argument_count)
  1568. {
  1569. Vector<String> conditions;
  1570. for (auto i = 0u; i < argument_count; ++i) {
  1571. auto const& parameter = parameters[i];
  1572. if (parameter.type->is_string() || parameter.type->is_primitive())
  1573. continue;
  1574. auto argument = String::formatted("arg{}", i);
  1575. StringBuilder condition;
  1576. condition.append('(');
  1577. if (parameter.type->nullable)
  1578. condition.appendff("{}.is_nullish() || ", argument);
  1579. else if (parameter.optional)
  1580. condition.appendff("{}.is_undefined() || ", argument);
  1581. condition.appendff("{}.is_object()", argument);
  1582. condition.append(')');
  1583. conditions.append(condition.build());
  1584. }
  1585. if (conditions.is_empty())
  1586. return {};
  1587. return String::formatted("({})", String::join(" && "sv, conditions));
  1588. }
  1589. static String generate_arguments_match_check(Function const& function)
  1590. {
  1591. Vector<String> options;
  1592. for (size_t i = 0; i < function.parameters.size(); ++i) {
  1593. if (!function.parameters[i].optional && !function.parameters[i].variadic)
  1594. continue;
  1595. auto match_check = generate_arguments_match_check_for_count(function.parameters, i);
  1596. if (match_check.has_value())
  1597. options.append(match_check.release_value());
  1598. }
  1599. if (!function.parameters.is_empty() && !function.parameters.last().variadic) {
  1600. auto match_check = generate_arguments_match_check_for_count(function.parameters, function.parameters.size());
  1601. if (match_check.has_value())
  1602. options.append(match_check.release_value());
  1603. }
  1604. return String::join(" || "sv, options);
  1605. }
  1606. static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, String const& class_name)
  1607. {
  1608. auto function_generator = generator.fork();
  1609. function_generator.set("class_name", class_name);
  1610. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  1611. function_generator.append(R"~~~(
  1612. JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@)
  1613. {
  1614. [[maybe_unused]] auto& realm = *vm.current_realm();
  1615. )~~~");
  1616. auto minimum_argument_count = get_shortest_function_length(overload_set.value);
  1617. generate_argument_count_check(function_generator, overload_set.key, minimum_argument_count);
  1618. auto overloaded_functions = overload_set.value;
  1619. quick_sort(overloaded_functions, [](auto const& a, auto const& b) { return a.length() < b.length(); });
  1620. auto fetched_arguments = 0u;
  1621. for (auto i = 0u; i < overloaded_functions.size(); ++i) {
  1622. auto const& overloaded_function = overloaded_functions[i];
  1623. auto argument_count = overloaded_function.parameters.size();
  1624. function_generator.set("argument_count", String::number(argument_count));
  1625. auto arguments_match_check = generate_arguments_match_check(overloaded_function);
  1626. function_generator.set("arguments_match_check", arguments_match_check);
  1627. function_generator.set("overload_suffix", String::number(i));
  1628. if (argument_count > fetched_arguments) {
  1629. for (auto j = fetched_arguments; j < argument_count; ++j) {
  1630. function_generator.set("argument.index", String::number(j));
  1631. function_generator.append(R"~~~(
  1632. [[maybe_unused]] auto arg@argument.index@ = vm.argument(@argument.index@);
  1633. )~~~");
  1634. }
  1635. fetched_arguments = argument_count;
  1636. }
  1637. auto is_last = i == overloaded_functions.size() - 1;
  1638. if (!is_last) {
  1639. function_generator.append(R"~~~(
  1640. if (vm.argument_count() == @argument_count@) {
  1641. )~~~");
  1642. }
  1643. if (arguments_match_check.is_empty()) {
  1644. function_generator.append(R"~~~(
  1645. return @function.name:snakecase@@overload_suffix@(vm);
  1646. )~~~");
  1647. } else {
  1648. function_generator.append(R"~~~(
  1649. if (@arguments_match_check@)
  1650. return @function.name:snakecase@@overload_suffix@(vm);
  1651. )~~~");
  1652. }
  1653. if (!is_last) {
  1654. function_generator.append(R"~~~(
  1655. }
  1656. )~~~");
  1657. }
  1658. }
  1659. function_generator.append(R"~~~(
  1660. return vm.throw_completion<JS::TypeError>(JS::ErrorType::OverloadResolutionFailed);
  1661. }
  1662. )~~~");
  1663. }
  1664. void generate_constructor_header(IDL::Interface const& interface)
  1665. {
  1666. StringBuilder builder;
  1667. SourceGenerator generator { builder };
  1668. generator.set("name", interface.name);
  1669. generator.set("fully_qualified_name", interface.fully_qualified_name);
  1670. generator.set("constructor_class", interface.constructor_class);
  1671. generator.set("constructor_class:snakecase", interface.constructor_class.to_snakecase());
  1672. generator.append(R"~~~(
  1673. #pragma once
  1674. #include <LibJS/Runtime/NativeFunction.h>
  1675. namespace Web::Bindings {
  1676. class @constructor_class@ : public JS::NativeFunction {
  1677. JS_OBJECT(@constructor_class@, JS::NativeFunction);
  1678. public:
  1679. explicit @constructor_class@(JS::Realm&);
  1680. virtual void initialize(JS::Realm&) override;
  1681. virtual ~@constructor_class@() override;
  1682. virtual JS::ThrowCompletionOr<JS::Value> call() override;
  1683. virtual JS::ThrowCompletionOr<JS::Object*> construct(JS::FunctionObject& new_target) override;
  1684. private:
  1685. virtual bool has_constructor() const override { return true; }
  1686. )~~~");
  1687. for (auto const& overload_set : interface.static_overload_sets) {
  1688. auto function_generator = generator.fork();
  1689. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  1690. function_generator.append(R"~~~(
  1691. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
  1692. )~~~");
  1693. if (overload_set.value.size() > 1) {
  1694. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  1695. function_generator.set("overload_suffix", String::number(i));
  1696. function_generator.append(R"~~~(
  1697. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
  1698. )~~~");
  1699. }
  1700. }
  1701. }
  1702. generator.append(R"~~~(
  1703. };
  1704. } // namespace Web::Bindings
  1705. )~~~");
  1706. outln("{}", generator.as_string_view());
  1707. }
  1708. void generate_constructor_implementation(IDL::Interface const& interface)
  1709. {
  1710. StringBuilder builder;
  1711. SourceGenerator generator { builder };
  1712. generator.set("name", interface.name);
  1713. generator.set("prototype_class", interface.prototype_class);
  1714. generator.set("wrapper_class", interface.wrapper_class);
  1715. generator.set("constructor_class", interface.constructor_class);
  1716. generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase());
  1717. generator.set("fully_qualified_name", interface.fully_qualified_name);
  1718. generator.append(R"~~~(
  1719. #include <LibJS/Heap/Heap.h>
  1720. #include <LibJS/Runtime/GlobalObject.h>
  1721. #include <LibJS/Runtime/IteratorOperations.h>
  1722. #include <LibJS/Runtime/ArrayBuffer.h>
  1723. #include <LibWeb/Bindings/@constructor_class@.h>
  1724. #include <LibWeb/Bindings/@prototype_class@.h>
  1725. #if __has_include(<LibWeb/Bindings/@wrapper_class@.h>)
  1726. #include <LibWeb/Bindings/@wrapper_class@.h>
  1727. #endif
  1728. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  1729. #include <LibWeb/HTML/Window.h>
  1730. #if __has_include(<LibWeb/Crypto/@name@.h>)
  1731. # include <LibWeb/Crypto/@name@.h>
  1732. #elif __has_include(<LibWeb/CSS/@name@.h>)
  1733. # include <LibWeb/CSS/@name@.h>
  1734. #elif __has_include(<LibWeb/DOM/@name@.h>)
  1735. # include <LibWeb/DOM/@name@.h>
  1736. #elif __has_include(<LibWeb/Encoding/@name@.h>)
  1737. # include <LibWeb/Encoding/@name@.h>
  1738. #elif __has_include(<LibWeb/Fetch/@name@.h>)
  1739. # include <LibWeb/Fetch/@name@.h>
  1740. #elif __has_include(<LibWeb/FileAPI/@name@.h>)
  1741. # include <LibWeb/FileAPI/@name@.h>
  1742. #elif __has_include(<LibWeb/Geometry/@name@.h>)
  1743. # include <LibWeb/Geometry/@name@.h>
  1744. #elif __has_include(<LibWeb/HTML/@name@.h>)
  1745. # include <LibWeb/HTML/@name@.h>
  1746. #elif __has_include(<LibWeb/UIEvents/@name@.h>)
  1747. # include <LibWeb/UIEvents/@name@.h>
  1748. #elif __has_include(<LibWeb/HighResolutionTime/@name@.h>)
  1749. # include <LibWeb/HighResolutionTime/@name@.h>
  1750. #elif __has_include(<LibWeb/IntersectionObserver/@name@.h>)
  1751. # include <LibWeb/IntersectionObserver/@name@.h>
  1752. #elif __has_include(<LibWeb/NavigationTiming/@name@.h>)
  1753. # include <LibWeb/NavigationTiming/@name@.h>
  1754. #elif __has_include(<LibWeb/RequestIdleCallback/@name@.h>)
  1755. # include <LibWeb/RequestIdleCallback/@name@.h>
  1756. #elif __has_include(<LibWeb/ResizeObserver/@name@.h>)
  1757. # include <LibWeb/ResizeObserver/@name@.h>
  1758. #elif __has_include(<LibWeb/SVG/@name@.h>)
  1759. # include <LibWeb/SVG/@name@.h>
  1760. #elif __has_include(<LibWeb/Selection/@name@.h>)
  1761. # include <LibWeb/Selection/@name@.h>
  1762. #elif __has_include(<LibWeb/WebSockets/@name@.h>)
  1763. # include <LibWeb/WebSockets/@name@.h>
  1764. #elif __has_include(<LibWeb/XHR/@name@.h>)
  1765. # include <LibWeb/XHR/@name@.h>
  1766. #elif __has_include(<LibWeb/URL/@name@.h>)
  1767. # include <LibWeb/URL/@name@.h>
  1768. #endif
  1769. )~~~");
  1770. for (auto& path : interface.required_imported_paths)
  1771. generate_include_for(generator, path);
  1772. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  1773. generator.append(R"~~~(
  1774. // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
  1775. using namespace Web::CSS;
  1776. using namespace Web::DOM;
  1777. using namespace Web::DOMParsing;
  1778. using namespace Web::Fetch;
  1779. using namespace Web::FileAPI;
  1780. using namespace Web::Geometry;
  1781. using namespace Web::HTML;
  1782. using namespace Web::IntersectionObserver;
  1783. using namespace Web::RequestIdleCallback;
  1784. using namespace Web::ResizeObserver;
  1785. using namespace Web::Selection;
  1786. using namespace Web::UIEvents;
  1787. using namespace Web::XHR;
  1788. using namespace Web::WebGL;
  1789. namespace Web::Bindings {
  1790. @constructor_class@::@constructor_class@(JS::Realm& realm)
  1791. : NativeFunction(*realm.intrinsics().function_prototype())
  1792. {
  1793. }
  1794. @constructor_class@::~@constructor_class@()
  1795. {
  1796. }
  1797. JS::ThrowCompletionOr<JS::Value> @constructor_class@::call()
  1798. {
  1799. return vm().throw_completion<JS::TypeError>(JS::ErrorType::ConstructorWithoutNew, "@name@");
  1800. }
  1801. JS::ThrowCompletionOr<JS::Object*> @constructor_class@::construct(FunctionObject&)
  1802. {
  1803. )~~~");
  1804. if (interface.constructors.is_empty()) {
  1805. // No constructor
  1806. generator.set("constructor.length", "0");
  1807. generator.append(R"~~~(
  1808. return vm().throw_completion<JS::TypeError>(JS::ErrorType::NotAConstructor, "@name@");
  1809. )~~~");
  1810. } else if (interface.constructors.size() == 1) {
  1811. // Single constructor
  1812. auto& constructor = interface.constructors[0];
  1813. generator.set("constructor.length", String::number(constructor.length()));
  1814. generator.append(R"~~~(
  1815. auto& vm = this->vm();
  1816. [[maybe_unused]] auto& realm = *vm.current_realm();
  1817. auto& window = verify_cast<HTML::Window>(realm.global_object());
  1818. )~~~");
  1819. if (!constructor.parameters.is_empty()) {
  1820. generate_argument_count_check(generator, constructor.name, constructor.length());
  1821. StringBuilder arguments_builder;
  1822. generate_arguments(generator, constructor.parameters, arguments_builder, interface);
  1823. generator.set(".constructor_arguments", arguments_builder.string_view());
  1824. generator.append(R"~~~(
  1825. auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::create_with_global_object(window, @.constructor_arguments@); }));
  1826. )~~~");
  1827. } else {
  1828. generator.append(R"~~~(
  1829. auto impl = TRY(throw_dom_exception_if_needed(vm, [&] { return @fully_qualified_name@::create_with_global_object(window); }));
  1830. )~~~");
  1831. }
  1832. generator.append(R"~~~(
  1833. return wrap(realm, *impl);
  1834. )~~~");
  1835. } else {
  1836. // Multiple constructor overloads - can't do that yet.
  1837. TODO();
  1838. }
  1839. generator.append(R"~~~(
  1840. }
  1841. void @constructor_class@::initialize(JS::Realm& realm)
  1842. {
  1843. auto& vm = this->vm();
  1844. auto& window = verify_cast<HTML::Window>(realm.global_object());
  1845. [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable;
  1846. NativeFunction::initialize(realm);
  1847. define_direct_property(vm.names.prototype, &window.ensure_web_prototype<@prototype_class@>("@name@"), 0);
  1848. define_direct_property(vm.names.length, JS::Value(@constructor.length@), JS::Attribute::Configurable);
  1849. )~~~");
  1850. for (auto& constant : interface.constants) {
  1851. auto constant_generator = generator.fork();
  1852. constant_generator.set("constant.name", constant.name);
  1853. generate_wrap_statement(constant_generator, constant.value, constant.type, interface, String::formatted("auto constant_{}_value =", constant.name));
  1854. constant_generator.append(R"~~~(
  1855. define_direct_property("@constant.name@", constant_@constant.name@_value, JS::Attribute::Enumerable);
  1856. )~~~");
  1857. }
  1858. // https://webidl.spec.whatwg.org/#es-operations
  1859. for (auto const& overload_set : interface.static_overload_sets) {
  1860. auto function_generator = generator.fork();
  1861. function_generator.set("function.name", overload_set.key);
  1862. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  1863. function_generator.set("function.length", String::number(get_shortest_function_length(overload_set.value)));
  1864. function_generator.append(R"~~~(
  1865. define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, default_attributes);
  1866. )~~~");
  1867. }
  1868. generator.append(R"~~~(
  1869. }
  1870. )~~~");
  1871. // Implementation: Static Functions
  1872. for (auto& function : interface.static_functions)
  1873. generate_function(generator, function, StaticFunction::Yes, interface.constructor_class, interface.fully_qualified_name, interface);
  1874. for (auto const& overload_set : interface.static_overload_sets) {
  1875. if (overload_set.value.size() == 1)
  1876. continue;
  1877. generate_overload_arbiter(generator, overload_set, interface.constructor_class);
  1878. }
  1879. generator.append(R"~~~(
  1880. } // namespace Web::Bindings
  1881. )~~~");
  1882. outln("{}", generator.as_string_view());
  1883. }
  1884. void generate_prototype_header(IDL::Interface const& interface)
  1885. {
  1886. StringBuilder builder;
  1887. SourceGenerator generator { builder };
  1888. generator.set("name", interface.name);
  1889. generator.set("fully_qualified_name", interface.fully_qualified_name);
  1890. generator.set("prototype_class", interface.prototype_class);
  1891. generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase());
  1892. generator.append(R"~~~(
  1893. #pragma once
  1894. #include <LibJS/Runtime/Object.h>
  1895. namespace Web::Bindings {
  1896. class @prototype_class@ : public JS::Object {
  1897. JS_OBJECT(@prototype_class@, JS::Object);
  1898. public:
  1899. explicit @prototype_class@(JS::Realm&);
  1900. virtual void initialize(JS::Realm&) override;
  1901. virtual ~@prototype_class@() override;
  1902. private:
  1903. )~~~");
  1904. for (auto const& overload_set : interface.overload_sets) {
  1905. auto function_generator = generator.fork();
  1906. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  1907. function_generator.append(R"~~~(
  1908. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@);
  1909. )~~~");
  1910. if (overload_set.value.size() > 1) {
  1911. for (auto i = 0u; i < overload_set.value.size(); ++i) {
  1912. function_generator.set("overload_suffix", String::number(i));
  1913. function_generator.append(R"~~~(
  1914. JS_DECLARE_NATIVE_FUNCTION(@function.name:snakecase@@overload_suffix@);
  1915. )~~~");
  1916. }
  1917. }
  1918. }
  1919. if (interface.has_stringifier) {
  1920. auto stringifier_generator = generator.fork();
  1921. stringifier_generator.append(R"~~~(
  1922. JS_DECLARE_NATIVE_FUNCTION(to_string);
  1923. )~~~");
  1924. }
  1925. if (interface.pair_iterator_types.has_value()) {
  1926. auto iterator_generator = generator.fork();
  1927. iterator_generator.append(R"~~~(
  1928. JS_DECLARE_NATIVE_FUNCTION(entries);
  1929. JS_DECLARE_NATIVE_FUNCTION(for_each);
  1930. JS_DECLARE_NATIVE_FUNCTION(keys);
  1931. JS_DECLARE_NATIVE_FUNCTION(values);
  1932. )~~~");
  1933. }
  1934. for (auto& attribute : interface.attributes) {
  1935. auto attribute_generator = generator.fork();
  1936. attribute_generator.set("attribute.name:snakecase", attribute.name.to_snakecase());
  1937. attribute_generator.append(R"~~~(
  1938. JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_getter);
  1939. )~~~");
  1940. if (!attribute.readonly) {
  1941. attribute_generator.append(R"~~~(
  1942. JS_DECLARE_NATIVE_FUNCTION(@attribute.name:snakecase@_setter);
  1943. )~~~");
  1944. }
  1945. }
  1946. generator.append(R"~~~(
  1947. };
  1948. )~~~");
  1949. for (auto& it : interface.enumerations) {
  1950. if (!it.value.is_original_definition)
  1951. continue;
  1952. auto enum_generator = generator.fork();
  1953. enum_generator.set("enum.type.name", it.key);
  1954. enum_generator.append(R"~~~(
  1955. enum class @enum.type.name@ {
  1956. )~~~");
  1957. for (auto& entry : it.value.translated_cpp_names) {
  1958. enum_generator.set("enum.entry", entry.value);
  1959. enum_generator.append(R"~~~(
  1960. @enum.entry@,
  1961. )~~~");
  1962. }
  1963. enum_generator.append(R"~~~(
  1964. };
  1965. inline String idl_enum_to_string(@enum.type.name@ value) {
  1966. switch(value) {
  1967. )~~~");
  1968. for (auto& entry : it.value.translated_cpp_names) {
  1969. enum_generator.set("enum.entry", entry.value);
  1970. enum_generator.set("enum.string", entry.key);
  1971. enum_generator.append(R"~~~(
  1972. case @enum.type.name@::@enum.entry@: return "@enum.string@";
  1973. )~~~");
  1974. }
  1975. enum_generator.append(R"~~~(
  1976. default: return "<unknown>";
  1977. };
  1978. }
  1979. )~~~");
  1980. }
  1981. generator.append(R"~~~(
  1982. } // namespace Web::Bindings
  1983. )~~~");
  1984. outln("{}", generator.as_string_view());
  1985. }
  1986. void generate_prototype_implementation(IDL::Interface const& interface)
  1987. {
  1988. StringBuilder builder;
  1989. SourceGenerator generator { builder };
  1990. generator.set("name", interface.name);
  1991. generator.set("parent_name", interface.parent_name);
  1992. generator.set("prototype_class", interface.prototype_class);
  1993. generator.set("prototype_base_class", interface.prototype_base_class);
  1994. generator.set("wrapper_class", interface.wrapper_class);
  1995. generator.set("constructor_class", interface.constructor_class);
  1996. generator.set("prototype_class:snakecase", interface.prototype_class.to_snakecase());
  1997. generator.set("fully_qualified_name", interface.fully_qualified_name);
  1998. if (interface.pair_iterator_types.has_value()) {
  1999. generator.set("iterator_name", String::formatted("{}Iterator", interface.name));
  2000. generator.set("iterator_wrapper_class", String::formatted("{}IteratorWrapper", interface.name));
  2001. }
  2002. generator.append(R"~~~(
  2003. #include <AK/Function.h>
  2004. #include <LibJS/Runtime/Array.h>
  2005. #include <LibJS/Runtime/DataView.h>
  2006. #include <LibJS/Runtime/Error.h>
  2007. #include <LibJS/Runtime/FunctionObject.h>
  2008. #include <LibJS/Runtime/GlobalObject.h>
  2009. #include <LibJS/Runtime/IteratorOperations.h>
  2010. #include <LibJS/Runtime/TypedArray.h>
  2011. #include <LibJS/Runtime/Value.h>
  2012. #include <LibWeb/Bindings/@prototype_class@.h>
  2013. #if __has_include(<LibWeb/Bindings/@wrapper_class@.h>)
  2014. #include <LibWeb/Bindings/@wrapper_class@.h>
  2015. #endif
  2016. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  2017. #include <LibWeb/Bindings/LocationObject.h>
  2018. #include <LibWeb/DOM/Element.h>
  2019. #include <LibWeb/DOM/Event.h>
  2020. #include <LibWeb/DOM/IDLEventListener.h>
  2021. #include <LibWeb/DOM/NodeFilter.h>
  2022. #include <LibWeb/DOM/Range.h>
  2023. #include <LibWeb/HTML/Origin.h>
  2024. #include <LibWeb/HTML/Scripting/Environments.h>
  2025. #include <LibWeb/HTML/Window.h>
  2026. #if __has_include(<LibWeb/Bindings/@prototype_base_class@.h>)
  2027. # include <LibWeb/Bindings/@prototype_base_class@.h>
  2028. #endif
  2029. )~~~");
  2030. for (auto& path : interface.required_imported_paths)
  2031. generate_include_for(generator, path);
  2032. emit_includes_for_all_imports(interface, generator, interface.pair_iterator_types.has_value());
  2033. generator.append(R"~~~(
  2034. // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
  2035. using namespace Web::Crypto;
  2036. using namespace Web::CSS;
  2037. using namespace Web::DOM;
  2038. using namespace Web::DOMParsing;
  2039. using namespace Web::Fetch;
  2040. using namespace Web::FileAPI;
  2041. using namespace Web::Geometry;
  2042. using namespace Web::HTML;
  2043. using namespace Web::IntersectionObserver;
  2044. using namespace Web::NavigationTiming;
  2045. using namespace Web::RequestIdleCallback;
  2046. using namespace Web::ResizeObserver;
  2047. using namespace Web::Selection;
  2048. using namespace Web::SVG;
  2049. using namespace Web::UIEvents;
  2050. using namespace Web::URL;
  2051. using namespace Web::WebSockets;
  2052. using namespace Web::XHR;
  2053. using namespace Web::WebGL;
  2054. namespace Web::Bindings {
  2055. @prototype_class@::@prototype_class@([[maybe_unused]] JS::Realm& realm))~~~");
  2056. if (interface.name == "DOMException") {
  2057. // https://webidl.spec.whatwg.org/#es-DOMException-specialness
  2058. // Object.getPrototypeOf(DOMException.prototype) === Error.prototype
  2059. generator.append(R"~~~(
  2060. : Object(*realm.intrinsics().error_prototype())
  2061. )~~~");
  2062. } else if (!interface.parent_name.is_empty()) {
  2063. generator.append(R"~~~(
  2064. : Object(verify_cast<HTML::Window>(realm.global_object()).ensure_web_prototype<@prototype_base_class@>("@parent_name@"))
  2065. )~~~");
  2066. } else {
  2067. generator.append(R"~~~(
  2068. : Object(*realm.intrinsics().object_prototype())
  2069. )~~~");
  2070. }
  2071. // FIXME: Currently almost everything gets default_attributes but it should be configurable per attribute.
  2072. // See the spec links for details
  2073. generator.append(R"~~~(
  2074. {
  2075. }
  2076. @prototype_class@::~@prototype_class@()
  2077. {
  2078. }
  2079. void @prototype_class@::initialize(JS::Realm& realm)
  2080. {
  2081. [[maybe_unused]] auto& vm = this->vm();
  2082. [[maybe_unused]] u8 default_attributes = JS::Attribute::Enumerable | JS::Attribute::Configurable | JS::Attribute::Writable;
  2083. )~~~");
  2084. if (interface.has_unscopable_member) {
  2085. generator.append(R"~~~(
  2086. auto* unscopable_object = JS::Object::create(realm, nullptr);
  2087. )~~~");
  2088. }
  2089. // https://webidl.spec.whatwg.org/#es-attributes
  2090. for (auto& attribute : interface.attributes) {
  2091. auto attribute_generator = generator.fork();
  2092. attribute_generator.set("attribute.name", attribute.name);
  2093. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  2094. if (attribute.readonly)
  2095. attribute_generator.set("attribute.setter_callback", "nullptr");
  2096. else
  2097. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  2098. if (attribute.extended_attributes.contains("Unscopable")) {
  2099. attribute_generator.append(R"~~~(
  2100. MUST(unscopable_object->create_data_property("@attribute.name@", JS::Value(true)));
  2101. )~~~");
  2102. }
  2103. attribute_generator.append(R"~~~(
  2104. define_native_accessor(realm, "@attribute.name@", @attribute.getter_callback@, @attribute.setter_callback@, default_attributes);
  2105. )~~~");
  2106. }
  2107. // https://webidl.spec.whatwg.org/#es-constants
  2108. for (auto& constant : interface.constants) {
  2109. // FIXME: Do constants need to be added to the unscopable list?
  2110. auto constant_generator = generator.fork();
  2111. constant_generator.set("constant.name", constant.name);
  2112. generate_wrap_statement(constant_generator, constant.value, constant.type, interface, String::formatted("auto constant_{}_value =", constant.name));
  2113. constant_generator.append(R"~~~(
  2114. define_direct_property("@constant.name@", constant_@constant.name@_value, JS::Attribute::Enumerable);
  2115. )~~~");
  2116. }
  2117. // https://webidl.spec.whatwg.org/#es-operations
  2118. for (auto const& overload_set : interface.overload_sets) {
  2119. auto function_generator = generator.fork();
  2120. function_generator.set("function.name", overload_set.key);
  2121. function_generator.set("function.name:snakecase", make_input_acceptable_cpp(overload_set.key.to_snakecase()));
  2122. function_generator.set("function.length", String::number(get_shortest_function_length(overload_set.value)));
  2123. // FIXME: What if only some of the overloads are Unscopable?
  2124. if (any_of(overload_set.value, [](auto const& function) { return function.extended_attributes.contains("Unscopable"); })) {
  2125. function_generator.append(R"~~~(
  2126. MUST(unscopable_object->create_data_property("@function.name@", JS::Value(true)));
  2127. )~~~");
  2128. }
  2129. function_generator.append(R"~~~(
  2130. define_native_function(realm, "@function.name@", @function.name:snakecase@, @function.length@, default_attributes);
  2131. )~~~");
  2132. }
  2133. if (interface.has_stringifier) {
  2134. // FIXME: Do stringifiers need to be added to the unscopable list?
  2135. auto stringifier_generator = generator.fork();
  2136. stringifier_generator.append(R"~~~(
  2137. define_native_function(realm, "toString", to_string, 0, default_attributes);
  2138. )~~~");
  2139. }
  2140. // https://webidl.spec.whatwg.org/#define-the-iteration-methods
  2141. // This applies to this if block and the following if block.
  2142. if (interface.indexed_property_getter.has_value()) {
  2143. auto iterator_generator = generator.fork();
  2144. iterator_generator.append(R"~~~(
  2145. 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);
  2146. )~~~");
  2147. if (interface.value_iterator_type.has_value()) {
  2148. iterator_generator.append(R"~~~(
  2149. define_direct_property(vm.names.entries, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.entries), default_attributes);
  2150. define_direct_property(vm.names.keys, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.keys), default_attributes);
  2151. define_direct_property(vm.names.values, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.values), default_attributes);
  2152. define_direct_property(vm.names.forEach, realm.intrinsics().array_prototype()->get_without_side_effects(vm.names.forEach), default_attributes);
  2153. )~~~");
  2154. }
  2155. }
  2156. if (interface.pair_iterator_types.has_value()) {
  2157. // FIXME: Do pair iterators need to be added to the unscopable list?
  2158. auto iterator_generator = generator.fork();
  2159. iterator_generator.append(R"~~~(
  2160. define_native_function(realm, vm.names.entries, entries, 0, default_attributes);
  2161. define_native_function(realm, vm.names.forEach, for_each, 1, default_attributes);
  2162. define_native_function(realm, vm.names.keys, keys, 0, default_attributes);
  2163. define_native_function(realm, vm.names.values, values, 0, default_attributes);
  2164. define_direct_property(*vm.well_known_symbol_iterator(), get_without_side_effects(vm.names.entries), JS::Attribute::Configurable | JS::Attribute::Writable);
  2165. )~~~");
  2166. }
  2167. if (interface.has_unscopable_member) {
  2168. generator.append(R"~~~(
  2169. define_direct_property(*vm.well_known_symbol_unscopables(), unscopable_object, JS::Attribute::Configurable);
  2170. )~~~");
  2171. }
  2172. generator.append(R"~~~(
  2173. Object::initialize(realm);
  2174. }
  2175. )~~~");
  2176. if (!interface.attributes.is_empty() || !interface.functions.is_empty() || interface.has_stringifier) {
  2177. generator.append(R"~~~(
  2178. static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
  2179. {
  2180. auto this_value = vm.this_value();
  2181. JS::Object* this_object = nullptr;
  2182. if (this_value.is_nullish())
  2183. this_object = &vm.current_realm()->global_object();
  2184. else
  2185. this_object = TRY(this_value.to_object(vm));
  2186. )~~~");
  2187. if (interface.name == "EventTarget") {
  2188. generator.append(R"~~~(
  2189. if (is<HTML::Window>(this_object)) {
  2190. return &static_cast<HTML::Window*>(this_object)->impl();
  2191. }
  2192. )~~~");
  2193. }
  2194. generator.append(R"~~~(
  2195. if (!is<@wrapper_class@>(this_object))
  2196. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@fully_qualified_name@");
  2197. return &static_cast<@wrapper_class@*>(this_object)->impl();
  2198. }
  2199. )~~~");
  2200. }
  2201. for (auto& attribute : interface.attributes) {
  2202. auto attribute_generator = generator.fork();
  2203. attribute_generator.set("attribute.getter_callback", attribute.getter_callback_name);
  2204. attribute_generator.set("attribute.setter_callback", attribute.setter_callback_name);
  2205. if (attribute.extended_attributes.contains("ImplementedAs")) {
  2206. auto implemented_as = attribute.extended_attributes.get("ImplementedAs").value();
  2207. attribute_generator.set("attribute.cpp_name", implemented_as);
  2208. } else {
  2209. attribute_generator.set("attribute.cpp_name", attribute.name.to_snakecase());
  2210. }
  2211. if (attribute.extended_attributes.contains("Reflect")) {
  2212. auto attribute_name = attribute.extended_attributes.get("Reflect").value();
  2213. if (attribute_name.is_null())
  2214. attribute_name = attribute.name;
  2215. attribute_name = make_input_acceptable_cpp(attribute_name);
  2216. attribute_generator.set("attribute.reflect_name", attribute_name);
  2217. } else {
  2218. attribute_generator.set("attribute.reflect_name", attribute.name.to_snakecase());
  2219. }
  2220. attribute_generator.append(R"~~~(
  2221. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@)
  2222. {
  2223. [[maybe_unused]] auto& realm = *vm.current_realm();
  2224. auto* impl = TRY(impl_from(vm));
  2225. )~~~");
  2226. if (attribute.extended_attributes.contains("Reflect")) {
  2227. if (attribute.type->name != "boolean") {
  2228. attribute_generator.append(R"~~~(
  2229. auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@);
  2230. )~~~");
  2231. } else {
  2232. attribute_generator.append(R"~~~(
  2233. auto retval = impl->has_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  2234. )~~~");
  2235. }
  2236. } else {
  2237. attribute_generator.append(R"~~~(
  2238. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->@attribute.cpp_name@(); }));
  2239. )~~~");
  2240. }
  2241. generate_return_statement(generator, *attribute.type, interface);
  2242. attribute_generator.append(R"~~~(
  2243. }
  2244. )~~~");
  2245. if (!attribute.readonly) {
  2246. attribute_generator.append(R"~~~(
  2247. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@)
  2248. {
  2249. [[maybe_unused]] auto& realm = *vm.current_realm();
  2250. auto* impl = TRY(impl_from(vm));
  2251. auto value = vm.argument(0);
  2252. )~~~");
  2253. generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface, attribute.extended_attributes.contains("LegacyNullToEmptyString"));
  2254. if (attribute.extended_attributes.contains("Reflect")) {
  2255. if (attribute.type->name != "boolean") {
  2256. attribute_generator.append(R"~~~(
  2257. impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value);
  2258. )~~~");
  2259. } else {
  2260. attribute_generator.append(R"~~~(
  2261. if (!cpp_value)
  2262. impl->remove_attribute(HTML::AttributeNames::@attribute.reflect_name@);
  2263. else
  2264. impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, String::empty());
  2265. )~~~");
  2266. }
  2267. } else {
  2268. attribute_generator.append(R"~~~(
  2269. TRY(throw_dom_exception_if_needed(vm, [&] { return impl->set_@attribute.cpp_name@(cpp_value); }));
  2270. )~~~");
  2271. }
  2272. attribute_generator.append(R"~~~(
  2273. return JS::js_undefined();
  2274. }
  2275. )~~~");
  2276. }
  2277. }
  2278. // Implementation: Functions
  2279. for (auto& function : interface.functions)
  2280. generate_function(generator, function, StaticFunction::No, interface.prototype_class, interface.fully_qualified_name, interface);
  2281. for (auto const& overload_set : interface.overload_sets) {
  2282. if (overload_set.value.size() == 1)
  2283. continue;
  2284. generate_overload_arbiter(generator, overload_set, interface.prototype_class);
  2285. }
  2286. if (interface.has_stringifier) {
  2287. auto stringifier_generator = generator.fork();
  2288. stringifier_generator.set("class_name", interface.prototype_class);
  2289. if (interface.stringifier_attribute.has_value())
  2290. stringifier_generator.set("attribute.cpp_getter_name", interface.stringifier_attribute->to_snakecase());
  2291. stringifier_generator.append(R"~~~(
  2292. JS_DEFINE_NATIVE_FUNCTION(@class_name@::to_string)
  2293. {
  2294. [[maybe_unused]] auto& realm = *vm.current_realm();
  2295. auto* impl = TRY(impl_from(vm));
  2296. )~~~");
  2297. if (interface.stringifier_attribute.has_value()) {
  2298. stringifier_generator.append(R"~~~(
  2299. auto retval = impl->@attribute.cpp_getter_name@();
  2300. )~~~");
  2301. } else {
  2302. stringifier_generator.append(R"~~~(
  2303. auto retval = TRY(throw_dom_exception_if_needed(vm, [&] { return impl->to_string(); }));
  2304. )~~~");
  2305. }
  2306. stringifier_generator.append(R"~~~(
  2307. return JS::js_string(vm, move(retval));
  2308. }
  2309. )~~~");
  2310. }
  2311. if (interface.pair_iterator_types.has_value()) {
  2312. auto iterator_generator = generator.fork();
  2313. iterator_generator.append(R"~~~(
  2314. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::entries)
  2315. {
  2316. auto& realm = *vm.current_realm();
  2317. auto* impl = TRY(impl_from(vm));
  2318. return wrap(realm, @iterator_name@::create(*impl, Object::PropertyKind::KeyAndValue));
  2319. }
  2320. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::for_each)
  2321. {
  2322. [[maybe_unused]] auto& realm = *vm.current_realm();
  2323. auto* impl = TRY(impl_from(vm));
  2324. auto callback = vm.argument(0);
  2325. if (!callback.is_function())
  2326. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAFunction, callback.to_string_without_side_effects());
  2327. auto this_value = vm.this_value();
  2328. TRY(impl->for_each([&](auto key, auto value) -> JS::ThrowCompletionOr<void> {
  2329. )~~~");
  2330. generate_variable_statement(iterator_generator, "wrapped_key", interface.pair_iterator_types->get<0>(), "key", interface);
  2331. generate_variable_statement(iterator_generator, "wrapped_value", interface.pair_iterator_types->get<1>(), "value", interface);
  2332. iterator_generator.append(R"~~~(
  2333. TRY(call(vm, callback.as_function(), vm.argument(1), wrapped_value, wrapped_key, this_value));
  2334. return {};
  2335. }));
  2336. return JS::js_undefined();
  2337. }
  2338. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::keys)
  2339. {
  2340. auto& realm = *vm.current_realm();
  2341. auto* impl = TRY(impl_from(vm));
  2342. return wrap(realm, @iterator_name@::create(*impl, Object::PropertyKind::Key));
  2343. }
  2344. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::values)
  2345. {
  2346. auto& realm = *vm.current_realm();
  2347. auto* impl = TRY(impl_from(vm));
  2348. return wrap(realm, @iterator_name@::create(*impl, Object::PropertyKind::Value));
  2349. }
  2350. )~~~");
  2351. }
  2352. generator.append(R"~~~(
  2353. } // namespace Web::Bindings
  2354. )~~~");
  2355. outln("{}", generator.as_string_view());
  2356. }
  2357. void generate_iterator_prototype_header(IDL::Interface const& interface)
  2358. {
  2359. VERIFY(interface.pair_iterator_types.has_value());
  2360. StringBuilder builder;
  2361. SourceGenerator generator { builder };
  2362. generator.set("prototype_class", String::formatted("{}IteratorPrototype", interface.name));
  2363. generator.append(R"~~~(
  2364. #pragma once
  2365. #include <LibJS/Runtime/Object.h>
  2366. namespace Web::Bindings {
  2367. class @prototype_class@ : public JS::Object {
  2368. JS_OBJECT(@prototype_class@, JS::Object);
  2369. public:
  2370. explicit @prototype_class@(JS::Realm&);
  2371. virtual void initialize(JS::Realm&) override;
  2372. virtual ~@prototype_class@() override;
  2373. private:
  2374. JS_DECLARE_NATIVE_FUNCTION(next);
  2375. };
  2376. } // namespace Web::Bindings
  2377. )~~~");
  2378. outln("{}", generator.as_string_view());
  2379. }
  2380. void generate_iterator_prototype_implementation(IDL::Interface const& interface)
  2381. {
  2382. VERIFY(interface.pair_iterator_types.has_value());
  2383. StringBuilder builder;
  2384. SourceGenerator generator { builder };
  2385. generator.set("name", String::formatted("{}Iterator", interface.name));
  2386. generator.set("prototype_class", String::formatted("{}IteratorPrototype", interface.name));
  2387. generator.set("wrapper_class", String::formatted("{}IteratorWrapper", interface.name));
  2388. generator.set("fully_qualified_name", String::formatted("{}Iterator", interface.fully_qualified_name));
  2389. generator.set("possible_include_path", String::formatted("{}Iterator", interface.name.replace("::"sv, "/"sv, ReplaceMode::All)));
  2390. generator.append(R"~~~(
  2391. #include <AK/Function.h>
  2392. #include <LibJS/Runtime/Array.h>
  2393. #include <LibJS/Runtime/Error.h>
  2394. #include <LibJS/Runtime/FunctionObject.h>
  2395. #include <LibJS/Runtime/GlobalObject.h>
  2396. #include <LibJS/Runtime/TypedArray.h>
  2397. #include <LibWeb/Bindings/@prototype_class@.h>
  2398. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  2399. #include <LibWeb/HTML/Window.h>
  2400. #if __has_include(<LibWeb/@possible_include_path@.h>)
  2401. # include <LibWeb/@possible_include_path@.h>
  2402. #endif
  2403. )~~~");
  2404. emit_includes_for_all_imports(interface, generator, true);
  2405. generator.append(R"~~~(
  2406. // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
  2407. using namespace Web::CSS;
  2408. using namespace Web::DOM;
  2409. using namespace Web::DOMParsing;
  2410. using namespace Web::Fetch;
  2411. using namespace Web::FileAPI;
  2412. using namespace Web::Geometry;
  2413. using namespace Web::HTML;
  2414. using namespace Web::IntersectionObserver;
  2415. using namespace Web::NavigationTiming;
  2416. using namespace Web::RequestIdleCallback;
  2417. using namespace Web::ResizeObserver;
  2418. using namespace Web::Selection;
  2419. using namespace Web::XHR;
  2420. using namespace Web::UIEvents;
  2421. using namespace Web::URL;
  2422. using namespace Web::WebGL;
  2423. namespace Web::Bindings {
  2424. @prototype_class@::@prototype_class@(JS::Realm& realm)
  2425. : Object(*realm.intrinsics().iterator_prototype())
  2426. {
  2427. }
  2428. @prototype_class@::~@prototype_class@()
  2429. {
  2430. }
  2431. void @prototype_class@::initialize(JS::Realm& realm)
  2432. {
  2433. auto& vm = this->vm();
  2434. Object::initialize(realm);
  2435. define_native_function(realm, vm.names.next, next, 0, JS::Attribute::Writable | JS::Attribute::Enumerable | JS::Attribute::Configurable);
  2436. define_direct_property(*vm.well_known_symbol_to_string_tag(), js_string(vm, "Iterator"), JS::Attribute::Configurable);
  2437. }
  2438. static JS::ThrowCompletionOr<@fully_qualified_name@*> impl_from(JS::VM& vm)
  2439. {
  2440. auto* this_object = TRY(vm.this_value().to_object(vm));
  2441. if (!is<@wrapper_class@>(this_object))
  2442. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "@fully_qualified_name@");
  2443. return &static_cast<@wrapper_class@*>(this_object)->impl();
  2444. }
  2445. JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::next)
  2446. {
  2447. auto* impl = TRY(impl_from(vm));
  2448. return TRY(throw_dom_exception_if_needed(vm, [&] { return impl->next(); }));
  2449. }
  2450. } // namespace Web::Bindings
  2451. )~~~");
  2452. outln("{}", generator.as_string_view());
  2453. }
  2454. }