summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibIDL
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-09-07 15:27:08 +0100
committerAndreas Kling <kling@serenityos.org>2022-09-17 21:27:17 +0200
commit8b4cc07a54fac34c3cf19d365fc404892c8b9aad (patch)
treefe6f183a3492940051295ee726b16be7e26348d4 /Userland/Libraries/LibIDL
parent7c8ef79898606448cd41b69dd0a4bf291a111e56 (diff)
downloadserenity-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.cpp160
-rw-r--r--Userland/Libraries/LibIDL/Types.h82
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;
};