ladybird/Libraries/LibIDL/Types.h

474 lines
15 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) 2020-2023, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/ByteString.h>
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <AK/SourceGenerator.h>
#include <AK/StringBuilder.h>
#include <AK/Tuple.h>
#include <AK/TypeCasts.h>
namespace IDL {
template<typename FunctionType>
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<Type> {
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 types 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 const> type;
ByteString name;
bool optional { false };
Optional<ByteString> optional_default_value;
HashMap<ByteString, ByteString> extended_attributes;
bool variadic { false };
};
struct Function {
NonnullRefPtr<Type const> return_type;
ByteString name;
Vector<Parameter> parameters;
HashMap<ByteString, ByteString> 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<Parameter> parameters;
HashMap<ByteString, ByteString> 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 const> type;
ByteString name;
ByteString value;
};
struct Attribute {
bool inherit { false };
bool readonly { false };
NonnullRefPtr<Type const> type;
ByteString name;
HashMap<ByteString, ByteString> extended_attributes;
// Added for convenience after parsing
ByteString getter_callback_name;
ByteString setter_callback_name;
};
struct DictionaryMember {
bool required { false };
NonnullRefPtr<Type const> type;
ByteString name;
HashMap<ByteString, ByteString> extended_attributes;
Optional<ByteString> default_value;
};
struct Dictionary {
ByteString parent_name;
Vector<DictionaryMember> members;
};
2022-03-30 20:32:44 +00:00
struct Typedef {
HashMap<ByteString, ByteString> extended_attributes;
NonnullRefPtr<Type const> type;
2022-03-30 20:32:44 +00:00
};
struct Enumeration {
OrderedHashTable<ByteString> values;
OrderedHashMap<ByteString, ByteString> translated_cpp_names;
HashMap<ByteString, ByteString> extended_attributes;
ByteString first_member;
bool is_original_definition { true };
};
struct CallbackFunction {
NonnullRefPtr<Type const> return_type;
Vector<Parameter> parameters;
bool is_legacy_treat_non_object_as_null { false };
};
class ParameterizedType : public Type {
public:
ParameterizedType(ByteString name, bool nullable, Vector<NonnullRefPtr<Type const>> 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<NonnullRefPtr<Type const>> const& parameters() const { return m_parameters; }
Vector<NonnullRefPtr<Type const>>& parameters() { return m_parameters; }
private:
Vector<NonnullRefPtr<Type const>> m_parameters;
};
static inline size_t get_shortest_function_length(Vector<Function&> 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<ByteString, ByteString> extended_attributes;
Vector<Attribute> attributes;
Vector<Attribute> static_attributes;
Vector<Constant> constants;
Vector<Constructor> constructors;
Vector<Function> functions;
Vector<Function> static_functions;
bool has_stringifier { false };
Optional<ByteString> stringifier_attribute;
bool has_unscopable_member { false };
Optional<NonnullRefPtr<Type const>> value_iterator_type;
Optional<Tuple<NonnullRefPtr<Type const>, NonnullRefPtr<Type const>>> pair_iterator_types;
Optional<NonnullRefPtr<Type const>> set_entry_type;
bool is_set_readonly { false };
Optional<Function> named_property_getter;
Optional<Function> named_property_setter;
Optional<Function> indexed_property_getter;
Optional<Function> indexed_property_setter;
Optional<Function> named_property_deleter;
HashMap<ByteString, Dictionary> dictionaries;
HashMap<ByteString, Enumeration> enumerations;
HashMap<ByteString, Typedef> typedefs;
HashMap<ByteString, Interface*> mixins;
HashMap<ByteString, CallbackFunction> 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<ByteString, HashTable<ByteString>> included_mixins;
ByteString module_own_path;
Vector<Interface&> imported_modules;
HashMap<ByteString, Vector<Function&>> overload_sets;
HashMap<ByteString, Vector<Function&>> static_overload_sets;
HashMap<ByteString, Vector<Constructor&>> 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<NonnullRefPtr<Type const>> member_types)
: Type(Kind::Union, move(name), nullable)
, m_member_types(move(member_types))
{
}
virtual ~UnionType() override = default;
Vector<NonnullRefPtr<Type const>> const& member_types() const { return m_member_types; }
Vector<NonnullRefPtr<Type const>>& member_types() { return m_member_types; }
// https://webidl.spec.whatwg.org/#dfn-flattened-union-member-types
Vector<NonnullRefPtr<Type const>> flattened_member_types() const
{
// 1. Let T be the union type.
// 2. Initialize S to ∅.
Vector<NonnullRefPtr<Type const>> 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<NonnullRefPtr<Type const>> 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<NonnullRefPtr<Type const>> types;
Vector<Optionality> optionality_values;
};
EffectiveOverloadSet(Vector<Item> items, size_t distinguishing_argument_index)
: m_items(move(items))
, m_distinguishing_argument_index(distinguishing_argument_index)
{
}
Vector<Item>& items() { return m_items; }
Vector<Item> 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<typename Matches>
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<Item> m_items;
size_t m_distinguishing_argument_index { 0 };
Optional<size_t> m_last_matching_item_index;
};
}