diff options
author | Sam Atkins <atkinssj@serenityos.org> | 2022-09-07 15:27:08 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-09-17 21:27:17 +0200 |
commit | 8b4cc07a54fac34c3cf19d365fc404892c8b9aad (patch) | |
tree | fe6f183a3492940051295ee726b16be7e26348d4 /Userland/Libraries/LibIDL | |
parent | 7c8ef79898606448cd41b69dd0a4bf291a111e56 (diff) | |
download | serenity-8b4cc07a54fac34c3cf19d365fc404892c8b9aad.zip |
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.
Diffstat (limited to 'Userland/Libraries/LibIDL')
-rw-r--r-- | Userland/Libraries/LibIDL/Types.cpp | 160 | ||||
-rw-r--r-- | Userland/Libraries/LibIDL/Types.h | 82 |
2 files changed, 211 insertions, 31 deletions
diff --git a/Userland/Libraries/LibIDL/Types.cpp b/Userland/Libraries/LibIDL/Types.cpp index 0e8ff7160c..09df15d7d4 100644 --- a/Userland/Libraries/LibIDL/Types.cpp +++ b/Userland/Libraries/LibIDL/Types.cpp @@ -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)]; +} + } diff --git a/Userland/Libraries/LibIDL/Types.h b/Userland/Libraries/LibIDL/Types.h index 306b14f048..f800203c2a 100644 --- a/Userland/Libraries/LibIDL/Types.h +++ b/Userland/Libraries/LibIDL/Types.h @@ -71,29 +71,70 @@ public: 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(); + 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-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 m_name.is_one_of("byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", "unsigned long long"); } + 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_integer() || m_name.is_one_of("float", "unrestricted float", "double", "unrestricted double"); } + 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_numeric() || m_name.is_one_of("bigint", "boolean"); } + bool is_primitive() const { return is_plain() && (is_numeric() || is_boolean() || m_name == "bigint"); } - bool is_parameterized() const { return m_kind == Kind::Parameterized; } - ParameterizedType const& as_parameterized() const; - ParameterizedType& as_parameterized(); + // https://webidl.spec.whatwg.org/#idl-sequence + bool is_sequence() const { return is_parameterized() && m_name == "sequence"; } - bool is_union() const { return m_kind == Kind::Union; } - UnionType const& as_union() const; - UnionType& as_union(); + // https://webidl.spec.whatwg.org/#dfn-distinguishable + bool is_distinguishable_from(Type const& other) const; private: Kind m_kind; @@ -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; }; |