/* * Copyright (c) 2020-2023, Andreas Kling * Copyright (c) 2021, Linus Groh * Copyright (c) 2021, Luke Wilde * Copyright (c) 2022, Ali Mohammad Pur * Copyright (c) 2022, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include namespace IDL { template 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; } enum class SequenceStorageType { Vector, // Used to safely store non-JS values MarkedVector, // Used to safely store JS::Value and anything that inherits JS::Cell, e.g. JS::Object }; struct CppType { ByteString name; SequenceStorageType sequence_storage_type; }; class ParameterizedType; class UnionType; class Interface; class Type : public RefCounted { 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", "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() || 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"; } // https://webidl.spec.whatwg.org/#dfn-distinguishable bool is_distinguishable_from(Interface const&, Type const& other) const; bool is_json(Interface 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; ByteString name; bool optional { false }; Optional optional_default_value; HashMap extended_attributes; bool variadic { false }; }; struct Function { NonnullRefPtr return_type; ByteString name; Vector parameters; HashMap 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 parameters; HashMap 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; ByteString name; ByteString value; }; struct Attribute { bool inherit { false }; bool readonly { false }; NonnullRefPtr type; ByteString name; HashMap extended_attributes; // Added for convenience after parsing ByteString getter_callback_name; ByteString setter_callback_name; }; struct DictionaryMember { bool required { false }; NonnullRefPtr type; ByteString name; HashMap extended_attributes; Optional default_value; }; struct Dictionary { ByteString parent_name; Vector members; }; struct Typedef { HashMap extended_attributes; NonnullRefPtr type; }; struct Enumeration { OrderedHashTable values; OrderedHashMap translated_cpp_names; HashMap extended_attributes; ByteString first_member; bool is_original_definition { true }; }; struct CallbackFunction { NonnullRefPtr return_type; Vector parameters; bool is_legacy_treat_non_object_as_null { false }; }; class ParameterizedType : public Type { public: ParameterizedType(ByteString name, bool nullable, Vector> parameters) : Type(Kind::Parameterized, move(name), nullable) , m_parameters(move(parameters)) { } virtual ~ParameterizedType() override = default; void generate_sequence_from_iterable(SourceGenerator& generator, ByteString const& cpp_name, ByteString const& iterable_cpp_name, ByteString const& iterator_method_cpp_name, IDL::Interface const&, size_t recursion_depth) const; Vector> const& parameters() const { return m_parameters; } Vector>& parameters() { return m_parameters; } private: Vector> m_parameters; }; static inline size_t get_shortest_function_length(Vector 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() = default; ByteString name; ByteString parent_name; ByteString namespaced_name; ByteString implemented_name; bool is_namespace { false }; bool is_mixin { false }; HashMap extended_attributes; Vector attributes; Vector static_attributes; Vector constants; Vector constructors; Vector functions; Vector static_functions; bool has_stringifier { false }; Optional stringifier_attribute; bool has_unscopable_member { false }; Optional> value_iterator_type; Optional, NonnullRefPtr>> pair_iterator_types; Optional> set_entry_type; bool is_set_readonly { false }; Optional named_property_getter; Optional named_property_setter; Optional indexed_property_getter; Optional indexed_property_setter; Optional named_property_deleter; HashMap dictionaries; HashMap enumerations; HashMap typedefs; HashMap mixins; HashMap callback_functions; // 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; HashMap> included_mixins; ByteString module_own_path; Vector imported_modules; HashMap> overload_sets; HashMap> static_overload_sets; HashMap> 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()); } bool will_generate_code() const { return !name.is_empty() || any_of(enumerations, [](auto& entry) { return entry.value.is_original_definition; }); } }; class UnionType : public Type { public: UnionType(ByteString name, bool nullable, Vector> member_types) : Type(Kind::Union, move(name), nullable) , m_member_types(move(member_types)) { } virtual ~UnionType() override = default; Vector> const& member_types() const { return m_member_types; } Vector>& member_types() { return m_member_types; } // https://webidl.spec.whatwg.org/#dfn-flattened-union-member-types Vector> flattened_member_types() const { // 1. Let T be the union type. // 2. Initialize S to ∅. Vector> 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> m_member_types; }; // 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> types; Vector optionality_values; }; EffectiveOverloadSet(Vector items, size_t distinguishing_argument_index) : m_items(move(items)) , m_distinguishing_argument_index(distinguishing_argument_index) { } Vector& items() { return m_items; } Vector 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 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 m_items; size_t m_distinguishing_argument_index { 0 }; Optional m_last_matching_item_index; }; }