mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibIDL+WrapperGenerator: Implement Type::is_distinguishable_from()
As part of this, I've moved a couple of methods for checking for null/undefined from UnionType to Type, and filled in more of their steps. This now detects more, and so causes us to hit a `TODO()` which is too big for me to go after right now, so I've replaced that assertion with a log message.
This commit is contained in:
parent
7c8ef79898
commit
8b4cc07a54
Notes:
sideshowbarker
2024-07-17 06:53:45 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/8b4cc07a54 Pull-request: https://github.com/SerenityOS/serenity/pull/15170
3 changed files with 217 additions and 37 deletions
|
@ -1019,7 +1019,7 @@ static void generate_to_cpp(SourceGenerator& generator, ParameterType& parameter
|
|||
|
||||
// FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.
|
||||
if (union_type.includes_nullable_type()) {
|
||||
TODO();
|
||||
dbgln("FIXME: 2. If the union type includes a nullable type and V is null or undefined, then return the IDL value null.");
|
||||
} else if (dictionary_type) {
|
||||
// 4. If V is null or undefined, then
|
||||
// 4.1 If types includes a dictionary type, then return the result of converting V to that dictionary type.
|
||||
|
|
|
@ -28,4 +28,164 @@ UnionType& Type::as_union()
|
|||
return verify_cast<UnionType>(*this);
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
for (auto& type : as_union().member_types()) {
|
||||
if (type.includes_undefined())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
bool Type::is_distinguishable_from(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.
|
||||
// FIXME: "is a union type with flattened member types including a dictionary type, or is a dictionary type,"
|
||||
if (includes_nullable_type() && other.includes_nullable_type())
|
||||
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(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(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 = [](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
|
||||
// FIXME: 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("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) {
|
||||
// Two interface-likes are distinguishable if:
|
||||
// "The two identified interface-like types are not the same, and no single platform object
|
||||
// implements both interface-like types."
|
||||
// FIXME: Implement this.
|
||||
return false;
|
||||
}
|
||||
|
||||
return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -71,21 +71,7 @@ public:
|
|||
|
||||
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 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() || 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() || m_name.is_one_of("bigint", "boolean"); }
|
||||
bool is_plain() const { return m_kind == Kind::Plain; }
|
||||
|
||||
bool is_parameterized() const { return m_kind == Kind::Parameterized; }
|
||||
ParameterizedType const& as_parameterized() const;
|
||||
|
@ -95,6 +81,61 @@ public:
|
|||
UnionType const& as_union() const;
|
||||
UnionType& as_union();
|
||||
|
||||
String 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", "CSSOMString", "DOMString", "USVString"); }
|
||||
|
||||
// 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() || 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_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"; }
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-distinguishable
|
||||
bool is_distinguishable_from(Type const& other) const;
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
String m_name;
|
||||
|
@ -349,27 +390,6 @@ public:
|
|||
return num_nullable_member_types;
|
||||
}
|
||||
|
||||
// https://webidl.spec.whatwg.org/#dfn-includes-a-nullable-type
|
||||
bool includes_nullable_type() const
|
||||
{
|
||||
// -> the type is a union type and its number of nullable member types is 1.
|
||||
return number_of_nullable_member_types() == 1;
|
||||
}
|
||||
|
||||
// -> https://webidl.spec.whatwg.org/#dfn-includes-undefined
|
||||
bool includes_undefined() const
|
||||
{
|
||||
// -> the type is a union type and one of its member types includes undefined.
|
||||
for (auto& type : m_member_types) {
|
||||
if (type.is_union() && type.as_union().includes_undefined())
|
||||
return true;
|
||||
|
||||
if (type.name() == "undefined"sv)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
NonnullRefPtrVector<Type> m_member_types;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue