Libraries: Remove LibIDL
Move the overload-resolution metadata types into LibWeb::WebIDL and update the Python generator and overload resolver to use them. LibIDL no longer has any users after the C++ bindings generator removal, so remove the library and unlink it from LibWeb.
This commit is contained in:
parent
efe144552c
commit
4a681c9148
15 changed files with 322 additions and 2678 deletions
|
|
@ -1,6 +1,5 @@
|
|||
add_subdirectory(LibCore)
|
||||
add_subdirectory(LibFileSystem)
|
||||
add_subdirectory(LibIDL)
|
||||
add_subdirectory(LibMain)
|
||||
add_subdirectory(LibRegex)
|
||||
add_subdirectory(LibSync)
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
set(SOURCES
|
||||
ExposedTo.cpp
|
||||
IDLParser.cpp
|
||||
Types.cpp
|
||||
)
|
||||
|
||||
ladybird_lib(LibIDL idl)
|
||||
target_link_libraries(LibIDL PRIVATE LibCore LibFileSystem)
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibIDL/ExposedTo.h>
|
||||
|
||||
static auto& error_string()
|
||||
{
|
||||
static NeverDestroyed<ByteString> string;
|
||||
return *string;
|
||||
}
|
||||
|
||||
namespace IDL {
|
||||
|
||||
ErrorOr<ExposedTo> parse_exposure_set(StringView interface_name, StringView exposed)
|
||||
{
|
||||
// NOTE: This roughly follows the definitions of https://webidl.spec.whatwg.org/#Exposed
|
||||
// It does not remotely interpret all the abstract operations therein though.
|
||||
|
||||
auto exposed_trimmed = exposed.trim_whitespace();
|
||||
if (exposed_trimmed == "*"sv)
|
||||
return ExposedTo::All;
|
||||
if (exposed_trimmed == "Nobody"sv)
|
||||
return ExposedTo::Nobody;
|
||||
|
||||
auto exposed_from_string = [](auto& string) -> Optional<ExposedTo> {
|
||||
if (string == "Window"sv)
|
||||
return ExposedTo::Window;
|
||||
if (string == "Worker"sv)
|
||||
return ExposedTo::AllWorkers;
|
||||
if (string == "DedicatedWorker"sv)
|
||||
return ExposedTo::DedicatedWorker;
|
||||
if (string == "SharedWorker"sv)
|
||||
return ExposedTo::SharedWorker;
|
||||
if (string == "ServiceWorker"sv)
|
||||
return ExposedTo::ServiceWorker;
|
||||
if (string == "AudioWorklet"sv)
|
||||
return ExposedTo::AudioWorklet;
|
||||
if (string == "LayoutWorklet"sv)
|
||||
return ExposedTo::LayoutWorklet;
|
||||
if (string == "PaintWorklet"sv)
|
||||
return ExposedTo::PaintWorklet;
|
||||
if (string == "Worklet"sv)
|
||||
return ExposedTo::Worklet;
|
||||
return {};
|
||||
};
|
||||
if (auto parsed_exposed = exposed_from_string(exposed_trimmed); parsed_exposed.has_value())
|
||||
return parsed_exposed.value();
|
||||
|
||||
if (exposed_trimmed[0] == '(') {
|
||||
ExposedTo whom = ExposedTo::Nobody;
|
||||
for (StringView candidate : exposed_trimmed.substring_view(1, exposed_trimmed.length() - 1).split_view(',')) {
|
||||
candidate = candidate.trim_whitespace();
|
||||
if (auto parsed_exposed = exposed_from_string(candidate); parsed_exposed.has_value()) {
|
||||
whom |= parsed_exposed.value();
|
||||
} else {
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute candidate {} in {} in {}", candidate, exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
}
|
||||
if (whom == ExposedTo::Nobody) {
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
return whom;
|
||||
}
|
||||
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/EnumBits.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/StringView.h>
|
||||
|
||||
namespace IDL {
|
||||
|
||||
enum class ExposedTo {
|
||||
Nobody = 0x0,
|
||||
DedicatedWorker = 0x1,
|
||||
SharedWorker = 0x2,
|
||||
ServiceWorker = 0x4,
|
||||
AudioWorklet = 0x8,
|
||||
Window = 0x10,
|
||||
Worklet = 0x40,
|
||||
PaintWorklet = 0x80,
|
||||
LayoutWorklet = 0x100,
|
||||
// FIXME: Categorize PaintWorklet and LayoutWorklet once we have them and know what they are.
|
||||
AllWorkers = DedicatedWorker | SharedWorker | ServiceWorker | AudioWorklet, // FIXME: Is "AudioWorklet" a Worker? We'll assume it is for now (here, and line below)
|
||||
All = AllWorkers | Window | Worklet,
|
||||
};
|
||||
AK_ENUM_BITWISE_OPERATORS(ExposedTo);
|
||||
|
||||
ErrorOr<ExposedTo> parse_exposure_set(StringView interface_name, StringView exposed);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2023, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
||||
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <LibIDL/Types.h>
|
||||
|
||||
namespace IDL {
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
static Module parse(ByteString filename, StringView contents, Context& context);
|
||||
|
||||
private:
|
||||
// https://webidl.spec.whatwg.org/#dfn-special-operation
|
||||
// A special operation is a getter, setter or deleter.
|
||||
enum class IsSpecialOperation {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
enum class IsStatic {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
Parser(ByteString filename, StringView contents, Context& context);
|
||||
|
||||
Module& parse();
|
||||
void assert_specific(char ch);
|
||||
void assert_string(StringView expected);
|
||||
void consume_whitespace();
|
||||
|
||||
HashMap<ByteString, ByteString> parse_extended_attributes();
|
||||
void parse_attribute(HashMap<ByteString, ByteString>& extended_attributes, Interface&, IsStatic is_static = IsStatic::No);
|
||||
void parse_interface(Interface&);
|
||||
void parse_partial_interface(HashMap<ByteString, ByteString> extended_attributes, Interface& parent);
|
||||
void parse_namespace(Interface&);
|
||||
void parse_partial_namespace(Interface& parent);
|
||||
void parse_non_interface_entities(bool allow_interface, Interface&);
|
||||
void parse_enumeration(HashMap<ByteString, ByteString>, Interface&);
|
||||
void parse_typedef(Interface&);
|
||||
void parse_callback_interface(HashMap<ByteString, ByteString> extended_attributes, Interface&);
|
||||
void parse_interface_mixin(Interface&);
|
||||
void parse_partial_interface_mixin(Interface&);
|
||||
void parse_dictionary(HashMap<ByteString, ByteString> extended_attributes, Interface&);
|
||||
void parse_callback_function(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_constructor(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_getter(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_setter(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_deleter(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_stringifier(HashMap<ByteString, ByteString>& extended_attributes, Interface&);
|
||||
void parse_iterable(Interface&);
|
||||
void parse_async_iterable(Interface&);
|
||||
void parse_setlike(Interface&, bool is_readonly);
|
||||
void parse_maplike(Interface&, bool is_readonly);
|
||||
Function parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface&, IsStatic is_static = IsStatic::No, IsSpecialOperation is_special_operation = IsSpecialOperation::No);
|
||||
Vector<Parameter> parse_parameters();
|
||||
NonnullRefPtr<Type const> parse_type();
|
||||
void parse_constant(Interface&);
|
||||
ByteString parse_identifier_until(AK::Function<bool(char)> predicate);
|
||||
ByteString parse_identifier_ending_with(auto... possible_terminating_characters);
|
||||
ByteString parse_identifier_ending_with_space();
|
||||
ByteString parse_identifier_ending_with_space_or(auto... possible_terminating_characters);
|
||||
|
||||
ByteString filename;
|
||||
StringView input;
|
||||
LineTrackingLexer lexer;
|
||||
Context& context;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <LibIDL/Types.h>
|
||||
|
||||
namespace IDL {
|
||||
|
||||
Interface& Context::add_interface(NonnullOwnPtr<Interface> interface)
|
||||
{
|
||||
auto& interface_ref = *interface;
|
||||
|
||||
if (!interface_ref.name.is_empty())
|
||||
interfaces.set(interface_ref.name, &interface_ref);
|
||||
|
||||
owned_interfaces.append(move(interface));
|
||||
return interface_ref;
|
||||
}
|
||||
|
||||
Interface& Context::add_mixin(NonnullOwnPtr<Interface> interface)
|
||||
{
|
||||
auto& interface_ref = *interface;
|
||||
mixins.set(interface_ref.name, &interface_ref);
|
||||
|
||||
for (auto& partial_mixin : partial_mixins) {
|
||||
if (partial_mixin->name == interface_ref.name)
|
||||
interface_ref.extend_with_partial_interface(*partial_mixin);
|
||||
}
|
||||
|
||||
owned_mixins.append(move(interface));
|
||||
return interface_ref;
|
||||
}
|
||||
|
||||
Module& Context::add_module(NonnullOwnPtr<Module> module)
|
||||
{
|
||||
auto& module_ref = *module;
|
||||
owned_modules.append(move(module));
|
||||
return module_ref;
|
||||
}
|
||||
|
||||
Module* Context::find_parsed_module(ByteString const& module_path)
|
||||
{
|
||||
for (auto const& module : owned_modules) {
|
||||
if (module->module_own_path == module_path)
|
||||
return module.ptr();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ParameterizedType const& Type::as_parameterized() const
|
||||
{
|
||||
return as<ParameterizedType const>(*this);
|
||||
}
|
||||
|
||||
ParameterizedType& Type::as_parameterized()
|
||||
{
|
||||
return as<ParameterizedType>(*this);
|
||||
}
|
||||
|
||||
UnionType const& Type::as_union() const
|
||||
{
|
||||
return as<UnionType const>(*this);
|
||||
}
|
||||
|
||||
UnionType& Type::as_union()
|
||||
{
|
||||
return as<UnionType>(*this);
|
||||
}
|
||||
|
||||
NonnullRefPtr<Type const> clone_type(Type const& type, bool nullable)
|
||||
{
|
||||
if (is<ParameterizedType>(type)) {
|
||||
Vector<NonnullRefPtr<Type const>> parameters;
|
||||
for (auto& parameter : type.as_parameterized().parameters())
|
||||
parameters.append(clone_type(parameter, parameter->is_nullable()));
|
||||
|
||||
return adopt_ref(*new ParameterizedType(type.name(), nullable, move(parameters)));
|
||||
}
|
||||
|
||||
if (is<UnionType>(type)) {
|
||||
Vector<NonnullRefPtr<Type const>> member_types;
|
||||
for (auto& member_type : type.as_union().member_types())
|
||||
member_types.append(clone_type(member_type, member_type->is_nullable()));
|
||||
|
||||
return adopt_ref(*new UnionType(type.name(), nullable, move(member_types)));
|
||||
}
|
||||
|
||||
return adopt_ref(*new Type(type.name(), nullable));
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
|
||||
bool Type::includes_nullable_type() const
|
||||
{
|
||||
// A type includes a nullable type if:
|
||||
// - the type is a nullable type, or
|
||||
if (is_nullable())
|
||||
return true;
|
||||
|
||||
// FIXME: - the type is an annotated type and its inner type is a nullable type, or
|
||||
|
||||
// - the type is a union type and its number of nullable member types is 1.
|
||||
if (is_union() && as_union().number_of_nullable_member_types() == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-includes-undefined
|
||||
bool Type::includes_undefined() const
|
||||
{
|
||||
// A type includes undefined if:
|
||||
// - the type is undefined, or
|
||||
if (is_undefined())
|
||||
return true;
|
||||
|
||||
// - the type is a nullable type and its inner type includes undefined, or
|
||||
// NOTE: We don't treat nullable as its own type, so this is handled by the other cases.
|
||||
|
||||
// FIXME: - the type is an annotated type and its inner type includes undefined, or
|
||||
|
||||
// - the type is a union type and one of its member types includes undefined.
|
||||
if (is_union())
|
||||
return as_union().member_types().contains([](auto& type) { return type->includes_undefined(); });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
bool Type::is_distinguishable_from(IDL::Interface const& interface, IDL::Type const& other) const
|
||||
{
|
||||
// 1. If one type includes a nullable type and the other type either includes a nullable type,
|
||||
// is a union type with flattened member types including a dictionary type, or is a dictionary type,
|
||||
// return false.
|
||||
if (includes_nullable_type() && (other.includes_nullable_type() || (other.is_union() && any_of(other.as_union().flattened_member_types(), [&interface](auto const& type) { return interface.context.dictionaries.contains(type->name()); })) || interface.context.dictionaries.contains(other.name())))
|
||||
return false;
|
||||
|
||||
// 2. If both types are either a union type or nullable union type, return true if each member type
|
||||
// of the one is distinguishable with each member type of the other, or false otherwise.
|
||||
if (is_union() && other.is_union()) {
|
||||
auto const& this_union = as_union();
|
||||
auto const& other_union = other.as_union();
|
||||
|
||||
for (auto& this_member_type : this_union.member_types()) {
|
||||
for (auto& other_member_type : other_union.member_types()) {
|
||||
if (!this_member_type->is_distinguishable_from(interface, other_member_type))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 3. If one type is a union type or nullable union type, return true if each member type of the union
|
||||
// type is distinguishable with the non-union type, or false otherwise.
|
||||
if (is_union() || other.is_union()) {
|
||||
auto const& the_union = is_union() ? as_union() : other.as_union();
|
||||
auto const& non_union = is_union() ? other : *this;
|
||||
|
||||
for (auto& member_type : the_union.member_types()) {
|
||||
if (!non_union.is_distinguishable_from(interface, member_type))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. Consider the two "innermost" types derived by taking each type’s inner type if it is an annotated type,
|
||||
// and then taking its inner type inner type if the result is a nullable type. If these two innermost types
|
||||
// appear or are in categories appearing in the following table and there is a “●” mark in the corresponding
|
||||
// entry or there is a letter in the corresponding entry and the designated additional requirement below the
|
||||
// table is satisfied, then return true. Otherwise return false.
|
||||
auto const& this_innermost_type = innermost_type();
|
||||
auto const& other_innermost_type = other.innermost_type();
|
||||
|
||||
enum class DistinguishabilityCategory {
|
||||
Undefined,
|
||||
Boolean,
|
||||
Numeric,
|
||||
BigInt,
|
||||
String,
|
||||
Object,
|
||||
Symbol,
|
||||
InterfaceLike,
|
||||
CallbackFunction,
|
||||
DictionaryLike,
|
||||
SequenceLike,
|
||||
__Count
|
||||
};
|
||||
|
||||
// See https://webidl.spec.whatwg.org/#distinguishable-table
|
||||
// clang-format off
|
||||
static constexpr bool table[to_underlying(DistinguishabilityCategory::__Count)][to_underlying(DistinguishabilityCategory::__Count)] {
|
||||
{false, true, true, true, true, true, true, true, true, false, true},
|
||||
{ true, false, true, true, true, true, true, true, true, true, true},
|
||||
{ true, true, false, true, true, true, true, true, true, true, true},
|
||||
{ true, true, true, false, true, true, true, true, true, true, true},
|
||||
{ true, true, true, true, false, true, true, true, true, true, true},
|
||||
{ true, true, true, true, true, false, true, false, false, false, false},
|
||||
{ true, true, true, true, true, true, false, true, true, true, true},
|
||||
{ true, true, true, true, true, false, true, false, true, true, true},
|
||||
{ true, true, true, true, true, false, true, true, false, false, true},
|
||||
{false, true, true, true, true, false, true, true, false, false, true},
|
||||
{ true, true, true, true, true, false, true, true, true, true, false},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
auto determine_category = [&interface](Type const& type) -> DistinguishabilityCategory {
|
||||
if (type.is_undefined())
|
||||
return DistinguishabilityCategory::Undefined;
|
||||
if (type.is_boolean())
|
||||
return DistinguishabilityCategory::Boolean;
|
||||
if (type.is_numeric())
|
||||
return DistinguishabilityCategory::Numeric;
|
||||
if (type.is_bigint())
|
||||
return DistinguishabilityCategory::BigInt;
|
||||
if (type.is_string())
|
||||
return DistinguishabilityCategory::String;
|
||||
if (type.is_object())
|
||||
return DistinguishabilityCategory::Object;
|
||||
if (type.is_symbol())
|
||||
return DistinguishabilityCategory::Symbol;
|
||||
// FIXME: InterfaceLike - see below
|
||||
// FIXME: CallbackFunction
|
||||
// DictionaryLike
|
||||
// * Dictionary Types
|
||||
// * Record Types
|
||||
// FIXME: * Callback Interface Types
|
||||
if (interface.context.dictionaries.contains(type.name()) || (type.is_parameterized() && type.name() == "record"sv))
|
||||
return DistinguishabilityCategory::DictionaryLike;
|
||||
// FIXME: Frozen array types are included in "sequence-like"
|
||||
if (type.is_sequence())
|
||||
return DistinguishabilityCategory::SequenceLike;
|
||||
|
||||
// FIXME: For lack of a better way of determining if something is an interface type, this just assumes anything we don't recognise is one.
|
||||
dbgln_if(IDL_DEBUG, "Unable to determine category for type named '{}', assuming it's an interface type.", type.name());
|
||||
return DistinguishabilityCategory::InterfaceLike;
|
||||
};
|
||||
|
||||
auto this_distinguishability = determine_category(this_innermost_type);
|
||||
auto other_distinguishability = determine_category(other_innermost_type);
|
||||
|
||||
if (this_distinguishability == DistinguishabilityCategory::InterfaceLike && other_distinguishability == DistinguishabilityCategory::InterfaceLike) {
|
||||
// The two identified interface-like types are not the same, and
|
||||
// FIXME: no single platform object implements both interface-like types.
|
||||
return this_innermost_type.name() != other_innermost_type.name();
|
||||
}
|
||||
|
||||
return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)];
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#buffer-types
|
||||
bool Type::is_buffer() const
|
||||
{
|
||||
// The buffer types are ArrayBuffer and SharedArrayBuffer.
|
||||
return m_name.is_one_of("ArrayBuffer", "SharedArrayBuffer");
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-typed-array-type
|
||||
bool Type::is_typed_array() const
|
||||
{
|
||||
// The typed array types are Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Uint8ClampedArray, BigInt64Array, BigUint64Array, Float16Array, Float32Array, and Float64Array.
|
||||
return m_name.is_one_of("Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array", "Float16Array", "Float32Array", "Float64Array");
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#buffer-view-types
|
||||
bool Type::is_buffer_view() const
|
||||
{
|
||||
// The buffer view types are DataView and the typed array types.
|
||||
return m_name == "DataView" || is_typed_array();
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-buffer-source-type
|
||||
bool Type::is_buffer_source() const
|
||||
{
|
||||
// The buffer source types are the buffer types and the buffer view types.
|
||||
return is_buffer() || is_buffer_view();
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-json-types
|
||||
bool Type::is_json(Context const& context) const
|
||||
{
|
||||
// The JSON types are:
|
||||
// - numeric types,
|
||||
if (is_numeric())
|
||||
return true;
|
||||
|
||||
// - boolean,
|
||||
if (is_boolean())
|
||||
return true;
|
||||
|
||||
// - string types,
|
||||
if (is_string() || context.enumerations.contains(m_name))
|
||||
return true;
|
||||
|
||||
// - object,
|
||||
if (is_object())
|
||||
return true;
|
||||
|
||||
// - nullable types whose inner type is a JSON type,
|
||||
// - annotated types whose inner type is a JSON type,
|
||||
// NOTE: We don't separate nullable and annotated into separate types.
|
||||
|
||||
// - union types whose member types are JSON types,
|
||||
if (is_union()) {
|
||||
auto const& union_type = as_union();
|
||||
|
||||
for (auto const& type : union_type.member_types()) {
|
||||
if (!type->is_json(context))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - typedefs whose type being given a new name is a JSON type,
|
||||
auto typedef_iterator = context.typedefs.find(m_name);
|
||||
if (typedef_iterator != context.typedefs.end())
|
||||
return typedef_iterator->value.type->is_json(context);
|
||||
|
||||
// - sequence types whose parameterized type is a JSON type,
|
||||
// - frozen array types whose parameterized type is a JSON type,
|
||||
// - records where all of their values are JSON types,
|
||||
if (is_parameterized() && m_name.is_one_of("sequence", "FrozenArray", "record")) {
|
||||
auto const& parameterized_type = as_parameterized();
|
||||
|
||||
for (auto const& parameter : parameterized_type.parameters()) {
|
||||
if (!parameter->is_json(context))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - dictionary types where the types of all members declared on the dictionary and all its inherited dictionaries are JSON types,
|
||||
auto dictionary_iterator = context.dictionaries.find(m_name);
|
||||
if (dictionary_iterator != context.dictionaries.end()) {
|
||||
auto const& dictionary = dictionary_iterator->value;
|
||||
for (auto const& member : dictionary.members) {
|
||||
if (!member.type->is_json(context))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - interface types that have a toJSON operation declared on themselves or one of their inherited interfaces.
|
||||
auto current_interface = context.interfaces.get(m_name);
|
||||
while (current_interface.has_value()) {
|
||||
auto to_json_iterator = current_interface.value()->functions.find_if([](IDL::Function const& function) {
|
||||
return function.name == "toJSON"sv;
|
||||
});
|
||||
|
||||
if (to_json_iterator != current_interface.value()->functions.end())
|
||||
return true;
|
||||
|
||||
if (current_interface.value()->parent_name.is_empty())
|
||||
break;
|
||||
|
||||
current_interface = context.interfaces.get(current_interface.value()->parent_name);
|
||||
VERIFY(current_interface.has_value());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EffectiveOverloadSet::remove_all_other_entries()
|
||||
{
|
||||
Vector<Item> new_items;
|
||||
new_items.append(m_items[*m_last_matching_item_index]);
|
||||
m_items = move(new_items);
|
||||
}
|
||||
|
||||
void Interface::dump()
|
||||
{
|
||||
dbgln("Attributes:");
|
||||
for (auto& attribute : attributes) {
|
||||
dbgln(" {}{}{}{} {}",
|
||||
attribute.inherit ? "inherit " : "",
|
||||
attribute.readonly ? "readonly " : "",
|
||||
attribute.type->name(),
|
||||
attribute.type->is_nullable() ? "?" : "",
|
||||
attribute.name);
|
||||
}
|
||||
|
||||
dbgln("Functions:");
|
||||
for (auto& function : functions) {
|
||||
dbgln(" {}{} {}",
|
||||
function.return_type->name(),
|
||||
function.return_type->is_nullable() ? "?" : "",
|
||||
function.name);
|
||||
for (auto& parameter : function.parameters) {
|
||||
dbgln(" {}{} {}",
|
||||
parameter.type->name(),
|
||||
parameter.type->is_nullable() ? "?" : "",
|
||||
parameter.name);
|
||||
}
|
||||
}
|
||||
|
||||
dbgln("Static Functions:");
|
||||
for (auto& function : static_functions) {
|
||||
dbgln(" static {}{} {}",
|
||||
function.return_type->name(),
|
||||
function.return_type->is_nullable() ? "?" : "",
|
||||
function.name);
|
||||
for (auto& parameter : function.parameters) {
|
||||
dbgln(" {}{} {}",
|
||||
parameter.type->name(),
|
||||
parameter.type->is_nullable() ? "?" : "",
|
||||
parameter.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::extend_with_partial_interface(Interface const& partial)
|
||||
{
|
||||
for (auto const& attribute : partial.attributes) {
|
||||
auto attribute_copy = attribute;
|
||||
attribute_copy.extended_attributes.update(partial.extended_attributes);
|
||||
attributes.append(move(attribute_copy));
|
||||
}
|
||||
|
||||
for (auto const& static_attribute : partial.static_attributes) {
|
||||
auto static_attribute_copy = static_attribute;
|
||||
static_attribute_copy.extended_attributes.update(partial.extended_attributes);
|
||||
static_attributes.append(move(static_attribute_copy));
|
||||
}
|
||||
|
||||
constants.extend(partial.constants);
|
||||
|
||||
for (auto const& function : partial.functions) {
|
||||
auto function_copy = function;
|
||||
function_copy.extended_attributes.update(partial.extended_attributes);
|
||||
functions.append(move(function_copy));
|
||||
}
|
||||
|
||||
for (auto const& static_function : partial.static_functions) {
|
||||
auto static_function_copy = static_function;
|
||||
static_function_copy.extended_attributes.update(partial.extended_attributes);
|
||||
static_functions.append(move(static_function_copy));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,522 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2023, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
|
||||
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/SourceGenerator.h>
|
||||
#include <AK/Tuple.h>
|
||||
|
||||
namespace IDL {
|
||||
|
||||
template<typename FunctionType>
|
||||
static size_t get_function_shortest_length(FunctionType& function)
|
||||
{
|
||||
size_t length = 0;
|
||||
for (auto& parameter : function.parameters) {
|
||||
if (!parameter.optional && !parameter.variadic)
|
||||
length++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
class Context;
|
||||
class ParameterizedType;
|
||||
class UnionType;
|
||||
class Interface;
|
||||
struct Module;
|
||||
|
||||
class Type : public RefCounted<Type> {
|
||||
public:
|
||||
enum class Kind {
|
||||
Plain, // AKA, Type.
|
||||
Parameterized,
|
||||
Union,
|
||||
};
|
||||
|
||||
Type(ByteString name, bool nullable)
|
||||
: m_kind(Kind::Plain)
|
||||
, m_name(move(name))
|
||||
, m_nullable(nullable)
|
||||
{
|
||||
}
|
||||
|
||||
Type(Kind kind, ByteString name, bool nullable)
|
||||
: m_kind(kind)
|
||||
, m_name(move(name))
|
||||
, m_nullable(nullable)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Type() = default;
|
||||
|
||||
Kind kind() const { return m_kind; }
|
||||
|
||||
bool is_plain() const { return m_kind == Kind::Plain; }
|
||||
|
||||
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();
|
||||
|
||||
ByteString const& name() const { return m_name; }
|
||||
|
||||
bool is_nullable() const { return m_nullable; }
|
||||
void set_nullable(bool value) { m_nullable = value; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
|
||||
bool includes_nullable_type() const;
|
||||
|
||||
// -> https://webidl.spec.whatwg.org/#dfn-includes-undefined
|
||||
bool includes_undefined() const;
|
||||
|
||||
Type const& innermost_type() const
|
||||
{
|
||||
// From step 4 of https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
// "Consider the two "innermost" types derived by taking each type’s inner type if it is an annotated type, and then taking its inner type inner type if the result is a nullable type."
|
||||
// FIXME: Annotated types.
|
||||
VERIFY(!is_union());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-any
|
||||
bool is_any() const { return is_plain() && m_name == "any"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-undefined
|
||||
bool is_undefined() const { return is_plain() && m_name == "undefined"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-boolean
|
||||
bool is_boolean() const { return is_plain() && m_name == "boolean"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-bigint
|
||||
bool is_bigint() const { return is_plain() && m_name == "bigint"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-object
|
||||
bool is_object() const { return is_plain() && m_name == "object"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-symbol
|
||||
bool is_symbol() const { return is_plain() && m_name == "symbol"; }
|
||||
|
||||
bool is_string() const { return is_plain() && m_name.is_one_of("ByteString", "DOMString", "Utf16DOMString", "USVString", "Utf16USVString"); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-integer-type
|
||||
bool is_integer() const { return is_plain() && 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_plain() && (is_integer() || is_floating_point()); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-primitive-type
|
||||
bool is_primitive() const { return is_plain() && (is_numeric() || is_boolean() || m_name == "bigint"); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#idl-sequence
|
||||
bool is_sequence() const { return is_parameterized() && m_name == "sequence"; }
|
||||
|
||||
bool is_buffer() const;
|
||||
|
||||
bool is_typed_array() const;
|
||||
|
||||
bool is_buffer_view() const;
|
||||
|
||||
bool is_buffer_source() const;
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
bool is_distinguishable_from(Interface const&, Type const& other) const;
|
||||
|
||||
bool is_json(Context const&) const;
|
||||
|
||||
bool is_restricted_floating_point() const { return m_name.is_one_of("float", "double"); }
|
||||
bool is_unrestricted_floating_point() const { return m_name.is_one_of("unrestricted float", "unrestricted double"); }
|
||||
bool is_floating_point() const { return is_restricted_floating_point() || is_unrestricted_floating_point(); }
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
ByteString m_name;
|
||||
bool m_nullable { false };
|
||||
};
|
||||
|
||||
struct Parameter {
|
||||
NonnullRefPtr<Type const> type;
|
||||
ByteString name;
|
||||
bool optional { false };
|
||||
Optional<ByteString> optional_default_value;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
bool variadic { false };
|
||||
};
|
||||
|
||||
struct Function {
|
||||
NonnullRefPtr<Type const> return_type;
|
||||
ByteString name;
|
||||
Vector<Parameter> parameters;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
LineTrackingLexer::Position source_position;
|
||||
size_t overload_index { 0 };
|
||||
bool is_overloaded { false };
|
||||
|
||||
size_t shortest_length() const { return get_function_shortest_length(*this); }
|
||||
};
|
||||
|
||||
struct Constructor {
|
||||
ByteString name;
|
||||
Vector<Parameter> parameters;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
size_t overload_index { 0 };
|
||||
bool is_overloaded { false };
|
||||
|
||||
size_t shortest_length() const { return get_function_shortest_length(*this); }
|
||||
};
|
||||
|
||||
struct Constant {
|
||||
NonnullRefPtr<Type const> type;
|
||||
ByteString name;
|
||||
ByteString value;
|
||||
};
|
||||
|
||||
struct Attribute {
|
||||
bool inherit { false };
|
||||
bool readonly { false };
|
||||
NonnullRefPtr<Type const> type;
|
||||
ByteString name;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
|
||||
// Added for convenience after parsing
|
||||
ByteString getter_callback_name;
|
||||
ByteString setter_callback_name;
|
||||
};
|
||||
|
||||
struct DictionaryMember {
|
||||
bool required { false };
|
||||
NonnullRefPtr<Type const> type;
|
||||
ByteString name;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
Optional<ByteString> default_value;
|
||||
};
|
||||
|
||||
struct Dictionary {
|
||||
ByteString parent_name;
|
||||
Vector<DictionaryMember> members;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
ByteString module_own_path;
|
||||
bool is_original_definition { true };
|
||||
};
|
||||
|
||||
struct Typedef {
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
NonnullRefPtr<Type const> type;
|
||||
};
|
||||
|
||||
struct Enumeration {
|
||||
ByteString module_own_path;
|
||||
OrderedHashTable<ByteString> values;
|
||||
OrderedHashMap<ByteString, ByteString> translated_cpp_names;
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
ByteString first_member;
|
||||
bool is_original_definition { true };
|
||||
};
|
||||
|
||||
struct CallbackFunction {
|
||||
NonnullRefPtr<Type const> return_type;
|
||||
Vector<Parameter> parameters;
|
||||
bool is_legacy_treat_non_object_as_null { false };
|
||||
};
|
||||
|
||||
class ParameterizedType : public Type {
|
||||
public:
|
||||
ParameterizedType(ByteString name, bool nullable, Vector<NonnullRefPtr<Type const>> parameters)
|
||||
: Type(Kind::Parameterized, move(name), nullable)
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ParameterizedType() override = default;
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> const& parameters() const { return m_parameters; }
|
||||
Vector<NonnullRefPtr<Type const>>& parameters() { return m_parameters; }
|
||||
|
||||
private:
|
||||
Vector<NonnullRefPtr<Type const>> m_parameters;
|
||||
};
|
||||
|
||||
static inline size_t get_shortest_function_length(Vector<Function&> const& overload_set)
|
||||
{
|
||||
size_t shortest_length = SIZE_MAX;
|
||||
for (auto const& function : overload_set)
|
||||
shortest_length = min(function.shortest_length(), shortest_length);
|
||||
return shortest_length;
|
||||
}
|
||||
|
||||
class Interface {
|
||||
AK_MAKE_NONCOPYABLE(Interface);
|
||||
AK_MAKE_NONMOVABLE(Interface);
|
||||
|
||||
public:
|
||||
explicit Interface(Context& context)
|
||||
: context(context)
|
||||
{
|
||||
}
|
||||
void dump();
|
||||
|
||||
ByteString name;
|
||||
ByteString parent_name;
|
||||
ByteString namespaced_name;
|
||||
ByteString implemented_name;
|
||||
|
||||
bool is_namespace { false };
|
||||
bool is_mixin { false };
|
||||
bool is_callback_interface { false };
|
||||
bool is_partial { false };
|
||||
|
||||
HashMap<ByteString, ByteString> extended_attributes;
|
||||
|
||||
Vector<Attribute> attributes;
|
||||
Vector<Attribute> static_attributes;
|
||||
Vector<Constant> constants;
|
||||
Vector<Constructor> constructors;
|
||||
Vector<Function> functions;
|
||||
Vector<Function> static_functions;
|
||||
bool has_stringifier { false };
|
||||
Optional<HashMap<ByteString, ByteString>> stringifier_extended_attributes;
|
||||
Optional<Attribute> stringifier_attribute;
|
||||
bool has_unscopable_member { false };
|
||||
|
||||
Optional<NonnullRefPtr<Type const>> value_iterator_type;
|
||||
Optional<size_t> value_iterator_offset;
|
||||
Optional<Tuple<NonnullRefPtr<Type const>, NonnullRefPtr<Type const>>> pair_iterator_types;
|
||||
Optional<size_t> pair_iterator_offset;
|
||||
|
||||
Optional<NonnullRefPtr<Type const>> async_value_iterator_type;
|
||||
Vector<Parameter> async_value_iterator_parameters;
|
||||
|
||||
Optional<NonnullRefPtr<Type const>> set_entry_type;
|
||||
bool is_set_readonly { false };
|
||||
|
||||
Optional<NonnullRefPtr<Type const>> map_key_type;
|
||||
Optional<NonnullRefPtr<Type const>> map_value_type;
|
||||
bool is_map_readonly { false };
|
||||
|
||||
Optional<Function> named_property_getter;
|
||||
Optional<Function> named_property_setter;
|
||||
|
||||
Optional<Function> indexed_property_getter;
|
||||
Optional<Function> indexed_property_setter;
|
||||
|
||||
Optional<Function> named_property_deleter;
|
||||
|
||||
Context& context;
|
||||
|
||||
OrderedHashTable<ByteString> own_dictionaries;
|
||||
OrderedHashTable<ByteString> own_enumerations;
|
||||
|
||||
// Added for convenience after parsing
|
||||
ByteString fully_qualified_name;
|
||||
ByteString constructor_class;
|
||||
ByteString prototype_class;
|
||||
ByteString prototype_base_class;
|
||||
ByteString namespace_class;
|
||||
ByteString global_mixin_class;
|
||||
|
||||
ByteString module_own_path;
|
||||
|
||||
OrderedHashMap<ByteString, Vector<Function&>> overload_sets;
|
||||
OrderedHashMap<ByteString, Vector<Function&>> static_overload_sets;
|
||||
OrderedHashMap<ByteString, Vector<Constructor&>> constructor_overload_sets;
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-support-indexed-properties
|
||||
bool supports_indexed_properties() const { return indexed_property_getter.has_value(); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-support-named-properties
|
||||
bool supports_named_properties() const { return named_property_getter.has_value(); }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-legacy-platform-object
|
||||
bool is_legacy_platform_object() const { return !extended_attributes.contains("Global") && (supports_indexed_properties() || supports_named_properties()); }
|
||||
|
||||
void extend_with_partial_interface(Interface const&);
|
||||
};
|
||||
|
||||
struct Module {
|
||||
Context* context { nullptr };
|
||||
ByteString module_own_path;
|
||||
OrderedHashTable<ByteString> own_dictionaries;
|
||||
OrderedHashTable<ByteString> own_enumerations;
|
||||
Optional<Interface&> interface;
|
||||
};
|
||||
|
||||
class UnionType : public Type {
|
||||
public:
|
||||
UnionType(ByteString name, bool nullable, Vector<NonnullRefPtr<Type const>> member_types)
|
||||
: Type(Kind::Union, move(name), nullable)
|
||||
, m_member_types(move(member_types))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~UnionType() override = default;
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> const& member_types() const { return m_member_types; }
|
||||
Vector<NonnullRefPtr<Type const>>& member_types() { return m_member_types; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-flattened-union-member-types
|
||||
Vector<NonnullRefPtr<Type const>> flattened_member_types() const
|
||||
{
|
||||
// 1. Let T be the union type.
|
||||
|
||||
// 2. Initialize S to ∅.
|
||||
Vector<NonnullRefPtr<Type const>> types;
|
||||
|
||||
// 3. For each member type U of T:
|
||||
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 (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.
|
||||
types.append(type);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Return S.
|
||||
return types;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-number-of-nullable-member-types
|
||||
size_t number_of_nullable_member_types() const
|
||||
{
|
||||
// 1. Let T be the union type.
|
||||
|
||||
// 2. Initialize n to 0.
|
||||
size_t num_nullable_member_types = 0;
|
||||
|
||||
// 3. For each member type U of T:
|
||||
for (auto& type : m_member_types) {
|
||||
// 1. If U is a nullable type, then:
|
||||
if (type->is_nullable()) {
|
||||
// 1. Set n to n + 1.
|
||||
++num_nullable_member_types;
|
||||
|
||||
// 2. Set U to be the inner type of U. (NOTE: Not necessary as nullable is stored with Type and not as a separate struct)
|
||||
}
|
||||
|
||||
// 2. If U is a union type, then:
|
||||
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.
|
||||
num_nullable_member_types += union_member_type.number_of_nullable_member_types();
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Return n.
|
||||
return num_nullable_member_types;
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<NonnullRefPtr<Type const>> m_member_types;
|
||||
};
|
||||
|
||||
NonnullRefPtr<Type const> clone_type(Type const&, bool nullable);
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Interface& add_interface(NonnullOwnPtr<Interface>);
|
||||
Interface& add_mixin(NonnullOwnPtr<Interface>);
|
||||
Module& add_module(NonnullOwnPtr<Module>);
|
||||
Module* find_parsed_module(ByteString const& module_path);
|
||||
void resolve();
|
||||
|
||||
HashMap<ByteString, Interface*> interfaces;
|
||||
Vector<NonnullOwnPtr<Interface>> owned_interfaces;
|
||||
HashMap<ByteString, Dictionary> dictionaries;
|
||||
HashMap<ByteString, Vector<Dictionary>> partial_dictionaries;
|
||||
HashMap<ByteString, Enumeration> enumerations;
|
||||
HashMap<ByteString, Typedef> typedefs;
|
||||
HashMap<ByteString, CallbackFunction> callback_functions;
|
||||
HashMap<ByteString, Interface*> mixins;
|
||||
|
||||
Vector<NonnullOwnPtr<Interface>> owned_mixins;
|
||||
Vector<NonnullOwnPtr<Interface>> partial_interfaces;
|
||||
Vector<NonnullOwnPtr<Interface>> partial_mixins;
|
||||
Vector<NonnullOwnPtr<Interface>> partial_namespaces;
|
||||
|
||||
HashMap<ByteString, HashTable<ByteString>> included_mixins;
|
||||
|
||||
Vector<NonnullOwnPtr<Module>> owned_modules;
|
||||
};
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-optionality-value
|
||||
enum class Optionality {
|
||||
Required,
|
||||
Optional,
|
||||
Variadic,
|
||||
};
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-effective-overload-set
|
||||
class EffectiveOverloadSet {
|
||||
public:
|
||||
struct Item {
|
||||
int callable_id;
|
||||
Vector<NonnullRefPtr<Type const>> types;
|
||||
Vector<Optionality> optionality_values;
|
||||
};
|
||||
|
||||
EffectiveOverloadSet(Vector<Item> items, size_t distinguishing_argument_index)
|
||||
: m_items(move(items))
|
||||
, m_distinguishing_argument_index(distinguishing_argument_index)
|
||||
{
|
||||
}
|
||||
|
||||
Vector<Item>& items() { return m_items; }
|
||||
Vector<Item> const& items() const { return m_items; }
|
||||
|
||||
Item const& only_item() const
|
||||
{
|
||||
VERIFY(m_items.size() == 1);
|
||||
return m_items[0];
|
||||
}
|
||||
|
||||
bool is_empty() const { return m_items.is_empty(); }
|
||||
size_t size() const { return m_items.size(); }
|
||||
|
||||
size_t distinguishing_argument_index() const { return m_distinguishing_argument_index; }
|
||||
|
||||
template<typename Matches>
|
||||
bool has_overload_with_matching_argument_at_index(size_t index, Matches matches)
|
||||
{
|
||||
for (size_t i = 0; i < m_items.size(); ++i) {
|
||||
auto const& item = m_items[i];
|
||||
if (matches(item.types[index], item.optionality_values[index])) {
|
||||
m_last_matching_item_index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_last_matching_item_index = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
void remove_all_other_entries();
|
||||
|
||||
private:
|
||||
// FIXME: This should be an "ordered set".
|
||||
Vector<Item> m_items;
|
||||
size_t m_distinguishing_argument_index { 0 };
|
||||
|
||||
Optional<size_t> m_last_matching_item_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1179,6 +1179,7 @@ set(SOURCES
|
|||
WebIDL/DOMException.cpp
|
||||
WebIDL/ObservableArray.cpp
|
||||
WebIDL/OverloadResolution.cpp
|
||||
WebIDL/OverloadTypes.cpp
|
||||
WebIDL/Promise.cpp
|
||||
WebIDL/QuotaExceededError.cpp
|
||||
WebIDL/Tracing.cpp
|
||||
|
|
@ -1254,7 +1255,7 @@ set(GENERATED_SOURCES
|
|||
|
||||
ladybird_lib(LibWeb web EXPLICIT_SYMBOL_EXPORT)
|
||||
|
||||
target_link_libraries(LibWeb PRIVATE LibCore LibCompress LibCrypto LibJS LibHTTP LibGfx LibIPC LibRegex LibSyntax LibTextCodec LibUnicode LibMedia LibWasm LibXML LibIDL LibURL LibTLS LibRequests LibGC LibSync LibThreading skia ${ANGLE_TARGETS} SDL3::SDL3 LibXml2::LibXml2)
|
||||
target_link_libraries(LibWeb PRIVATE LibCore LibCompress LibCrypto LibJS LibHTTP LibGfx LibIPC LibRegex LibSyntax LibTextCodec LibUnicode LibMedia LibWasm LibXML LibURL LibTLS LibRequests LibGC LibSync LibThreading skia ${ANGLE_TARGETS} SDL3::SDL3 LibXml2::LibXml2)
|
||||
|
||||
import_rust_crate(MANIFEST_PATH Rust/Cargo.toml CRATE_NAME libweb_rust FFI_HEADER RustFFI.h)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@
|
|||
namespace Web::WebIDL {
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-convert-ecmascript-to-idl-value
|
||||
static JS::Value convert_ecmascript_type_to_idl_value(JS::Value value, IDL::Type const&)
|
||||
static JS::Value convert_ecmascript_type_to_idl_value(JS::Value value, Type const&)
|
||||
{
|
||||
// FIXME: We have this code already in the code generator, in `generate_to_cpp()`, but how do we use it here?
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Match>
|
||||
static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOverloadSet& overloads, size_t argument_index, Match match)
|
||||
static bool has_overload_with_argument_type_or_subtype_matching(EffectiveOverloadSet& overloads, size_t argument_index, Match match)
|
||||
{
|
||||
// NOTE: This is to save some repetition.
|
||||
// Almost every sub-step of step 12 of the overload resolution algorithm matches overloads with an argument that is:
|
||||
|
|
@ -33,7 +33,7 @@ static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOv
|
|||
// So, this function lets you pass in the first check, and handles the others automatically.
|
||||
|
||||
return overloads.has_overload_with_matching_argument_at_index(argument_index,
|
||||
[match](IDL::Type const& type, auto) {
|
||||
[match](Type const& type, auto) {
|
||||
if (match(type))
|
||||
return true;
|
||||
|
||||
|
|
@ -55,9 +55,9 @@ static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOv
|
|||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#es-overloads
|
||||
JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads, ReadonlySpan<StringView> dictionary_types)
|
||||
JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, EffectiveOverloadSet& overloads, ReadonlySpan<StringView> dictionary_types)
|
||||
{
|
||||
auto is_dictionary = [&dictionary_types](IDL::Type const& type) {
|
||||
auto is_dictionary = [&dictionary_types](Type const& type) {
|
||||
return dictionary_types.contains_slow(type.name());
|
||||
};
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
auto const& optionality = item.optionality_values[i];
|
||||
|
||||
// 4. If optionality is “optional” and V is undefined, then:
|
||||
if (optionality == IDL::Optionality::Optional && value.is_undefined()) {
|
||||
if (optionality == Optionality::Optional && value.is_undefined()) {
|
||||
// FIXME: 1. If the argument at index i is declared with a default value, then append to values that default value.
|
||||
|
||||
// 2. Otherwise, append to values the special value “missing”.
|
||||
|
|
@ -125,7 +125,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
|
||||
// 2. If V is undefined, and there is an entry in S whose list of optionality values has “optional” at index i, then remove from S all other entries.
|
||||
if (value.is_undefined()
|
||||
&& overloads.has_overload_with_matching_argument_at_index(i, [](auto&, IDL::Optionality const& optionality) { return optionality == IDL::Optionality::Optional; })) {
|
||||
&& overloads.has_overload_with_matching_argument_at_index(i, [](auto&, Optionality const& optionality) { return optionality == Optionality::Optional; })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +138,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// NOTE: This is the one case we can't use `has_overload_with_argument_type_or_subtype_matching()` because we also need to look
|
||||
// for dictionary types in the flattened members.
|
||||
else if ((value.is_undefined() || value.is_null())
|
||||
&& overloads.has_overload_with_matching_argument_at_index(i, [&is_dictionary](IDL::Type const& type, auto) {
|
||||
&& overloads.has_overload_with_matching_argument_at_index(i, [&is_dictionary](Type const& type, auto) {
|
||||
if (type.is_nullable())
|
||||
return true;
|
||||
if (is_dictionary(type))
|
||||
|
|
@ -169,7 +169,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_object() && is<Bindings::PlatformObject>(value.as_object())
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [value](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [value](Type const& type) {
|
||||
// - an interface type that V implements
|
||||
if (static_cast<Bindings::PlatformObject const&>(value.as_object()).implements_interface(MUST(String::from_byte_string(type.name()))))
|
||||
return true;
|
||||
|
|
@ -191,7 +191,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_object() && is<JS::ArrayBuffer>(value.as_object())
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) {
|
||||
if (type.is_plain() && (type.name() == "ArrayBuffer" || type.name() == "BufferSource"))
|
||||
return true;
|
||||
if (type.is_object())
|
||||
|
|
@ -209,7 +209,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_object() && is<JS::DataView>(value.as_object())
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) {
|
||||
if (type.is_plain() && (type.name() == "DataView" || type.name() == "BufferSource" || type.name() == "ArrayBufferView"))
|
||||
return true;
|
||||
if (type.is_object())
|
||||
|
|
@ -227,7 +227,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_object() && value.as_object().is_typed_array()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&](Type const& type) {
|
||||
if (type.is_plain() && (type.name() == static_cast<JS::TypedArrayBase const&>(value.as_object()).element_name() || type.name() == "BufferSource" || type.name() == "ArrayBufferView"))
|
||||
return true;
|
||||
if (type.is_object())
|
||||
|
|
@ -245,7 +245,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_function()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) {
|
||||
// FIXME: - a callback function type
|
||||
if (type.is_object())
|
||||
return true;
|
||||
|
|
@ -266,7 +266,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// }
|
||||
// method is not undefined, then remove from S all other entries.
|
||||
else if (value.is_object()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&vm, &method, &value](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&vm, &method, &value](Type const& type) {
|
||||
// - a sequence type
|
||||
// FIXME: - a frozen array type
|
||||
// - a nullable version of any of the above types
|
||||
|
|
@ -297,7 +297,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_object()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&is_dictionary](IDL::Type const& type) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&is_dictionary](Type const& type) {
|
||||
if (is_dictionary(type))
|
||||
return true;
|
||||
// FIXME: a callback interface type
|
||||
|
|
@ -314,7 +314,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_boolean()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_boolean(); })) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_boolean(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_number()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_numeric(); })) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_numeric(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (value.is_bigint()
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_bigint(); })) {
|
||||
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_bigint(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +346,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - an annotated type whose inner type is one of the above types
|
||||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_string(); })) {
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_string(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +356,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - an annotated type whose inner type is one of the above types
|
||||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_numeric(); })) {
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_numeric(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +366,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - an annotated type whose inner type is one of the above types
|
||||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_boolean(); })) {
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_boolean(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
// - an annotated type whose inner type is one of the above types
|
||||
// - a union type, nullable union type, or annotated union type that has one of the above types in its flattened member types
|
||||
// then remove from S all other entries.
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { return type.is_bigint(); })) {
|
||||
else if (has_overload_with_argument_type_or_subtype_matching(overloads, i, [](Type const& type) { return type.is_bigint(); })) {
|
||||
overloads.remove_all_other_entries();
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +427,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
auto const& optionality = entry.optionality_values[i];
|
||||
|
||||
// 4. If optionality is “optional” and V is undefined, then:
|
||||
if (optionality == IDL::Optionality::Optional && value.is_undefined()) {
|
||||
if (optionality == Optionality::Optional && value.is_undefined()) {
|
||||
// FIXME: 1. If the argument at index i is declared with a default value, then append to values that default value.
|
||||
|
||||
// 2. Otherwise, append to values the special value “missing”.
|
||||
|
|
@ -450,7 +450,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
|
|||
}
|
||||
|
||||
// 2. Otherwise, if callable’s argument at index i is not variadic, then append to values the special value “missing”.
|
||||
else if (callable.optionality_values[i] != IDL::Optionality::Variadic) {
|
||||
else if (callable.optionality_values[i] != Optionality::Variadic) {
|
||||
values.empend(ResolvedOverload::Missing {});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <AK/Span.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibIDL/Types.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/Export.h>
|
||||
#include <LibWeb/WebIDL/OverloadTypes.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
|
|
@ -25,6 +25,6 @@ struct ResolvedOverload {
|
|||
};
|
||||
|
||||
// https://webidl.spec.whatwg.org/#es-overloads
|
||||
WEB_API JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM&, IDL::EffectiveOverloadSet&, ReadonlySpan<StringView> interface_dictionaries);
|
||||
WEB_API JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM&, EffectiveOverloadSet&, ReadonlySpan<StringView> interface_dictionaries);
|
||||
|
||||
}
|
||||
|
|
|
|||
106
Libraries/LibWeb/WebIDL/OverloadTypes.cpp
Normal file
106
Libraries/LibWeb/WebIDL/OverloadTypes.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Ladybird contributors
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibWeb/WebIDL/OverloadTypes.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
ParameterizedType const& Type::as_parameterized() const
|
||||
{
|
||||
return as<ParameterizedType const>(*this);
|
||||
}
|
||||
|
||||
ParameterizedType& Type::as_parameterized()
|
||||
{
|
||||
return as<ParameterizedType>(*this);
|
||||
}
|
||||
|
||||
UnionType const& Type::as_union() const
|
||||
{
|
||||
return as<UnionType const>(*this);
|
||||
}
|
||||
|
||||
UnionType& Type::as_union()
|
||||
{
|
||||
return as<UnionType>(*this);
|
||||
}
|
||||
|
||||
bool Type::includes_nullable_type() const
|
||||
{
|
||||
if (is_nullable())
|
||||
return true;
|
||||
|
||||
if (is_union() && as_union().number_of_nullable_member_types() == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::includes_undefined() const
|
||||
{
|
||||
if (is_undefined())
|
||||
return true;
|
||||
|
||||
if (is_union())
|
||||
return as_union().member_types().contains([](auto& type) { return type->includes_undefined(); });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::is_buffer() const
|
||||
{
|
||||
return m_name.is_one_of("ArrayBuffer", "SharedArrayBuffer");
|
||||
}
|
||||
|
||||
bool Type::is_typed_array() const
|
||||
{
|
||||
return m_name.is_one_of("Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray", "BigInt64Array", "BigUint64Array", "Float16Array", "Float32Array", "Float64Array");
|
||||
}
|
||||
|
||||
bool Type::is_buffer_view() const
|
||||
{
|
||||
return m_name == "DataView" || is_typed_array();
|
||||
}
|
||||
|
||||
bool Type::is_buffer_source() const
|
||||
{
|
||||
return is_buffer() || is_buffer_view();
|
||||
}
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> UnionType::flattened_member_types() const
|
||||
{
|
||||
Vector<NonnullRefPtr<Type const>> types;
|
||||
for (auto& type : m_member_types) {
|
||||
if (type->is_union())
|
||||
types.extend(type->as_union().flattened_member_types());
|
||||
else
|
||||
types.append(type);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
size_t UnionType::number_of_nullable_member_types() const
|
||||
{
|
||||
size_t num_nullable_member_types = 0;
|
||||
for (auto& type : m_member_types) {
|
||||
if (type->is_nullable())
|
||||
++num_nullable_member_types;
|
||||
|
||||
if (type->is_union())
|
||||
num_nullable_member_types += type->as_union().number_of_nullable_member_types();
|
||||
}
|
||||
return num_nullable_member_types;
|
||||
}
|
||||
|
||||
void EffectiveOverloadSet::remove_all_other_entries()
|
||||
{
|
||||
Vector<Item> new_items;
|
||||
new_items.append(m_items[*m_last_matching_item_index]);
|
||||
m_items = move(new_items);
|
||||
}
|
||||
|
||||
}
|
||||
178
Libraries/LibWeb/WebIDL/OverloadTypes.h
Normal file
178
Libraries/LibWeb/WebIDL/OverloadTypes.h
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2026, Ladybird contributors
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/RefCounted.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
namespace Web::WebIDL {
|
||||
|
||||
class ParameterizedType;
|
||||
class UnionType;
|
||||
|
||||
class Type : public RefCounted<Type> {
|
||||
public:
|
||||
enum class Kind {
|
||||
Plain,
|
||||
Parameterized,
|
||||
Union,
|
||||
};
|
||||
|
||||
Type(ByteString name, bool nullable)
|
||||
: m_kind(Kind::Plain)
|
||||
, m_name(move(name))
|
||||
, m_nullable(nullable)
|
||||
{
|
||||
}
|
||||
|
||||
Type(Kind kind, ByteString name, bool nullable)
|
||||
: m_kind(kind)
|
||||
, m_name(move(name))
|
||||
, m_nullable(nullable)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Type() = default;
|
||||
|
||||
bool is_plain() const { return m_kind == Kind::Plain; }
|
||||
|
||||
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();
|
||||
|
||||
ByteString const& name() const { return m_name; }
|
||||
|
||||
bool is_nullable() const { return m_nullable; }
|
||||
|
||||
bool includes_nullable_type() const;
|
||||
bool includes_undefined() const;
|
||||
|
||||
bool is_any() const { return is_plain() && m_name == "any"; }
|
||||
bool is_undefined() const { return is_plain() && m_name == "undefined"; }
|
||||
bool is_boolean() const { return is_plain() && m_name == "boolean"; }
|
||||
bool is_bigint() const { return is_plain() && m_name == "bigint"; }
|
||||
bool is_object() const { return is_plain() && m_name == "object"; }
|
||||
bool is_symbol() const { return is_plain() && m_name == "symbol"; }
|
||||
bool is_string() const { return is_plain() && m_name.is_one_of("ByteString", "DOMString", "Utf16DOMString", "USVString", "Utf16USVString"); }
|
||||
bool is_integer() const { return is_plain() && m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); }
|
||||
bool is_numeric() const { return is_plain() && (is_integer() || is_floating_point()); }
|
||||
bool is_sequence() const { return is_parameterized() && m_name == "sequence"; }
|
||||
|
||||
bool is_buffer() const;
|
||||
bool is_typed_array() const;
|
||||
bool is_buffer_view() const;
|
||||
bool is_buffer_source() const;
|
||||
|
||||
bool is_restricted_floating_point() const { return m_name.is_one_of("float", "double"); }
|
||||
bool is_unrestricted_floating_point() const { return m_name.is_one_of("unrestricted float", "unrestricted double"); }
|
||||
bool is_floating_point() const { return is_restricted_floating_point() || is_unrestricted_floating_point(); }
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
ByteString m_name;
|
||||
bool m_nullable { false };
|
||||
};
|
||||
|
||||
class ParameterizedType : public Type {
|
||||
public:
|
||||
ParameterizedType(ByteString name, bool nullable, Vector<NonnullRefPtr<Type const>> parameters)
|
||||
: Type(Kind::Parameterized, move(name), nullable)
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ParameterizedType() override = default;
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> const& parameters() const { return m_parameters; }
|
||||
|
||||
private:
|
||||
Vector<NonnullRefPtr<Type const>> m_parameters;
|
||||
};
|
||||
|
||||
class UnionType : public Type {
|
||||
public:
|
||||
UnionType(ByteString name, bool nullable, Vector<NonnullRefPtr<Type const>> member_types)
|
||||
: Type(Kind::Union, move(name), nullable)
|
||||
, m_member_types(move(member_types))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~UnionType() override = default;
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> const& member_types() const { return m_member_types; }
|
||||
|
||||
Vector<NonnullRefPtr<Type const>> flattened_member_types() const;
|
||||
size_t number_of_nullable_member_types() const;
|
||||
|
||||
private:
|
||||
Vector<NonnullRefPtr<Type const>> m_member_types;
|
||||
};
|
||||
|
||||
enum class Optionality {
|
||||
Required,
|
||||
Optional,
|
||||
Variadic,
|
||||
};
|
||||
|
||||
class EffectiveOverloadSet {
|
||||
public:
|
||||
struct Item {
|
||||
int callable_id;
|
||||
Vector<NonnullRefPtr<Type const>> types;
|
||||
Vector<Optionality> optionality_values;
|
||||
};
|
||||
|
||||
EffectiveOverloadSet(Vector<Item> items, size_t distinguishing_argument_index)
|
||||
: m_items(move(items))
|
||||
, m_distinguishing_argument_index(distinguishing_argument_index)
|
||||
{
|
||||
}
|
||||
|
||||
Vector<Item>& items() { return m_items; }
|
||||
Vector<Item> const& items() const { return m_items; }
|
||||
|
||||
Item const& only_item() const
|
||||
{
|
||||
VERIFY(m_items.size() == 1);
|
||||
return m_items[0];
|
||||
}
|
||||
|
||||
bool is_empty() const { return m_items.is_empty(); }
|
||||
size_t size() const { return m_items.size(); }
|
||||
|
||||
size_t distinguishing_argument_index() const { return m_distinguishing_argument_index; }
|
||||
|
||||
template<typename Matches>
|
||||
bool has_overload_with_matching_argument_at_index(size_t index, Matches matches)
|
||||
{
|
||||
for (size_t i = 0; i < m_items.size(); ++i) {
|
||||
auto const& item = m_items[i];
|
||||
if (matches(item.types[index], item.optionality_values[index])) {
|
||||
m_last_matching_item_index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
m_last_matching_item_index = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
void remove_all_other_entries();
|
||||
|
||||
private:
|
||||
Vector<Item> m_items;
|
||||
size_t m_distinguishing_argument_index { 0 };
|
||||
Optional<size_t> m_last_matching_item_index;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -44,7 +44,6 @@ def write_constructor_overload_arbiter(
|
|||
) -> None:
|
||||
includes.add("AK/Optional.h")
|
||||
includes.add("AK/Vector.h")
|
||||
includes.add("LibIDL/Types.h")
|
||||
includes.add("LibWeb/WebIDL/OverloadResolution.h")
|
||||
|
||||
out.write(
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ def write_overload_resolution_switch(
|
|||
dictionary_types: set[str] = set()
|
||||
out.write(
|
||||
f""" Optional<int> chosen_overload_callable_id;
|
||||
Optional<IDL::EffectiveOverloadSet> effective_overload_set;
|
||||
Optional<WebIDL::EffectiveOverloadSet> effective_overload_set;
|
||||
|
||||
switch (min({maximum_argument_count}, vm.argument_count())) {{
|
||||
"""
|
||||
|
|
@ -77,7 +77,7 @@ def write_overload_resolution_switch(
|
|||
)
|
||||
out.write(
|
||||
f""" case {argument_count}: {{
|
||||
Vector<IDL::EffectiveOverloadSet::Item> overloads;
|
||||
Vector<WebIDL::EffectiveOverloadSet::Item> overloads;
|
||||
overloads.ensure_capacity({len(effective_overload_set)});
|
||||
"""
|
||||
)
|
||||
|
|
@ -85,10 +85,10 @@ def write_overload_resolution_switch(
|
|||
dictionary_types.update(context.dictionary_type_names(*overload.types))
|
||||
types = ", ".join(constructor_for_idl_type(idl_type, context) for idl_type in overload.types)
|
||||
optionality_values = ", ".join(
|
||||
f"IDL::Optionality::{optionality.value}" for optionality in overload.optionality_values
|
||||
f"WebIDL::Optionality::{optionality.value}" for optionality in overload.optionality_values
|
||||
)
|
||||
out.write(
|
||||
f""" overloads.empend({overload.callable_id}, Vector<NonnullRefPtr<IDL::Type const>> {{ {types} }}, Vector<IDL::Optionality> {{ {optionality_values} }});
|
||||
f""" overloads.empend({overload.callable_id}, Vector<NonnullRefPtr<WebIDL::Type const>> {{ {types} }}, Vector<WebIDL::Optionality> {{ {optionality_values} }});
|
||||
"""
|
||||
)
|
||||
out.write(
|
||||
|
|
@ -130,7 +130,7 @@ def write_overload_arbiter(
|
|||
|
||||
includes.add("AK/Optional.h")
|
||||
includes.add("AK/Vector.h")
|
||||
includes.add("LibIDL/Types.h")
|
||||
includes.add("LibWeb/WebIDL/OverloadTypes.h")
|
||||
includes.add("LibWeb/WebIDL/OverloadResolution.h")
|
||||
includes.add("LibWeb/WebIDL/Tracing.h")
|
||||
|
||||
|
|
@ -284,18 +284,18 @@ def constructor_for_idl_type(idl_type: IDLType, context: GenerationContext) -> s
|
|||
if isinstance(idl_type, IDLParameterizedType):
|
||||
parameters = ", ".join(constructor_for_idl_type(parameter, context) for parameter in idl_type.parameters)
|
||||
return (
|
||||
f'make_ref_counted<IDL::ParameterizedType>("{idl_type.name}", {nullable}, '
|
||||
f"Vector<NonnullRefPtr<IDL::Type const>> {{ {parameters} }})"
|
||||
f'make_ref_counted<WebIDL::ParameterizedType>("{idl_type.name}", {nullable}, '
|
||||
f"Vector<NonnullRefPtr<WebIDL::Type const>> {{ {parameters} }})"
|
||||
)
|
||||
if isinstance(idl_type, IDLUnionType):
|
||||
member_types = ", ".join(
|
||||
constructor_for_idl_type(member_type, context) for member_type in idl_type.member_types
|
||||
)
|
||||
return (
|
||||
f'make_ref_counted<IDL::UnionType>("{idl_type.name}", {nullable}, '
|
||||
f"Vector<NonnullRefPtr<IDL::Type const>> {{ {member_types} }})"
|
||||
f'make_ref_counted<WebIDL::UnionType>("{idl_type.name}", {nullable}, '
|
||||
f"Vector<NonnullRefPtr<WebIDL::Type const>> {{ {member_types} }})"
|
||||
)
|
||||
return f'make_ref_counted<IDL::Type>("{idl_type.name}", {nullable})'
|
||||
return f'make_ref_counted<WebIDL::Type>("{idl_type.name}", {nullable})'
|
||||
|
||||
|
||||
# https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
|
|
|
|||
Loading…
Reference in a new issue