diff options
author | Hendiadyoin1 <leon2002.la@gmail.com> | 2022-02-22 19:24:30 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-28 23:08:08 +0200 |
commit | bd6927ecaba40485a77b8efc655aa26b4c7f0530 (patch) | |
tree | 84b331be51a7a8d64ca798adf9375131b9429472 /Meta/Lagom | |
parent | 50b6e74d33034a47f7d4f63b0f5604f03701576c (diff) | |
download | serenity-bd6927ecaba40485a77b8efc655aa26b4c7f0530.zip |
Meta: Refactor the IPC-compiler and port it to LibMain
This does a few things in total:
* Ports the IPC-compiler to LibMain
* Extract some compiler steps into separate functions
* Minify some appends to use appendln (or appendff in the case of
StringBuilder)
This reduces the clang-tidies maximum cognitive-complexity score for
this file from 325 to under 100.
Diffstat (limited to 'Meta/Lagom')
-rw-r--r-- | Meta/Lagom/Tools/CodeGenerators/IPCCompiler/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp | 878 |
2 files changed, 415 insertions, 465 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/CMakeLists.txt index c734d1c175..d3ebbddc62 100644 --- a/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/CMakeLists.txt @@ -2,4 +2,4 @@ set(SOURCES main.cpp ) -lagom_tool(IPCCompiler) +lagom_tool(IPCCompiler LIBS LagomMain) diff --git a/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp b/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp index ae4528cc7d..b93e9f9919 100644 --- a/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/IPCCompiler/main.cpp @@ -11,6 +11,7 @@ #include <AK/SourceGenerator.h> #include <AK/StringBuilder.h> #include <LibCore/File.h> +#include <LibMain/Main.h> #include <ctype.h> #include <stdio.h> @@ -65,7 +66,7 @@ static bool is_primitive_type(String const& type) return type.is_one_of("u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "bool", "double", "float", "int", "unsigned", "unsigned int"); } -static String message_name(String const& endpoint, String& message, bool is_response) +static String message_name(String const& endpoint, String const& message, bool is_response) { StringBuilder builder; builder.append("Messages::"); @@ -77,32 +78,20 @@ static String message_name(String const& endpoint, String& message, bool is_resp return builder.to_string(); } -int main(int argc, char** argv) +Vector<Endpoint> parse(ByteBuffer const& file_contents) { - if (argc != 2) { - outln("usage: {} <IPC endpoint definition file>", argv[0]); - return 0; - } - - auto file = Core::File::construct(argv[1]); - if (!file->open(Core::OpenMode::ReadOnly)) { - warnln("Error: Cannot open {}: {}", argv[1], file->error_string()); - return 1; - } - - auto file_contents = file->read_all(); GenericLexer lexer(file_contents); Vector<Endpoint> endpoints; - auto assert_specific = [&](char ch) { + auto assert_specific = [&lexer](char ch) { if (lexer.peek() != ch) warnln("assert_specific: wanted '{}', but got '{}' at index {}", ch, lexer.peek(), lexer.tell()); bool saw_expected = lexer.consume_specific(ch); VERIFY(saw_expected); }; - auto consume_whitespace = [&] { + auto consume_whitespace = [&lexer] { lexer.ignore_while([](char ch) { return isspace(ch); }); if (lexer.peek() == '/' && lexer.peek(1) == '/') lexer.ignore_until([](char ch) { return ch == '\n'; }); @@ -239,130 +228,77 @@ int main(int argc, char** argv) while (lexer.tell() < file_contents.size()) parse_endpoint(); - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.append("#pragma once\n"); - - // This must occur before LibIPC/Decoder.h - for (auto& endpoint : endpoints) { - for (auto& include : endpoint.includes) { - generator.append(include); - generator.append("\n"); - } - } - - generator.append(R"~~~(#include <AK/MemoryStream.h> -#include <AK/OwnPtr.h> -#include <AK/Result.h> -#include <AK/Utf8View.h> -#include <LibIPC/Connection.h> -#include <LibIPC/Decoder.h> -#include <LibIPC/Dictionary.h> -#include <LibIPC/Encoder.h> -#include <LibIPC/File.h> -#include <LibIPC/Message.h> -#include <LibIPC/Stub.h> - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdefaulted-function-deleted" -#endif -)~~~"); - - for (auto& endpoint : endpoints) { - auto endpoint_generator = generator.fork(); - - endpoint_generator.set("endpoint.name", endpoint.name); - endpoint_generator.set("endpoint.magic", String::number(endpoint.magic)); - - endpoint_generator.append(R"~~~( -namespace Messages::@endpoint.name@ { -)~~~"); + return endpoints; +} - HashMap<String, int> message_ids; +HashMap<String, int> build_message_ids_for_endpoint(SourceGenerator generator, Endpoint const& endpoint) +{ + HashMap<String, int> message_ids; - endpoint_generator.append(R"~~~( -enum class MessageID : i32 { -)~~~"); - for (auto& message : endpoint.messages) { - auto message_generator = endpoint_generator.fork(); + generator.appendln("\nenum class MessageID : i32 {"); + for (auto const& message : endpoint.messages) { - message_ids.set(message.name, message_ids.size() + 1); - message_generator.set("message.name", message.name); - message_generator.set("message.pascal_name", pascal_case(message.name)); - message_generator.set("message.id", String::number(message_ids.size())); + message_ids.set(message.name, message_ids.size() + 1); + generator.set("message.pascal_name", pascal_case(message.name)); + generator.set("message.id", String::number(message_ids.size())); - message_generator.append(R"~~~( - @message.pascal_name@ = @message.id@, -)~~~"); - if (message.is_synchronous) { - message_ids.set(message.response_name(), message_ids.size() + 1); - message_generator.set("message.name", message.response_name()); - message_generator.set("message.pascal_name", pascal_case(message.response_name())); - message_generator.set("message.id", String::number(message_ids.size())); + generator.appendln(" @message.pascal_name@ = @message.id@,"); + if (message.is_synchronous) { + message_ids.set(message.response_name(), message_ids.size() + 1); + generator.set("message.pascal_name", pascal_case(message.response_name())); + generator.set("message.id", String::number(message_ids.size())); - message_generator.append(R"~~~( - @message.pascal_name@ = @message.id@, -)~~~"); - } + generator.appendln(" @message.pascal_name@ = @message.id@,"); } - endpoint_generator.append(R"~~~( -}; -)~~~"); - - auto constructor_for_message = [&](const String& name, const Vector<Parameter>& parameters) { - StringBuilder builder; - builder.append(name); + } + generator.appendln("};"); + return message_ids; +} - if (parameters.is_empty()) { - builder.append("() {}"); - return builder.to_string(); - } +String constructor_for_message(String const& name, Vector<Parameter> const& parameters) +{ + StringBuilder builder; + builder.append(name); - builder.append('('); - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - builder.append(parameter.type); - builder.append(" "); - builder.append(parameter.name); - if (i != parameters.size() - 1) - builder.append(", "); - } - builder.append(") : "); - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - builder.append("m_"); - builder.append(parameter.name); - builder.append("(move("); - builder.append(parameter.name); - builder.append("))"); - if (i != parameters.size() - 1) - builder.append(", "); - } - builder.append(" {}"); - return builder.to_string(); - }; + if (parameters.is_empty()) { + builder.append("() {}"); + return builder.to_string(); + } + builder.append('('); + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + builder.appendff("{} {}", parameter.type, parameter.name); + if (i != parameters.size() - 1) + builder.append(", "); + } + builder.append(") : "); + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + builder.appendff("m_{}(move({}))", parameter.name, parameter.name); + if (i != parameters.size() - 1) + builder.append(", "); + } + builder.append(" {}"); + return builder.to_string(); +} - auto do_message = [&](const String& name, const Vector<Parameter>& parameters, const String& response_type = {}) { - auto message_generator = endpoint_generator.fork(); - auto pascal_name = pascal_case(name); - message_generator.set("message.name", name); - message_generator.set("message.pascal_name", pascal_name); - message_generator.set("message.response_type", response_type); - message_generator.set("message.constructor", constructor_for_message(pascal_name, parameters)); +void do_message(SourceGenerator message_generator, const String& name, const Vector<Parameter>& parameters, const String& response_type = {}) +{ + auto pascal_name = pascal_case(name); + message_generator.set("message.name", name); + message_generator.set("message.pascal_name", pascal_name); + message_generator.set("message.response_type", response_type); + message_generator.set("message.constructor", constructor_for_message(pascal_name, parameters)); - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( class @message.pascal_name@ final : public IPC::Message { -public: -)~~~"); +public:)~~~"); - if (!response_type.is_null()) - message_generator.append(R"~~~( - typedef class @message.response_type@ ResponseType; -)~~~"); + if (!response_type.is_null()) + message_generator.appendln(R"~~~( + typedef class @message.response_type@ ResponseType;)~~~"); - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( @message.pascal_name@(decltype(nullptr)) : m_ipc_message_valid(false) { } @message.pascal_name@(@message.pascal_name@ const&) = default; @message.pascal_name@(@message.pascal_name@&&) = default; @@ -377,52 +313,46 @@ public: static OwnPtr<@message.pascal_name@> decode(InputMemoryStream& stream, Core::Stream::LocalSocket& socket) { - IPC::Decoder decoder { stream, socket }; -)~~~"); + IPC::Decoder decoder { stream, socket };)~~~"); - for (auto& parameter : parameters) { - auto parameter_generator = message_generator.fork(); + for (auto const& parameter : parameters) { + auto parameter_generator = message_generator.fork(); - parameter_generator.set("parameter.type", parameter.type); - parameter_generator.set("parameter.name", parameter.name); + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); - if (parameter.type == "bool") - parameter_generator.set("parameter.initial_value", "false"); - else - parameter_generator.set("parameter.initial_value", "{}"); + if (parameter.type == "bool") + parameter_generator.set("parameter.initial_value", "false"); + else + parameter_generator.set("parameter.initial_value", "{}"); - parameter_generator.append(R"~~~( + parameter_generator.appendln(R"~~~( @parameter.type@ @parameter.name@ = @parameter.initial_value@; if (decoder.decode(@parameter.name@).is_error()) - return {}; -)~~~"); + return {};)~~~"); - if (parameter.attributes.contains_slow("UTF8")) { - parameter_generator.append(R"~~~( + if (parameter.attributes.contains_slow("UTF8")) { + parameter_generator.appendln(R"~~~( if (!Utf8View(@parameter.name@).validate()) - return {}; -)~~~"); - } - } + return {};)~~~"); + } + } - StringBuilder builder; - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - builder.append("move("); - builder.append(parameter.name); - builder.append(")"); - if (i != parameters.size() - 1) - builder.append(", "); - } + StringBuilder builder; + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + builder.appendff("move({})", parameter.name); + if (i != parameters.size() - 1) + builder.append(", "); + } - message_generator.set("message.constructor_call_parameters", builder.build()); + message_generator.set("message.constructor_call_parameters", builder.build()); - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( return make<@message.pascal_name@>(@message.constructor_call_parameters@); - } -)~~~"); + })~~~"); - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( virtual bool valid() const override { return m_ipc_message_valid; } virtual IPC::MessageBuffer encode() const override @@ -432,201 +362,192 @@ public: IPC::MessageBuffer buffer; IPC::Encoder stream(buffer); stream << endpoint_magic(); - stream << (int)MessageID::@message.pascal_name@; -)~~~"); + stream << (int)MessageID::@message.pascal_name@;)~~~"); - for (auto& parameter : parameters) { - auto parameter_generator = message_generator.fork(); + for (auto const& parameter : parameters) { + auto parameter_generator = message_generator.fork(); - parameter_generator.set("parameter.name", parameter.name); - parameter_generator.append(R"~~~( - stream << m_@parameter.name@; -)~~~"); - } + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.appendln(R"~~~( + stream << m_@parameter.name@;)~~~"); + } - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( return buffer; - } -)~~~"); + })~~~"); - for (auto& parameter : parameters) { - auto parameter_generator = message_generator.fork(); - parameter_generator.set("parameter.type", parameter.type); - parameter_generator.set("parameter.name", parameter.name); - parameter_generator.append(R"~~~( + for (auto const& parameter : parameters) { + auto parameter_generator = message_generator.fork(); + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.appendln(R"~~~( const @parameter.type@& @parameter.name@() const { return m_@parameter.name@; } - @parameter.type@ take_@parameter.name@() { return move(m_@parameter.name@); } -)~~~"); - } + @parameter.type@ take_@parameter.name@() { return move(m_@parameter.name@); })~~~"); + } - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( private: - bool m_ipc_message_valid { true }; - )~~~"); - - for (auto& parameter : parameters) { - auto parameter_generator = message_generator.fork(); - parameter_generator.set("parameter.type", parameter.type); - parameter_generator.set("parameter.name", parameter.name); - parameter_generator.append(R"~~~( - @parameter.type@ m_@parameter.name@ {}; -)~~~"); - } - - message_generator.append(R"~~~( -}; - )~~~"); - }; - for (auto& message : endpoint.messages) { - String response_name; - if (message.is_synchronous) { - response_name = message.response_name(); - do_message(response_name, message.outputs); - } - do_message(message.name, message.inputs, response_name); - } - - endpoint_generator.append(R"~~~( -} // namespace Messages::@endpoint.name@ - )~~~"); - - endpoint_generator.append(R"~~~( -template<typename LocalEndpoint, typename PeerEndpoint> -class @endpoint.name@Proxy { -public: - // Used to disambiguate the constructor call. - struct Tag { }; + bool m_ipc_message_valid { true };)~~~"); + + for (auto const& parameter : parameters) { + auto parameter_generator = message_generator.fork(); + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.appendln(R"~~~( + @parameter.type@ m_@parameter.name@ {};)~~~"); + } - @endpoint.name@Proxy(IPC::Connection<LocalEndpoint, PeerEndpoint>& connection, Tag) - : m_connection(connection) - { } -)~~~"); - - for (auto& message : endpoint.messages) { - auto message_generator = endpoint_generator.fork(); - - auto do_implement_proxy = [&](String const& name, Vector<Parameter> const& parameters, bool is_synchronous, bool is_try) { - String return_type = "void"; - if (is_synchronous) { - if (message.outputs.size() == 1) - return_type = message.outputs[0].type; - else if (!message.outputs.is_empty()) - return_type = message_name(endpoint.name, message.name, true); - } - String inner_return_type = return_type; - if (is_try) { - StringBuilder builder; - builder.append("Result<"); - builder.append(return_type); - builder.append(", IPC::ErrorCode>"); - return_type = builder.to_string(); - } - message_generator.set("message.name", message.name); - message_generator.set("message.pascal_name", pascal_case(message.name)); - message_generator.set("message.complex_return_type", return_type); - message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_"); - message_generator.set("try_prefix_maybe", is_try ? "try_" : ""); + message_generator.appendln("\n};"); +} - message_generator.set("handler_name", name); - message_generator.append(R"~~~( +void do_message_for_proxy(SourceGenerator message_generator, Endpoint const& endpoint, Message const& message) +{ + auto do_implement_proxy = [&](String const& name, Vector<Parameter> const& parameters, bool is_synchronous, bool is_try) { + String return_type = "void"; + if (is_synchronous) { + if (message.outputs.size() == 1) + return_type = message.outputs[0].type; + else if (!message.outputs.is_empty()) + return_type = message_name(endpoint.name, message.name, true); + } + String inner_return_type = return_type; + if (is_try) + return_type = String::formatted("IPC::IPCErrorOr<{}>", return_type); + + message_generator.set("message.name", message.name); + message_generator.set("message.pascal_name", pascal_case(message.name)); + message_generator.set("message.complex_return_type", return_type); + message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_"); + message_generator.set("try_prefix_maybe", is_try ? "try_" : ""); + + message_generator.set("handler_name", name); + message_generator.appendln(R"~~~( @message.complex_return_type@ @try_prefix_maybe@@async_prefix_maybe@@handler_name@()~~~"); - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - auto argument_generator = message_generator.fork(); - argument_generator.set("argument.type", parameter.type); - argument_generator.set("argument.name", parameter.name); - argument_generator.append("@argument.type@ @argument.name@"); - if (i != parameters.size() - 1) - argument_generator.append(", "); - } + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + auto argument_generator = message_generator.fork(); + argument_generator.set("argument.type", parameter.type); + argument_generator.set("argument.name", parameter.name); + argument_generator.append("@argument.type@ @argument.name@"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } - message_generator.append(") {"); + message_generator.append(") {"); - if (is_synchronous && !is_try) { - if (return_type != "void") { - message_generator.append(R"~~~( + if (is_synchronous && !is_try) { + if (return_type != "void") { + message_generator.append(R"~~~( return )~~~"); - if (message.outputs.size() != 1) - message_generator.append("move(*"); - } else { - message_generator.append(R"~~~( + if (message.outputs.size() != 1) + message_generator.append("move(*"); + } else { + message_generator.append(R"~~~( (void) )~~~"); - } + } - message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>("); - } else if (is_try) { - message_generator.append(R"~~~( + message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>("); + } else if (is_try) { + message_generator.append(R"~~~( auto result = m_connection.template send_sync_but_allow_failure<Messages::@endpoint.name@::@message.pascal_name@>()~~~"); - } else { - message_generator.append(R"~~~( + } else { + message_generator.append(R"~~~( // FIXME: Handle post_message failures. (void) m_connection.post_message(Messages::@endpoint.name@::@message.pascal_name@ { )~~~"); - } + } - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - auto argument_generator = message_generator.fork(); - argument_generator.set("argument.name", parameter.name); - if (is_primitive_type(parameters[i].type)) - argument_generator.append("@argument.name@"); - else - argument_generator.append("move(@argument.name@)"); - if (i != parameters.size() - 1) - argument_generator.append(", "); - } + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + auto argument_generator = message_generator.fork(); + argument_generator.set("argument.name", parameter.name); + if (is_primitive_type(parameters[i].type)) + argument_generator.append("@argument.name@"); + else + argument_generator.append("move(@argument.name@)"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } - if (is_synchronous && !is_try) { - if (return_type != "void") { - message_generator.append(")"); - } + if (is_synchronous && !is_try) { + if (return_type != "void") { + message_generator.append(")"); + } - if (message.outputs.size() == 1) { - message_generator.append("->take_"); - message_generator.append(message.outputs[0].name); - message_generator.append("()"); - } else - message_generator.append(")"); + if (message.outputs.size() == 1) { + message_generator.append("->take_"); + message_generator.append(message.outputs[0].name); + message_generator.append("()"); + } else + message_generator.append(")"); - message_generator.append(";"); - } else if (is_try) { - message_generator.append(R"~~~(); + message_generator.append(";"); + } else if (is_try) { + message_generator.append(R"~~~(); if (!result) - return IPC::ErrorCode::PeerDisconnected; -)~~~"); - if (inner_return_type != "void") { - message_generator.append(R"~~~( - return move(*result); -)~~~"); - } else { - message_generator.append(R"~~~( - return { }; -)~~~"); - } - } else { - message_generator.append(R"~~~( }); -)~~~"); - } + return IPC::ErrorCode::PeerDisconnected;)~~~"); + if (inner_return_type != "void") { + message_generator.appendln(R"~~~( + return move(*result);)~~~"); + } else { + message_generator.appendln(R"~~~( + return { };)~~~"); + } + } else { + message_generator.appendln(" });"); + } - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( + })~~~"); + }; + + do_implement_proxy(message.name, message.inputs, message.is_synchronous, false); + if (message.is_synchronous) { + do_implement_proxy(message.name, message.inputs, false, false); + do_implement_proxy(message.name, message.inputs, true, true); } -)~~~"); - }; +} - do_implement_proxy(message.name, message.inputs, message.is_synchronous, false); - if (message.is_synchronous) { - do_implement_proxy(message.name, message.inputs, false, false); - do_implement_proxy(message.name, message.inputs, true, true); - } +void build_endpoint(SourceGenerator generator, Endpoint const& endpoint) +{ + generator.set("endpoint.name", endpoint.name); + generator.set("endpoint.magic", String::number(endpoint.magic)); + + generator.appendln("\nnamespace Messages::@endpoint.name@ {"); + + HashMap<String, int> message_ids = build_message_ids_for_endpoint(generator.fork(), endpoint); + + for (auto const& message : endpoint.messages) { + String response_name; + if (message.is_synchronous) { + response_name = message.response_name(); + do_message(generator.fork(), response_name, message.outputs); } + do_message(generator.fork(), message.name, message.inputs, response_name); + } + + generator.appendln(R"~~~( +} // namespace Messages::@endpoint.name@ + +template<typename LocalEndpoint, typename PeerEndpoint> +class @endpoint.name@Proxy { +public: + // Used to disambiguate the constructor call. + struct Tag { }; + + @endpoint.name@Proxy(IPC::Connection<LocalEndpoint, PeerEndpoint>& connection, Tag) + : m_connection(connection) + { })~~~"); + + for (auto const& message : endpoint.messages) + do_message_for_proxy(generator.fork(), endpoint, message); - endpoint_generator.append(R"~~~( + generator.appendln(R"~~~( private: IPC::Connection<LocalEndpoint, PeerEndpoint>& m_connection; -}; -)~~~"); +};)~~~"); - endpoint_generator.append(R"~~~( + generator.appendln(R"~~~( template<typename LocalEndpoint, typename PeerEndpoint> class @endpoint.name@Proxy; class @endpoint.name@Stub; @@ -644,84 +565,72 @@ public: InputMemoryStream stream { buffer }; u32 message_endpoint_magic = 0; stream >> message_endpoint_magic; - if (stream.handle_any_error()) { -)~~~"); - if constexpr (GENERATE_DEBUG) { - endpoint_generator.append(R"~~~( - dbgln("Failed to read message endpoint magic"); -)~~~"); - } - endpoint_generator.append(R"~~~( + if (stream.handle_any_error()) {)~~~"); + if constexpr (GENERATE_DEBUG) { + generator.appendln(R"~~~( + dbgln(\"Failed to read message endpoint magic\"))~~~"); + } + generator.appendln(R"~~~( return {}; } - if (message_endpoint_magic != @endpoint.magic@) { -)~~~"); - if constexpr (GENERATE_DEBUG) { - endpoint_generator.append(R"~~~( - dbgln("@endpoint.name@: Endpoint magic number message_endpoint_magic != @endpoint.magic@, not my message! (the other endpoint may have handled it)"); -)~~~"); - } - endpoint_generator.append(R"~~~( + if (message_endpoint_magic != @endpoint.magic@) {)~~~"); + if constexpr (GENERATE_DEBUG) { + generator.appendln(R"~~~( + dbgln(\"@endpoint.name@: Endpoint magic number message_endpoint_magic != @endpoint.magic@, not my message! (the other endpoint may have handled it)\"))~~~"); + } + generator.appendln(R"~~~( return {}; } i32 message_id = 0; stream >> message_id; - if (stream.handle_any_error()) { -)~~~"); - if constexpr (GENERATE_DEBUG) { - endpoint_generator.append(R"~~~( - dbgln("Failed to read message ID"); -)~~~"); - } - endpoint_generator.append(R"~~~( + if (stream.handle_any_error()) {)~~~"); + if constexpr (GENERATE_DEBUG) { + generator.appendln(R"~~~( + dbgln(\"Failed to read message ID\"))~~~"); + } + generator.appendln(R"~~~( return {}; } OwnPtr<IPC::Message> message; - switch (message_id) { -)~~~"); + switch (message_id) {)~~~"); - for (auto& message : endpoint.messages) { - auto do_decode_message = [&](const String& name) { - auto message_generator = endpoint_generator.fork(); + for (auto const& message : endpoint.messages) { + auto do_decode_message = [&](const String& name) { + auto message_generator = generator.fork(); - message_generator.set("message.name", name); - message_generator.set("message.pascal_name", pascal_case(name)); + message_generator.set("message.name", name); + message_generator.set("message.pascal_name", pascal_case(name)); - message_generator.append(R"~~~( + message_generator.appendln(R"~~~( case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@: message = Messages::@endpoint.name@::@message.pascal_name@::decode(stream, socket); - break; -)~~~"); - }; + break;)~~~"); + }; - do_decode_message(message.name); - if (message.is_synchronous) - do_decode_message(message.response_name()); - } + do_decode_message(message.name); + if (message.is_synchronous) + do_decode_message(message.response_name()); + } - endpoint_generator.append(R"~~~( - default: -)~~~"); - if constexpr (GENERATE_DEBUG) { - endpoint_generator.append(R"~~~( - dbgln("Failed to decode @endpoint.name@.({})", message_id); -)~~~"); - } - endpoint_generator.append(R"~~~( + generator.appendln(R"~~~( + default:)~~~"); + if constexpr (GENERATE_DEBUG) { + generator.appendln(R"~~~( + dbgln(\"Failed to decode @endpoint.name@.({})\", message_id))~~~"); + } + generator.appendln(R"~~~( return {}; } - if (stream.handle_any_error()) { -)~~~"); - if constexpr (GENERATE_DEBUG) { - endpoint_generator.append(R"~~~( - dbgln("Failed to read the message"); -)~~~"); - } - endpoint_generator.append(R"~~~( + if (stream.handle_any_error()) {)~~~"); + if constexpr (GENERATE_DEBUG) { + generator.appendln(R"~~~( + dbgln(\"Failed to read the message\");)~~~"); + } + generator.appendln(R"~~~( return {}; } @@ -740,124 +649,164 @@ public: virtual OwnPtr<IPC::MessageBuffer> handle(const IPC::Message& message) override { - switch (message.message_id()) { -)~~~"); - for (auto& message : endpoint.messages) { - auto do_handle_message = [&](String const& name, Vector<Parameter> const& parameters, bool returns_something) { - auto message_generator = endpoint_generator.fork(); - - StringBuilder argument_generator; - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - argument_generator.append("request."); - argument_generator.append(parameter.name); - argument_generator.append("()"); - if (i != parameters.size() - 1) - argument_generator.append(", "); - } + switch (message.message_id()) {)~~~"); + for (auto const& message : endpoint.messages) { + auto do_handle_message = [&](String const& name, Vector<Parameter> const& parameters, bool returns_something) { + auto message_generator = generator.fork(); - message_generator.set("message.pascal_name", pascal_case(name)); - message_generator.set("message.response_type", pascal_case(message.response_name())); - message_generator.set("handler_name", name); - message_generator.set("arguments", argument_generator.to_string()); - message_generator.append(R"~~~( - case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@: { -)~~~"); - if (returns_something) { - if (message.outputs.is_empty()) { - message_generator.append(R"~~~( + StringBuilder argument_generator; + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + argument_generator.append("request."); + argument_generator.append(parameter.name); + argument_generator.append("()"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } + + message_generator.set("message.pascal_name", pascal_case(name)); + message_generator.set("message.response_type", pascal_case(message.response_name())); + message_generator.set("handler_name", name); + message_generator.set("arguments", argument_generator.to_string()); + message_generator.appendln(R"~~~( + case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@: {)~~~"); + if (returns_something) { + if (message.outputs.is_empty()) { + message_generator.appendln(R"~~~( [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); @handler_name@(@arguments@); auto response = Messages::@endpoint.name@::@message.response_type@ { }; - return make<IPC::MessageBuffer>(response.encode()); -)~~~"); - } else { - message_generator.append(R"~~~( + return make<IPC::MessageBuffer>(response.encode());)~~~"); + } else { + message_generator.appendln(R"~~~( [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); auto response = @handler_name@(@arguments@); if (!response.valid()) return {}; - return make<IPC::MessageBuffer>(response.encode()); -)~~~"); - } - } else { - message_generator.append(R"~~~( + return make<IPC::MessageBuffer>(response.encode());)~~~"); + } + } else { + message_generator.appendln(R"~~~( [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); @handler_name@(@arguments@); - return {}; -)~~~"); - } - message_generator.append(R"~~~( - } -)~~~"); - }; - do_handle_message(message.name, message.inputs, message.is_synchronous); - } - endpoint_generator.append(R"~~~( + return {};)~~~"); + } + message_generator.appendln(R"~~~( + })~~~"); + }; + do_handle_message(message.name, message.inputs, message.is_synchronous); + } + generator.appendln(R"~~~( default: return {}; } - } -)~~~"); + })~~~"); - for (auto& message : endpoint.messages) { - auto message_generator = endpoint_generator.fork(); + for (auto const& message : endpoint.messages) { + auto message_generator = generator.fork(); - auto do_handle_message_decl = [&](String const& name, Vector<Parameter> const& parameters, bool is_response) { - String return_type = "void"; - if (message.is_synchronous && !message.outputs.is_empty() && !is_response) - return_type = message_name(endpoint.name, message.name, true); - message_generator.set("message.complex_return_type", return_type); + auto do_handle_message_decl = [&](String const& name, Vector<Parameter> const& parameters, bool is_response) { + String return_type = "void"; + if (message.is_synchronous && !message.outputs.is_empty() && !is_response) + return_type = message_name(endpoint.name, message.name, true); + message_generator.set("message.complex_return_type", return_type); - message_generator.set("handler_name", name); - message_generator.append(R"~~~( + message_generator.set("handler_name", name); + message_generator.appendln(R"~~~( virtual @message.complex_return_type@ @handler_name@()~~~"); - auto make_argument_type = [](String const& type) { - StringBuilder builder; + auto make_argument_type = [](String const& type) { + StringBuilder builder; - bool const_ref = !is_primitive_type(type); + bool const_ref = !is_primitive_type(type); - builder.append(type); - if (const_ref) - builder.append(" const&"); + builder.append(type); + if (const_ref) + builder.append(" const&"); - return builder.to_string(); - }; + return builder.to_string(); + }; - for (size_t i = 0; i < parameters.size(); ++i) { - auto& parameter = parameters[i]; - auto argument_generator = message_generator.fork(); - argument_generator.set("argument.type", make_argument_type(parameter.type)); - argument_generator.set("argument.name", parameter.name); - argument_generator.append("[[maybe_unused]] @argument.type@ @argument.name@"); - if (i != parameters.size() - 1) - argument_generator.append(", "); - } + for (size_t i = 0; i < parameters.size(); ++i) { + auto const& parameter = parameters[i]; + auto argument_generator = message_generator.fork(); + argument_generator.set("argument.type", make_argument_type(parameter.type)); + argument_generator.set("argument.name", parameter.name); + argument_generator.append("[[maybe_unused]] @argument.type@ @argument.name@"); + if (i != parameters.size() - 1) + argument_generator.append(", "); + } - if (is_response) { - message_generator.append(R"~~~() { }; -)~~~"); - } else { - message_generator.append(R"~~~() = 0; -)~~~"); - } - }; + if (is_response) { + message_generator.append(") { };"); + } else { + message_generator.appendln(") = 0;"); + } + }; - do_handle_message_decl(message.name, message.inputs, false); - } + do_handle_message_decl(message.name, message.inputs, false); + } - endpoint_generator.append(R"~~~( + generator.appendln(R"~~~( private: }; #ifdef __clang__ #pragma clang diagnostic pop -#endif -)~~~"); +#endif)~~~"); +} + +void build(StringBuilder& builder, Vector<Endpoint> const& endpoints) +{ + SourceGenerator generator { builder }; + + generator.appendln("#pragma once"); + + // This must occur before LibIPC/Decoder.h + for (auto const& endpoint : endpoints) { + for (auto const& include : endpoint.includes) { + generator.appendln(include); + } + } + + generator.appendln(R"~~~(#include <AK/MemoryStream.h> +#include <AK/OwnPtr.h> +#include <AK/Result.h> +#include <AK/Utf8View.h> +#include <LibIPC/Connection.h> +#include <LibIPC/Decoder.h> +#include <LibIPC/Dictionary.h> +#include <LibIPC/Encoder.h> +#include <LibIPC/File.h> +#include <LibIPC/Message.h> +#include <LibIPC/Stub.h> + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdefaulted-function-deleted" +#endif)~~~"); + + for (auto const& endpoint : endpoints) + build_endpoint(generator.fork(), endpoint); +} + +ErrorOr<int> serenity_main(Main::Arguments arguments) +{ + if (arguments.argc != 2) { + outln("usage: {} <IPC endpoint definition file>", arguments.strings[0]); + return 1; } - outln("{}", generator.as_string_view()); + auto file = TRY(Core::File::open(arguments.strings[1], Core::OpenMode::ReadOnly)); + + auto file_contents = file->read_all(); + + auto endpoints = parse(file_contents); + + StringBuilder builder; + build(builder, endpoints); + + outln("{}", builder.string_view()); if constexpr (GENERATE_DEBUG) { for (auto& endpoint : endpoints) { @@ -880,4 +829,5 @@ private: } } } + return 0; } |