diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp index 5e5def38326..a760c7b56ba 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/IDLGenerators.cpp @@ -16,47 +16,48 @@ Vector s_header_search_paths; namespace IDL { +// FIXME: Generate this automatically somehow. static bool is_wrappable_type(Type const& type) { - if (type.name == "EventTarget") + if (type.name() == "EventTarget") return true; - if (type.name == "Node") + if (type.name() == "Node") return true; - if (type.name == "Document") + if (type.name() == "Document") return true; - if (type.name == "Text") + if (type.name() == "Text") return true; - if (type.name == "DocumentType") + if (type.name() == "DocumentType") return true; - if (type.name.ends_with("Element"sv)) + if (type.name().ends_with("Element"sv)) return true; - if (type.name.ends_with("Event"sv)) + if (type.name().ends_with("Event"sv)) return true; - if (type.name == "ImageData") + if (type.name() == "ImageData") return true; - if (type.name == "Window") + if (type.name() == "Window") return true; - if (type.name == "Range") + if (type.name() == "Range") return true; - if (type.name == "Selection") + if (type.name() == "Selection") return true; - if (type.name == "Attribute") + if (type.name() == "Attribute") return true; - if (type.name == "NamedNodeMap") + if (type.name() == "NamedNodeMap") return true; - if (type.name == "TextMetrics") + if (type.name() == "TextMetrics") return true; - if (type.name == "AbortSignal") + if (type.name() == "AbortSignal") return true; - if (type.name == "CanvasRenderingContext2D") + if (type.name() == "CanvasRenderingContext2D") return true; - if (type.name == "WebGLRenderingContext") + if (type.name() == "WebGLRenderingContext") return true; - if (type.name == "URLSearchParams") + if (type.name() == "URLSearchParams") return true; - if (type.name == "Blob") + if (type.name() == "Blob") return true; - if (type.name == "Path2D") + if (type.name() == "Path2D") return true; return false; } @@ -75,99 +76,99 @@ static StringView sequence_storage_type_to_cpp_storage_type_name(SequenceStorage static bool impl_is_wrapper(Type const& type) { - if (type.name == "StyleSheet"sv) + if (type.name() == "StyleSheet"sv) return true; - if (type.name == "CSSStyleSheet"sv) + if (type.name() == "CSSStyleSheet"sv) return true; - if (type.name == "StyleSheetList"sv) + if (type.name() == "StyleSheetList"sv) return true; - if (type.name == "CSSRuleList"sv) + if (type.name() == "CSSRuleList"sv) return true; - if (type.name == "CSSRule"sv) + if (type.name() == "CSSRule"sv) return true; - if (type.name == "CSSStyleRule"sv) + if (type.name() == "CSSStyleRule"sv) return true; - if (type.name == "CSSFontFaceRule"sv) + if (type.name() == "CSSFontFaceRule"sv) return true; - if (type.name == "CSSConditionRule"sv) + if (type.name() == "CSSConditionRule"sv) return true; - if (type.name == "CSSGroupingRule"sv) + if (type.name() == "CSSGroupingRule"sv) return true; - if (type.name == "CSSMediaRule"sv) + if (type.name() == "CSSMediaRule"sv) return true; - if (type.name == "CSSImportRule"sv) + if (type.name() == "CSSImportRule"sv) return true; - if (type.name == "EventTarget"sv) + if (type.name() == "EventTarget"sv) return true; - if (type.name == "Node"sv) + if (type.name() == "Node"sv) return true; - if (type.name == "ShadowRoot"sv) + if (type.name() == "ShadowRoot"sv) return true; - if (type.name == "DocumentTemporary"sv) + if (type.name() == "DocumentTemporary"sv) return true; - if (type.name == "Text"sv) + if (type.name() == "Text"sv) return true; - if (type.name == "Document"sv) + if (type.name() == "Document"sv) return true; - if (type.name == "DocumentType"sv) + if (type.name() == "DocumentType"sv) return true; - if (type.name.ends_with("Element"sv)) + if (type.name().ends_with("Element"sv)) return true; - if (type.name == "XMLHttpRequest"sv) + if (type.name() == "XMLHttpRequest"sv) return true; - if (type.name == "XMLHttpRequestEventTarget"sv) + if (type.name() == "XMLHttpRequestEventTarget"sv) return true; - if (type.name == "AbortSignal"sv) + if (type.name() == "AbortSignal"sv) return true; - if (type.name == "WebSocket"sv) + if (type.name() == "WebSocket"sv) return true; - if (type.name == "Worker"sv) + if (type.name() == "Worker"sv) return true; - if (type.name == "NodeIterator"sv) + if (type.name() == "NodeIterator"sv) return true; - if (type.name == "TreeWalker"sv) + if (type.name() == "TreeWalker"sv) return true; - if (type.name == "MediaQueryList"sv) + if (type.name() == "MediaQueryList"sv) return true; - if (type.name == "MessagePort"sv) + if (type.name() == "MessagePort"sv) return true; - if (type.name == "NodeFilter"sv) + if (type.name() == "NodeFilter"sv) return true; - if (type.name == "DOMTokenList"sv) + if (type.name() == "DOMTokenList"sv) return true; - if (type.name == "DOMStringMap"sv) + if (type.name() == "DOMStringMap"sv) return true; - if (type.name == "MutationRecord"sv) + if (type.name() == "MutationRecord"sv) return true; - if (type.name == "CanvasRenderingContext2D"sv) + if (type.name() == "CanvasRenderingContext2D"sv) return true; - if (type.name == "WebGLRenderingContext"sv) + if (type.name() == "WebGLRenderingContext"sv) return true; - if (type.name == "Path2D"sv) + if (type.name() == "Path2D"sv) return true; - if (type.name == "Storage"sv) + if (type.name() == "Storage"sv) return true; - if (type.name == "File"sv) + if (type.name() == "File"sv) return true; - if (type.name == "Blob"sv) + if (type.name() == "Blob"sv) return true; - if (type.name == "URL"sv) + if (type.name() == "URL"sv) return true; - if (type.name == "URLSearchParams"sv) + if (type.name() == "URLSearchParams"sv) return true; - if (type.name == "DOMException"sv) + if (type.name() == "DOMException"sv) return true; return false; @@ -202,51 +203,51 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface) { if (is_wrappable_type(type)) { if (impl_is_wrapper(type)) { - return { .name = String::formatted("JS::Handle<{}>", type.name), .sequence_storage_type = SequenceStorageType::MarkedVector }; + return { .name = String::formatted("JS::Handle<{}>", type.name()), .sequence_storage_type = SequenceStorageType::MarkedVector }; } - if (type.nullable) - return { .name = String::formatted("RefPtr<{}>", type.name), .sequence_storage_type = SequenceStorageType::Vector }; + if (type.is_nullable()) + return { .name = String::formatted("RefPtr<{}>", type.name()), .sequence_storage_type = SequenceStorageType::Vector }; - return { .name = String::formatted("NonnullRefPtr<{}>", type.name), .sequence_storage_type = SequenceStorageType::Vector }; + return { .name = String::formatted("NonnullRefPtr<{}>", type.name()), .sequence_storage_type = SequenceStorageType::Vector }; } if (type.is_string()) return { .name = "String", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "double" && !type.nullable) + if (type.name() == "double" && !type.is_nullable()) return { .name = "double", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "float" && !type.nullable) + if (type.name() == "float" && !type.is_nullable()) return { .name = "float", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "boolean" && !type.nullable) + if (type.name() == "boolean" && !type.is_nullable()) return { .name = "bool", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "unsigned long" && !type.nullable) + if (type.name() == "unsigned long" && !type.is_nullable()) return { .name = "u32", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "unsigned short" && !type.nullable) + if (type.name() == "unsigned short" && !type.is_nullable()) return { .name = "u16", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "long long" && !type.nullable) + if (type.name() == "long long" && !type.is_nullable()) return { .name = "i64", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "unsigned long long" && !type.nullable) + if (type.name() == "unsigned long long" && !type.is_nullable()) return { .name = "u64", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "long" && !type.nullable) + if (type.name() == "long" && !type.is_nullable()) return { .name = "i32", .sequence_storage_type = SequenceStorageType::Vector }; - if (type.name == "any") + if (type.name() == "any") return { .name = "JS::Value", .sequence_storage_type = SequenceStorageType::MarkedVector }; - if (type.name == "BufferSource") + if (type.name() == "BufferSource") return { .name = "JS::Handle", .sequence_storage_type = SequenceStorageType::MarkedVector }; - if (type.name == "sequence") { + if (type.name() == "sequence") { auto& parameterized_type = verify_cast(type); - auto& sequence_type = parameterized_type.parameters.first(); + auto& sequence_type = parameterized_type.parameters().first(); auto sequence_cpp_type = idl_type_name_to_cpp_type(sequence_type, interface); auto storage_type_name = sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type); @@ -256,10 +257,10 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface) return { .name = String::formatted("{}<{}>", storage_type_name, sequence_cpp_type.name), .sequence_storage_type = SequenceStorageType::Vector }; } - if (type.name == "record") { + if (type.name() == "record") { auto& parameterized_type = verify_cast(type); - auto& record_key_type = parameterized_type.parameters[0]; - auto& record_value_type = parameterized_type.parameters[1]; + auto& record_key_type = parameterized_type.parameters()[0]; + auto& record_value_type = parameterized_type.parameters()[1]; auto record_key_cpp_type = idl_type_name_to_cpp_type(record_key_type, interface); auto record_value_cpp_type = idl_type_name_to_cpp_type(record_value_type, interface); @@ -271,14 +272,14 @@ CppType idl_type_name_to_cpp_type(Type const& type, Interface const& interface) return { .name = union_type_to_variant(union_type, interface), .sequence_storage_type = SequenceStorageType::Vector }; } - if (!type.nullable) { + if (!type.is_nullable()) { for (auto& dictionary : interface.dictionaries) { - if (type.name == dictionary.key) - return { .name = type.name, .sequence_storage_type = SequenceStorageType::Vector }; + if (type.name() == dictionary.key) + return { .name = type.name(), .sequence_storage_type = SequenceStorageType::Vector }; } } - dbgln("Unimplemented type for idl_type_name_to_cpp_type: {}{}", type.name, type.nullable ? "?" : ""); + dbgln("Unimplemented type for idl_type_name_to_cpp_type: {}{}", type.name(), type.is_nullable() ? "?" : ""); TODO(); } @@ -366,11 +367,11 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter scoped_generator.set("js_name", js_name); scoped_generator.set("js_suffix", js_suffix); scoped_generator.set("legacy_null_to_empty_string", legacy_null_to_empty_string ? "true" : "false"); - scoped_generator.set("parameter.type.name", parameter.type->name); - if (parameter.type->name == "Window") + scoped_generator.set("parameter.type.name", parameter.type->name()); + if (parameter.type->name() == "Window") scoped_generator.set("wrapper_name", "HTML::Window"); else { - scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type->name)); + scoped_generator.set("wrapper_name", String::formatted("{}Wrapper", parameter.type->name())); } if (optional_default_value.has_value()) @@ -389,7 +390,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } )~~~"); } else if (!optional) { - if (!parameter.type->nullable) { + if (!parameter.type->is_nullable()) { scoped_generator.append(R"~~~( String @cpp_name@; if (@js_name@@js_suffix@.is_null() && @legacy_null_to_empty_string@) { @@ -414,7 +415,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter else @cpp_name@ = TRY(@js_name@@js_suffix@.to_string(vm)); })~~~"); - if (optional_default_value.has_value() && (!parameter.type->nullable || optional_default_value.value() != "null")) { + if (optional_default_value.has_value() && (!parameter.type->is_nullable() || optional_default_value.value() != "null")) { scoped_generator.append(R"~~~( else { @cpp_name@ = @parameter.optional_default_value@; } @@ -424,15 +425,15 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } } - } else if (parameter.type->name.is_one_of("EventListener", "NodeFilter")) { + } else if (parameter.type->name().is_one_of("EventListener", "NodeFilter")) { // FIXME: Replace this with support for callback interfaces. https://heycam.github.io/webidl/#idl-callback-interface - if (parameter.type->name == "EventListener") + if (parameter.type->name() == "EventListener") scoped_generator.set("cpp_type", "IDLEventListener"); else - scoped_generator.set("cpp_type", parameter.type->name); + scoped_generator.set("cpp_type", parameter.type->name()); - if (parameter.type->nullable) { + if (parameter.type->is_nullable()) { scoped_generator.append(R"~~~( @cpp_type@* @cpp_name@ = nullptr; if (!@js_name@@js_suffix@.is_nullish()) { @@ -453,7 +454,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } } else if (IDL::is_wrappable_type(*parameter.type)) { - if (!parameter.type->nullable) { + if (!parameter.type->is_nullable()) { if (!optional) { scoped_generator.append(R"~~~( if (!@js_name@@js_suffix@.is_object() || !is<@wrapper_name@>(@js_name@@js_suffix@.as_object())) @@ -483,7 +484,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } )~~~"); } - } else if (parameter.type->name == "double" || parameter.type->name == "float") { + } else if (parameter.type->name() == "double" || parameter.type->name() == "float") { if (!optional) { scoped_generator.append(R"~~~( @parameter.type.name@ @cpp_name@ = TRY(@js_name@@js_suffix@.to_double(vm)); @@ -512,7 +513,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } } - } else if (parameter.type->name == "boolean") { + } else if (parameter.type->name() == "boolean") { if (!optional || optional_default_value.has_value()) { scoped_generator.append(R"~~~( bool @cpp_name@; @@ -536,7 +537,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = @parameter.optional_default_value@; )~~~"); } - } else if (parameter.type->name == "unsigned long") { + } else if (parameter.type->name() == "unsigned long") { if (!optional || optional_default_value.has_value()) { scoped_generator.append(R"~~~( u32 @cpp_name@; @@ -560,7 +561,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = @parameter.optional_default_value@UL; )~~~"); } - } else if (parameter.type->name == "unsigned short") { + } else if (parameter.type->name() == "unsigned short") { if (!optional || optional_default_value.has_value()) { scoped_generator.append(R"~~~( u16 @cpp_name@; @@ -584,7 +585,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = @parameter.optional_default_value@; )~~~"); } - } else if (parameter.type->name == "long") { + } else if (parameter.type->name() == "long") { if (!optional || optional_default_value.has_value()) { scoped_generator.append(R"~~~( i32 @cpp_name@; @@ -608,7 +609,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = @parameter.optional_default_value@L; )~~~"); } - } else if (parameter.type->name == "long long") { + } else if (parameter.type->name() == "long long") { if (!optional || optional_default_value.has_value()) { scoped_generator.append(R"~~~( i64 @cpp_name@; @@ -632,7 +633,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @cpp_name@ = @parameter.optional_default_value@L; )~~~"); } - } else if (parameter.type->name == "Promise") { + } else if (parameter.type->name() == "Promise") { // NOTE: It's not clear to me where the implicit wrapping of non-Promise values in a resolved // Promise is defined in the spec; https://webidl.spec.whatwg.org/#idl-promise doesn't say // anything of this sort. Both Gecko and Blink do it, however, so I'm sure it's correct. @@ -644,7 +645,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } auto @cpp_name@ = JS::make_handle(&static_cast(@js_name@@js_suffix@.as_object())); )~~~"); - } else if (parameter.type->name == "BufferSource") { + } else if (parameter.type->name() == "BufferSource") { scoped_generator.append(R"~~~( if (!@js_name@@js_suffix@.is_object() || !(is(@js_name@@js_suffix@.as_object()) || is(@js_name@@js_suffix@.as_object()) || is(@js_name@@js_suffix@.as_object()))) return vm.throw_completion(JS::ErrorType::NotAnObjectOfType, "@parameter.type.name@"); @@ -652,7 +653,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // TODO: Should we make this a Variant? auto @cpp_name@ = JS::make_handle(&@js_name@@js_suffix@.as_object()); )~~~"); - } else if (parameter.type->name == "any") { + } else if (parameter.type->name() == "any") { if (!optional) { scoped_generator.append(R"~~~( auto @cpp_name@ = @js_name@@js_suffix@; @@ -679,9 +680,9 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } } } - } else if (interface.enumerations.contains(parameter.type->name)) { + } else if (interface.enumerations.contains(parameter.type->name())) { auto enum_generator = scoped_generator.fork(); - auto& enumeration = interface.enumerations.find(parameter.type->name)->value; + auto& enumeration = interface.enumerations.find(parameter.type->name())->value; StringView enum_member_name; if (optional_default_value.has_value()) { VERIFY(optional_default_value->length() >= 2 && (*optional_default_value)[0] == '"' && (*optional_default_value)[optional_default_value->length() - 1] == '"'); @@ -737,7 +738,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } )~~~"); } - } else if (interface.dictionaries.contains(parameter.type->name)) { + } else if (interface.dictionaries.contains(parameter.type->name())) { if (optional_default_value.has_value() && optional_default_value != "{}") TODO(); auto dictionary_generator = scoped_generator.fork(); @@ -747,7 +748,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter @parameter.type.name@ @cpp_name@ {}; )~~~"); - auto* current_dictionary = &interface.dictionaries.find(parameter.type->name)->value; + auto* current_dictionary = &interface.dictionaries.find(parameter.type->name())->value; while (true) { for (auto& member : current_dictionary->members) { dictionary_generator.set("member_key", member.name); @@ -780,11 +781,11 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter VERIFY(interface.dictionaries.contains(current_dictionary->parent_name)); current_dictionary = &interface.dictionaries.find(current_dictionary->parent_name)->value; } - } else if (interface.callback_functions.contains(parameter.type->name)) { + } else if (interface.callback_functions.contains(parameter.type->name())) { // https://webidl.spec.whatwg.org/#es-callback-function auto callback_function_generator = scoped_generator.fork(); - auto& callback_function = interface.callback_functions.find(parameter.type->name)->value; + auto& callback_function = interface.callback_functions.find(parameter.type->name())->value; // An ECMAScript value V is converted to an IDL callback function type value by running the following algorithm: // 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. @@ -806,7 +807,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter auto @cpp_name@ = vm.heap().allocate_without_realm(@js_name@@js_suffix@.as_object(), HTML::incumbent_settings_object()); )~~~"); } - } else if (parameter.type->name == "sequence") { + } else if (parameter.type->name() == "sequence") { // https://webidl.spec.whatwg.org/#es-sequence auto sequence_generator = scoped_generator.fork(); @@ -820,7 +821,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 4. Return the result of creating a sequence from V and method. if (optional) { - auto sequence_cpp_type = idl_type_name_to_cpp_type(parameterized_type.parameters.first(), interface); + auto sequence_cpp_type = idl_type_name_to_cpp_type(parameterized_type.parameters().first(), interface); sequence_generator.set("sequence.type", sequence_cpp_type.name); sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type)); @@ -871,7 +872,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter } )~~~"); } - } else if (parameter.type->name == "record") { + } else if (parameter.type->name() == "record") { // https://webidl.spec.whatwg.org/#es-record auto record_generator = scoped_generator.fork(); @@ -879,10 +880,10 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter record_generator.set("recursion_depth", String::number(recursion_depth)); // A record can only have two types: key type and value type. - VERIFY(parameterized_type.parameters.size() == 2); + VERIFY(parameterized_type.parameters().size() == 2); // A record only allows the key to be a string. - VERIFY(parameterized_type.parameters[0].is_string()); + VERIFY(parameterized_type.parameters()[0].is_string()); // An ECMAScript value O is converted to an IDL record value as follows: // 1. If Type(O) is not Object, throw a TypeError. @@ -925,7 +926,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter continue; )~~~"); - IDL::Parameter key_parameter { .type = parameterized_type.parameters[0], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; + IDL::Parameter key_parameter { .type = parameterized_type.parameters()[0], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; 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); record_generator.append(R"~~~( @@ -933,7 +934,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); // FIXME: Record value types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here. - IDL::Parameter value_parameter { .type = parameterized_type.parameters[1], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; + IDL::Parameter value_parameter { .type = parameterized_type.parameters()[1], .name = acceptable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; 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); record_generator.append(R"~~~( @@ -956,7 +957,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter RefPtr dictionary_type; for (auto& dictionary : interface.dictionaries) { for (auto& type : types) { - if (type.name == dictionary.key) { + if (type.name() == dictionary.key) { dictionary_type = type; break; } @@ -968,7 +969,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter if (dictionary_type) { auto dictionary_generator = union_generator.fork(); - dictionary_generator.set("dictionary.type", dictionary_type->name); + dictionary_generator.set("dictionary.type", dictionary_type->name()); // The lambda must take the JS::Value to convert as a parameter instead of capturing it in order to support union types being variadic. dictionary_generator.append(R"~~~( @@ -1030,7 +1031,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter bool includes_object = false; for (auto& type : types) { - if (type.name == "object") { + if (type.name() == "object") { includes_object = true; break; } @@ -1062,7 +1063,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter continue; auto union_platform_object_type_generator = union_generator.fork(); - union_platform_object_type_generator.set("platform_object_type", String::formatted("{}Wrapper", type.name)); + union_platform_object_type_generator.set("platform_object_type", String::formatted("{}Wrapper", type.name())); auto cpp_type = IDL::idl_type_name_to_cpp_type(type, interface); union_platform_object_type_generator.set("refptr_type", cpp_type.name); @@ -1087,7 +1088,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 6. If Type(V) is Object and V has an [[ArrayBufferData]] internal slot, then // 1. If types includes ArrayBuffer, then return the result of converting V to ArrayBuffer. for (auto& type : types) { - if (type.name == "BufferSource") { + if (type.name() == "BufferSource") { union_generator.append(R"~~~( if (is(@js_name@@js_suffix@_object)) return JS::make_handle(@js_name@@js_suffix@_object); @@ -1117,7 +1118,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 1. If types includes a sequence type, then: RefPtr sequence_type; for (auto& type : types) { - if (type.name == "sequence") { + if (type.name() == "sequence") { sequence_type = verify_cast(type); break; } @@ -1157,7 +1158,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 4. If types includes a record type, then return the result of converting V to that record type. RefPtr record_type; for (auto& type : types) { - if (type.name == "record") { + if (type.name() == "record") { record_type = verify_cast(type); break; } @@ -1190,7 +1191,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 1. If types includes boolean, then return the result of converting V to boolean. bool includes_boolean = false; for (auto& type : types) { - if (type.name == "boolean") { + if (type.name() == "boolean") { includes_boolean = true; break; } @@ -1232,7 +1233,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter // 1. If types includes bigint, then return the result of converting V to bigint bool includes_bigint = false; for (auto& type : types) { - if (type.name == "bigint") { + if (type.name() == "bigint") { includes_bigint = true; break; } @@ -1367,7 +1368,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter )~~~"); } } else { - dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name); + dbgln("Unimplemented JS-to-C++ conversion: {}", parameter.type->name()); VERIFY_NOT_REACHED(); } } @@ -1427,7 +1428,7 @@ void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& ge sequence_generator.set("iterable_cpp_name", iterable_cpp_name); sequence_generator.set("iterator_method_cpp_name", iterator_method_cpp_name); sequence_generator.set("recursion_depth", String::number(recursion_depth)); - auto sequence_cpp_type = idl_type_name_to_cpp_type(parameters.first(), interface); + auto sequence_cpp_type = idl_type_name_to_cpp_type(parameters().first(), interface); sequence_generator.set("sequence.type", sequence_cpp_type.name); sequence_generator.set("sequence.storage_type", sequence_storage_type_to_cpp_storage_type_name(sequence_cpp_type.sequence_storage_type)); @@ -1465,7 +1466,7 @@ void IDL::ParameterizedType::generate_sequence_from_iterable(SourceGenerator& ge )~~~"); // FIXME: Sequences types should be TypeWithExtendedAttributes, which would allow us to get [LegacyNullToEmptyString] here. - IDL::Parameter parameter { .type = parameters.first(), .name = iterable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; + IDL::Parameter parameter { .type = parameters().first(), .name = iterable_cpp_name, .optional_default_value = {}, .extended_attributes = {} }; generate_to_cpp(sequence_generator, parameter, "next_item", String::number(recursion_depth), String::formatted("sequence_item{}", recursion_depth), interface, false, false, {}, false, recursion_depth); sequence_generator.append(R"~~~( @@ -1483,25 +1484,25 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va { auto scoped_generator = generator.fork(); scoped_generator.set("value", value); - scoped_generator.set("type", type.name); + scoped_generator.set("type", type.name()); scoped_generator.set("result_expression", result_expression); scoped_generator.set("recursion_depth", String::number(recursion_depth)); - if (type.name == "undefined") { + if (type.name() == "undefined") { scoped_generator.append(R"~~~( @result_expression@ JS::js_undefined(); )~~~"); return; } - if (type.nullable && !is(type)) { + if (type.is_nullable() && !is(type)) { if (type.is_string()) { scoped_generator.append(R"~~~( if (@value@.is_null()) { @result_expression@ JS::js_null(); } else { )~~~"); - } else if (type.name == "sequence") { + } else if (type.name() == "sequence") { scoped_generator.append(R"~~~( if (!@value@.has_value()) { @result_expression@ JS::js_null(); @@ -1520,7 +1521,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va scoped_generator.append(R"~~~( @result_expression@ JS::js_string(vm, @value@); )~~~"); - } else if (type.name == "sequence") { + } else if (type.name() == "sequence") { // https://webidl.spec.whatwg.org/#es-sequence auto& sequence_generic_type = verify_cast(type); @@ -1528,7 +1529,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va auto* new_array@recursion_depth@ = MUST(JS::Array::create(realm, 0)); )~~~"); - if (!type.nullable) { + if (!type.is_nullable()) { scoped_generator.append(R"~~~( for (size_t i@recursion_depth@ = 0; i@recursion_depth@ < @value@.size(); ++i@recursion_depth@) { auto& element@recursion_depth@ = @value@.at(i@recursion_depth@); @@ -1541,12 +1542,12 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va )~~~"); } - if (impl_is_wrapper(sequence_generic_type.parameters.first())) { + if (impl_is_wrapper(sequence_generic_type.parameters().first())) { scoped_generator.append(R"~~~( auto* wrapped_element@recursion_depth@ = &(*element@recursion_depth@); )~~~"); } else { - 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); + 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); } scoped_generator.append(R"~~~( @@ -1556,27 +1557,27 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va @result_expression@ new_array@recursion_depth@; )~~~"); - } else if (type.name == "boolean" || type.name == "double" || type.name == "float") { + } else if (type.name() == "boolean" || type.name() == "double" || type.name() == "float") { scoped_generator.append(R"~~~( @result_expression@ JS::Value(@value@); )~~~"); - } else if (type.name == "short" || type.name == "long" || type.name == "unsigned short") { + } else if (type.name() == "short" || type.name() == "long" || type.name() == "unsigned short") { scoped_generator.append(R"~~~( @result_expression@ JS::Value((i32)@value@); )~~~"); - } else if (type.name == "unsigned long") { + } else if (type.name() == "unsigned long") { scoped_generator.append(R"~~~( @result_expression@ JS::Value((u32)@value@); )~~~"); - } else if (type.name == "long long") { + } else if (type.name() == "long long") { scoped_generator.append(R"~~~( @result_expression@ JS::Value((double)@value@); )~~~"); - } else if (type.name == "unsigned long long") { + } else if (type.name() == "unsigned long long") { scoped_generator.append(R"~~~( @result_expression@ JS::Value((double)@value@); )~~~"); - } else if (type.name == "Location" || type.name == "Promise" || type.name == "Uint8Array" || type.name == "Uint8ClampedArray" || type.name == "any") { + } else if (type.name() == "Location" || type.name() == "Promise" || type.name() == "Uint8Array" || type.name() == "Uint8ClampedArray" || type.name() == "any") { scoped_generator.append(R"~~~( @result_expression@ @value@; )~~~"); @@ -1605,7 +1606,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va // End of current visit lambda. // 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. - if (current_union_type_index != union_types.size() - 1 || type.nullable) { + if (current_union_type_index != union_types.size() - 1 || type.is_nullable()) { union_generator.append(R"~~~( }, )~~~"); @@ -1616,7 +1617,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va } } - if (type.nullable) { + if (type.is_nullable()) { union_generator.append(R"~~~( [](Empty) -> JS::Value { return JS::js_null(); @@ -1628,18 +1629,18 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va union_generator.append(R"~~~( ); )~~~"); - } else if (interface.enumerations.contains(type.name)) { + } else if (interface.enumerations.contains(type.name())) { scoped_generator.append(R"~~~( @result_expression@ JS::js_string(vm, Bindings::idl_enum_to_string(@value@)); )~~~"); - } else if (interface.callback_functions.contains(type.name)) { + } else if (interface.callback_functions.contains(type.name())) { // https://webidl.spec.whatwg.org/#es-callback-function - auto& callback_function = interface.callback_functions.find(type.name)->value; + auto& callback_function = interface.callback_functions.find(type.name())->value; // 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. - if (callback_function.is_legacy_treat_non_object_as_null && !type.nullable) { + if (callback_function.is_legacy_treat_non_object_as_null && !type.is_nullable()) { scoped_generator.append(R"~~~( if (!@value@) { @result_expression@ JS::js_null(); @@ -1652,7 +1653,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va @result_expression@ &@value@->callback; )~~~"); } - } else if (interface.dictionaries.contains(type.name)) { + } else if (interface.dictionaries.contains(type.name())) { // https://webidl.spec.whatwg.org/#es-dictionary auto dictionary_generator = scoped_generator.fork(); @@ -1660,7 +1661,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va auto* dictionary_object@recursion_depth@ = JS::Object::create(realm, realm.intrinsics().object_prototype()); )~~~"); - auto* current_dictionary = &interface.dictionaries.find(type.name)->value; + auto* current_dictionary = &interface.dictionaries.find(type.name())->value; while (true) { for (auto& member : current_dictionary->members) { dictionary_generator.set("member_key", member.name); @@ -1687,7 +1688,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va dictionary_generator.append(R"~~~( @result_expression@ dictionary_object@recursion_depth@; )~~~"); - } else if (type.name == "object") { + } else if (type.name() == "object") { scoped_generator.append(R"~~~( @result_expression@ JS::Value(const_cast(@value@)); )~~~"); @@ -1703,7 +1704,7 @@ static void generate_wrap_statement(SourceGenerator& generator, String const& va } } - if (type.nullable && !is(type)) { + if (type.is_nullable() && !is(type)) { scoped_generator.append(R"~~~( } )~~~"); @@ -1794,7 +1795,7 @@ static Optional generate_arguments_match_check_for_count(Vectornullable) + if (parameter.type->is_nullable()) condition.appendff("{}.is_nullish() || ", argument); else if (parameter.optional) condition.appendff("{}.is_undefined() || ", argument); @@ -2558,7 +2559,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.getter_callback@) )~~~"); if (attribute.extended_attributes.contains("Reflect")) { - if (attribute.type->name != "boolean") { + if (attribute.type->name() != "boolean") { attribute_generator.append(R"~~~( auto retval = impl->attribute(HTML::AttributeNames::@attribute.reflect_name@); )~~~"); @@ -2592,7 +2593,7 @@ JS_DEFINE_NATIVE_FUNCTION(@prototype_class@::@attribute.setter_callback@) generate_to_cpp(generator, attribute, "value", "", "cpp_value", interface, attribute.extended_attributes.contains("LegacyNullToEmptyString")); if (attribute.extended_attributes.contains("Reflect")) { - if (attribute.type->name != "boolean") { + if (attribute.type->name() != "boolean") { attribute_generator.append(R"~~~( impl->set_attribute(HTML::AttributeNames::@attribute.reflect_name@, cpp_value); )~~~"); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/main.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/main.cpp index 08d54280c0d..c43d3580a5c 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator/main.cpp @@ -112,21 +112,21 @@ int main(int argc, char** argv) for (auto& attribute : interface.attributes) { dbgln(" {}{}{} {}", attribute.readonly ? "readonly " : "", - attribute.type->name, - attribute.type->nullable ? "?" : "", + attribute.type->name(), + attribute.type->is_nullable() ? "?" : "", attribute.name); } dbgln("Functions:"); for (auto& function : interface.functions) { dbgln(" {}{} {}", - function.return_type->name, - function.return_type->nullable ? "?" : "", + function.return_type->name(), + function.return_type->is_nullable() ? "?" : "", function.name); for (auto& parameter : function.parameters) { dbgln(" {}{} {}", - parameter.type->name, - parameter.type->nullable ? "?" : "", + parameter.type->name(), + parameter.type->is_nullable() ? "?" : "", parameter.name); } } @@ -134,13 +134,13 @@ int main(int argc, char** argv) dbgln("Static Functions:"); for (auto& function : interface.static_functions) { dbgln(" static {}{} {}", - function.return_type->name, - function.return_type->nullable ? "?" : "", + function.return_type->name(), + function.return_type->is_nullable() ? "?" : "", function.name); for (auto& parameter : function.parameters) { dbgln(" {}{} {}", - parameter.type->name, - parameter.type->nullable ? "?" : "", + parameter.type->name(), + parameter.type->is_nullable() ? "?" : "", parameter.name); } } diff --git a/Userland/Libraries/LibIDL/CMakeLists.txt b/Userland/Libraries/LibIDL/CMakeLists.txt index 6c36da7885a..b5e3b48b710 100644 --- a/Userland/Libraries/LibIDL/CMakeLists.txt +++ b/Userland/Libraries/LibIDL/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES IDLParser.cpp + Types.cpp ) serenity_lib(LibIDL idl) diff --git a/Userland/Libraries/LibIDL/IDLParser.cpp b/Userland/Libraries/LibIDL/IDLParser.cpp index 7b4d4ba9194..1d5fbb2248d 100644 --- a/Userland/Libraries/LibIDL/IDLParser.cpp +++ b/Userland/Libraries/LibIDL/IDLParser.cpp @@ -403,7 +403,7 @@ void Parser::parse_getter(HashMap& extended_attributes, Interfac auto& identifier = function.parameters.first(); - if (identifier.type->nullable) + if (identifier.type->is_nullable()) report_parsing_error("identifier's type must not be nullable."sv, filename, input, lexer.tell()); if (identifier.optional) @@ -411,18 +411,18 @@ void Parser::parse_getter(HashMap& extended_attributes, Interfac // FIXME: Disallow variadic functions once they're supported. - if (identifier.type->name == "DOMString") { + if (identifier.type->name() == "DOMString") { if (interface.named_property_getter.has_value()) report_parsing_error("An interface can only have one named property getter."sv, filename, input, lexer.tell()); interface.named_property_getter = move(function); - } else if (identifier.type->name == "unsigned long") { + } else if (identifier.type->name() == "unsigned long") { if (interface.indexed_property_getter.has_value()) report_parsing_error("An interface can only have one indexed property getter."sv, filename, input, lexer.tell()); interface.indexed_property_getter = move(function); } else { - report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell()); + report_parsing_error(String::formatted("Named/indexed property getter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name()), filename, input, lexer.tell()); } } @@ -437,7 +437,7 @@ void Parser::parse_setter(HashMap& extended_attributes, Interfac auto& identifier = function.parameters.first(); - if (identifier.type->nullable) + if (identifier.type->is_nullable()) report_parsing_error("identifier's type must not be nullable."sv, filename, input, lexer.tell()); if (identifier.optional) @@ -445,7 +445,7 @@ void Parser::parse_setter(HashMap& extended_attributes, Interfac // FIXME: Disallow variadic functions once they're supported. - if (identifier.type->name == "DOMString") { + if (identifier.type->name() == "DOMString") { if (interface.named_property_setter.has_value()) report_parsing_error("An interface can only have one named property setter."sv, filename, input, lexer.tell()); @@ -453,7 +453,7 @@ void Parser::parse_setter(HashMap& extended_attributes, Interfac report_parsing_error("A named property setter must be accompanied by a named property getter."sv, filename, input, lexer.tell()); interface.named_property_setter = move(function); - } else if (identifier.type->name == "unsigned long") { + } else if (identifier.type->name() == "unsigned long") { if (interface.indexed_property_setter.has_value()) report_parsing_error("An interface can only have one indexed property setter."sv, filename, input, lexer.tell()); @@ -462,7 +462,7 @@ void Parser::parse_setter(HashMap& extended_attributes, Interfac interface.indexed_property_setter = move(function); } else { - report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name), filename, input, lexer.tell()); + report_parsing_error(String::formatted("Named/indexed property setter's identifier's type must be either 'DOMString' or 'unsigned long', got '{}'.", identifier.type->name()), filename, input, lexer.tell()); } } @@ -477,7 +477,7 @@ void Parser::parse_deleter(HashMap& extended_attributes, Interfa auto& identifier = function.parameters.first(); - if (identifier.type->nullable) + if (identifier.type->is_nullable()) report_parsing_error("identifier's type must not be nullable."sv, filename, input, lexer.tell()); if (identifier.optional) @@ -485,7 +485,7 @@ void Parser::parse_deleter(HashMap& extended_attributes, Interfa // FIXME: Disallow variadic functions once they're supported. - if (identifier.type->name == "DOMString") { + if (identifier.type->name() == "DOMString") { if (interface.named_property_deleter.has_value()) report_parsing_error("An interface can only have one named property deleter."sv, filename, input, lexer.tell()); @@ -494,7 +494,7 @@ void Parser::parse_deleter(HashMap& extended_attributes, Interfa interface.named_property_deleter = move(function); } else { - report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type->name), filename, input, lexer.tell()); + report_parsing_error(String::formatted("Named property deleter's identifier's type must be 'DOMString', got '{}'.", identifier.type->name()), filename, input, lexer.tell()); } } @@ -809,18 +809,18 @@ static void resolve_typedef(Interface& interface, NonnullRefPtr& type, Has { if (is(*type)) { auto parameterized_type = static_ptr_cast(type); - auto& parameters = static_cast>&>(parameterized_type->parameters); + auto& parameters = static_cast>&>(parameterized_type->parameters()); for (auto& parameter : parameters) resolve_typedef(interface, parameter); return; } - auto it = interface.typedefs.find(type->name); + auto it = interface.typedefs.find(type->name()); if (it == interface.typedefs.end()) return; - bool is_nullable = type->nullable; + bool nullable = type->is_nullable(); type = it->value.type; - type->nullable = is_nullable; + type->set_nullable(nullable); if (!extended_attributes) return; for (auto& attribute : it->value.extended_attributes) diff --git a/Userland/Libraries/LibIDL/Types.cpp b/Userland/Libraries/LibIDL/Types.cpp new file mode 100644 index 00000000000..0e8ff7160c5 --- /dev/null +++ b/Userland/Libraries/LibIDL/Types.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace IDL { + +ParameterizedType const& Type::as_parameterized() const +{ + return verify_cast(*this); +} + +ParameterizedType& Type::as_parameterized() +{ + return verify_cast(*this); +} + +UnionType const& Type::as_union() const +{ + return verify_cast(*this); +} + +UnionType& Type::as_union() +{ + return verify_cast(*this); +} + +} diff --git a/Userland/Libraries/LibIDL/Types.h b/Userland/Libraries/LibIDL/Types.h index 7dc9783753d..306b14f048d 100644 --- a/Userland/Libraries/LibIDL/Types.h +++ b/Userland/Libraries/LibIDL/Types.h @@ -3,6 +3,7 @@ * Copyright (c) 2021, Linus Groh * Copyright (c) 2021, Luke Wilde * Copyright (c) 2022, Ali Mohammad Pur + * Copyright (c) 2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -41,29 +42,63 @@ struct CppType { SequenceStorageType sequence_storage_type; }; -struct Type : public RefCounted { - Type() = default; +class ParameterizedType; +class UnionType; + +class Type : public RefCounted { +public: + enum class Kind { + Plain, // AKA, Type. + Parameterized, + Union, + }; Type(String name, bool nullable) - : name(move(name)) - , nullable(nullable) + : m_kind(Kind::Plain) + , m_name(move(name)) + , m_nullable(nullable) + { + } + + Type(Kind kind, String name, bool nullable) + : m_kind(kind) + , m_name(move(name)) + , m_nullable(nullable) { } virtual ~Type() = default; - String name; - bool nullable { false }; - bool is_string() const { return name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); } + Kind kind() const { return m_kind; } + + String const& name() const { return m_name; } + + bool is_nullable() const { return m_nullable; } + void set_nullable(bool value) { m_nullable = value; } + + bool is_string() const { return m_name.is_one_of("ByteString", "CSSOMString", "DOMString", "USVString"); } // https://webidl.spec.whatwg.org/#dfn-integer-type - bool is_integer() const { return name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); } + bool is_integer() const { return m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); } // https://webidl.spec.whatwg.org/#dfn-numeric-type - bool is_numeric() const { return is_integer() || name.is_one_of("float", "unrestricted float", "double", "unrestricted double"); } + bool is_numeric() const { return is_integer() || m_name.is_one_of("float", "unrestricted float", "double", "unrestricted double"); } // https://webidl.spec.whatwg.org/#dfn-primitive-type - bool is_primitive() const { return is_numeric() || name.is_one_of("bigint", "boolean"); } + bool is_primitive() const { return is_numeric() || m_name.is_one_of("bigint", "boolean"); } + + bool is_parameterized() const { return m_kind == Kind::Parameterized; } + ParameterizedType const& as_parameterized() const; + ParameterizedType& as_parameterized(); + + bool is_union() const { return m_kind == Kind::Union; } + UnionType const& as_union() const; + UnionType& as_union(); + +private: + Kind m_kind; + String m_name; + bool m_nullable { false }; }; struct Parameter { @@ -143,20 +178,23 @@ struct CallbackFunction { class Interface; -struct ParameterizedType : public Type { - ParameterizedType() = default; - +class ParameterizedType : public Type { +public: ParameterizedType(String name, bool nullable, NonnullRefPtrVector parameters) - : Type(move(name), nullable) - , parameters(move(parameters)) + : Type(Kind::Parameterized, move(name), nullable) + , m_parameters(move(parameters)) { } virtual ~ParameterizedType() override = default; - NonnullRefPtrVector parameters; - void generate_sequence_from_iterable(SourceGenerator& generator, String const& cpp_name, String const& iterable_cpp_name, String const& iterator_method_cpp_name, IDL::Interface const&, size_t recursion_depth) const; + + NonnullRefPtrVector const& parameters() const { return m_parameters; } + NonnullRefPtrVector& parameters() { return m_parameters; } + +private: + NonnullRefPtrVector m_parameters; }; static inline size_t get_shortest_function_length(Vector const& overload_set) @@ -238,18 +276,18 @@ public: } }; -struct UnionType : public Type { - UnionType() = default; - +class UnionType : public Type { +public: UnionType(String name, bool nullable, NonnullRefPtrVector member_types) - : Type(move(name), nullable) - , member_types(move(member_types)) + : Type(Kind::Union, move(name), nullable) + , m_member_types(move(member_types)) { } virtual ~UnionType() override = default; - NonnullRefPtrVector member_types; + NonnullRefPtrVector const& member_types() const { return m_member_types; } + NonnullRefPtrVector& member_types() { return m_member_types; } // https://webidl.spec.whatwg.org/#dfn-flattened-union-member-types NonnullRefPtrVector flattened_member_types() const @@ -260,14 +298,14 @@ struct UnionType : public Type { NonnullRefPtrVector types; // 3. For each member type U of T: - for (auto& type : member_types) { + for (auto& type : m_member_types) { // FIXME: 1. If U is an annotated type, then set U to be the inner type of U. // 2. If U is a nullable type, then set U to be the inner type of U. (NOTE: Not necessary as nullable is stored with Type and not as a separate struct) // 3. If U is a union type, then add to S the flattened member types of U. - if (is(type)) { - auto& union_member_type = verify_cast(type); + if (type.is_union()) { + auto& union_member_type = type.as_union(); types.extend(union_member_type.flattened_member_types()); } else { // 4. Otherwise, U is not a union type. Add U to S. @@ -288,9 +326,9 @@ struct UnionType : public Type { size_t num_nullable_member_types = 0; // 3. For each member type U of T: - for (auto& type : member_types) { + for (auto& type : m_member_types) { // 1. If U is a nullable type, then: - if (type.nullable) { + if (type.is_nullable()) { // 1. Set n to n + 1. ++num_nullable_member_types; @@ -298,8 +336,8 @@ struct UnionType : public Type { } // 2. If U is a union type, then: - if (is(type)) { - auto& union_member_type = verify_cast(type); + if (type.is_union()) { + auto& union_member_type = type.as_union(); // 1. Let m be the number of nullable member types of U. // 2. Set n to n + m. @@ -322,18 +360,18 @@ struct UnionType : public Type { bool includes_undefined() const { // -> the type is a union type and one of its member types includes undefined. - for (auto& type : member_types) { - if (is(type)) { - auto& union_type = verify_cast(type); - if (union_type.includes_undefined()) - return true; - } + for (auto& type : m_member_types) { + if (type.is_union() && type.as_union().includes_undefined()) + return true; - if (type.name == "undefined"sv) + if (type.name() == "undefined"sv) return true; } return false; } + +private: + NonnullRefPtrVector m_member_types; }; }