From 3f7fdfa807293c0bf5255306b43344765e166681 Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Thu, 23 Mar 2023 16:41:16 +0000 Subject: [PATCH] LibIDL: Add Type::is_json which says if the type is convertible to JSON --- Userland/Libraries/LibIDL/Types.cpp | 107 ++++++++++++++++++++++++++++ Userland/Libraries/LibIDL/Types.h | 5 +- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibIDL/Types.cpp b/Userland/Libraries/LibIDL/Types.cpp index 599f5180c7..bc568b1ddf 100644 --- a/Userland/Libraries/LibIDL/Types.cpp +++ b/Userland/Libraries/LibIDL/Types.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Sam Atkins + * Copyright (c) 2023, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -186,6 +187,112 @@ bool Type::is_distinguishable_from(IDL::Type const& other) const return table[to_underlying(this_distinguishability)][to_underlying(other_distinguishability)]; } +// https://webidl.spec.whatwg.org/#dfn-json-types +bool Type::is_json(Interface const& interface) const +{ + // The JSON types are: + // - numeric types, + if (is_numeric()) + return true; + + // - boolean, + if (is_boolean()) + return true; + + // - string types, + if (is_string() || interface.enumerations.find(m_name) != interface.enumerations.end()) + return true; + + // - object, + if (is_object()) + return true; + + // - nullable types whose inner type is a JSON type, + // - annotated types whose inner type is a JSON type, + // NOTE: We don't separate nullable and annotated into separate types. + + // - union types whose member types are JSON types, + if (is_union()) { + auto const& union_type = as_union(); + + for (auto const& type : union_type.member_types()) { + if (!type->is_json(interface)) + return false; + } + + return true; + } + + // - typedefs whose type being given a new name is a JSON type, + auto typedef_iterator = interface.typedefs.find(m_name); + if (typedef_iterator != interface.typedefs.end()) + return typedef_iterator->value.type->is_json(interface); + + // - sequence types whose parameterized type is a JSON type, + // - frozen array types whose parameterized type is a JSON type, + // - records where all of their values are JSON types, + if (is_parameterized() && m_name.is_one_of("sequence", "FrozenArray", "record")) { + auto const& parameterized_type = as_parameterized(); + + for (auto const& parameter : parameterized_type.parameters()) { + if (!parameter->is_json(interface)) + return false; + } + + return true; + } + + // - dictionary types where the types of all members declared on the dictionary and all its inherited dictionaries are JSON types, + auto dictionary_iterator = interface.dictionaries.find(m_name); + if (dictionary_iterator != interface.dictionaries.end()) { + auto const& dictionary = dictionary_iterator->value; + for (auto const& member : dictionary.members) { + if (!member.type->is_json(interface)) + return false; + } + + return true; + } + + // - interface types that have a toJSON operation declared on themselves or one of their inherited interfaces. + Optional current_interface_for_to_json; + if (m_name == interface.name) { + current_interface_for_to_json = interface; + } else { + // NOTE: Interface types must have the IDL file of their interface imported. + // Though the type name may not refer to an interface, so we don't assert this here. + auto imported_interface_iterator = interface.imported_modules.find_if([this](IDL::Interface const& imported_interface) { + return imported_interface.name == m_name; + }); + + if (imported_interface_iterator != interface.imported_modules.end()) + current_interface_for_to_json = *imported_interface_iterator; + } + + while (current_interface_for_to_json.has_value()) { + auto to_json_iterator = current_interface_for_to_json->functions.find_if([](IDL::Function const& function) { + return function.name == "toJSON"sv; + }); + + if (to_json_iterator != current_interface_for_to_json->functions.end()) + return true; + + if (interface.parent_name.is_empty()) + break; + + auto imported_interface_iterator = interface.imported_modules.find_if([¤t_interface_for_to_json](IDL::Interface const& imported_interface) { + return imported_interface.name == current_interface_for_to_json->parent_name; + }); + + // Inherited interfaces must have their IDL files imported. + VERIFY(imported_interface_iterator != interface.imported_modules.end()); + + current_interface_for_to_json = *imported_interface_iterator; + } + + return false; +} + // https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index int EffectiveOverloadSet::distinguishing_argument_index() { diff --git a/Userland/Libraries/LibIDL/Types.h b/Userland/Libraries/LibIDL/Types.h index e76f21e30e..2a13e580cb 100644 --- a/Userland/Libraries/LibIDL/Types.h +++ b/Userland/Libraries/LibIDL/Types.h @@ -43,6 +43,7 @@ struct CppType { class ParameterizedType; class UnionType; +class Interface; class Type : public RefCounted { public: @@ -135,6 +136,8 @@ public: // https://webidl.spec.whatwg.org/#dfn-distinguishable bool is_distinguishable_from(Type const& other) const; + bool is_json(Interface const&) const; + private: Kind m_kind; DeprecatedString m_name; @@ -218,8 +221,6 @@ struct CallbackFunction { bool is_legacy_treat_non_object_as_null { false }; }; -class Interface; - class ParameterizedType : public Type { public: ParameterizedType(DeprecatedString name, bool nullable, Vector> parameters)