/* * Copyright (c) 2020-2021, 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 #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 { String name; SequenceStorageType sequence_storage_type; }; class ParameterizedType; class UnionType; class Type : public RefCounted { public: enum class Kind { Plain, // AKA, Type. Parameterized, Union, }; Type(String name, bool nullable) : m_kind(Kind::Plain) , m_name(move(name)) , m_nullable(nullable) { } Type(Kind kind, String 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(); 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; bool m_nullable { false }; }; struct Parameter { NonnullRefPtr type; String name; bool optional { false }; Optional optional_default_value; HashMap extended_attributes; bool variadic { false }; }; struct Function { NonnullRefPtr return_type; String 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 Constructor { String name; Vector parameters; size_t shortest_length() const { return get_function_shortest_length(*this); } }; struct Constant { NonnullRefPtr type; String name; String value; }; struct Attribute { bool inherit { false }; bool readonly { false }; NonnullRefPtr type; String name; HashMap extended_attributes; // Added for convenience after parsing String getter_callback_name; String setter_callback_name; }; struct DictionaryMember { bool required { false }; NonnullRefPtr type; String name; HashMap extended_attributes; Optional default_value; }; struct Dictionary { String parent_name; Vector members; }; struct Typedef { HashMap extended_attributes; NonnullRefPtr type; }; struct Enumeration { HashTable values; HashMap translated_cpp_names; String first_member; bool is_original_definition { true }; }; struct CallbackFunction { NonnullRefPtr return_type; Vector parameters; bool is_legacy_treat_non_object_as_null { false }; }; class Interface; class ParameterizedType : public Type { public: ParameterizedType(String name, bool nullable, NonnullRefPtrVector parameters) : Type(Kind::Parameterized, move(name), nullable) , m_parameters(move(parameters)) { } virtual ~ParameterizedType() override = default; void generate_sequence_from_iterable(SourceGenerator& generator, String const& cpp_name, String const& iterable_cpp_name, String const& iterator_method_cpp_name, IDL::Interface const&, size_t recursion_depth) const; NonnullRefPtrVector const& parameters() const { return m_parameters; } NonnullRefPtrVector& parameters() { return m_parameters; } private: NonnullRefPtrVector 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; String name; String parent_name; bool is_mixin { false }; HashMap extended_attributes; Vector 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 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 String fully_qualified_name; String constructor_class; String prototype_class; String prototype_base_class; HashMap> included_mixins; String module_own_path; HashTable required_imported_paths; Vector imported_modules; HashMap> overload_sets; HashMap> static_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(String name, bool nullable, NonnullRefPtrVector member_types) : Type(Kind::Union, move(name), nullable) , m_member_types(move(member_types)) { } virtual ~UnionType() override = default; NonnullRefPtrVector const& member_types() const { return m_member_types; } NonnullRefPtrVector& member_types() { return m_member_types; } // https://webidl.spec.whatwg.org/#dfn-flattened-union-member-types NonnullRefPtrVector flattened_member_types() const { // 1. Let T be the union type. // 2. Initialize S to ∅. NonnullRefPtrVector 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: NonnullRefPtrVector 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; NonnullRefPtrVector types; Vector optionality_values; }; EffectiveOverloadSet(Vector items) : m_items(move(items)) , m_argument_count(m_items.is_empty() ? 0 : m_items.first().types.size()) { } 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(); } int distinguishing_argument_index(); template bool has_overload_with_matching_argument_at_index(size_t index, Matches matches) { for (auto const& item : m_items) { if (matches(item.types[index], item.optionality_values[index])) { m_last_matching_item = &item; return true; } } m_last_matching_item = nullptr; return false; } void remove_all_other_entries(); private: // FIXME: This should be an "ordered set". Vector m_items; size_t m_argument_count; Item const* m_last_matching_item { nullptr }; }; }