diff options
author | asynts <asynts@gmail.com> | 2020-10-11 19:57:53 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-10-12 19:40:49 +0200 |
commit | 0c5497829e77d176e74af7df3c6d3eddfdbb08d2 (patch) | |
tree | ad16d98561677e74c6015caa6da57c75aef42cb9 | |
parent | b99cebf63aef01030a50c63e6e8dcdab2e34b915 (diff) | |
download | serenity-0c5497829e77d176e74af7df3c6d3eddfdbb08d2.zip |
IPCCompiler: Use new SourceGenerator class.
-rw-r--r-- | DevTools/IPCCompiler/main.cpp | 413 |
1 files changed, 282 insertions, 131 deletions
diff --git a/DevTools/IPCCompiler/main.cpp b/DevTools/IPCCompiler/main.cpp index fc76c1ce2f..62e0b05ae7 100644 --- a/DevTools/IPCCompiler/main.cpp +++ b/DevTools/IPCCompiler/main.cpp @@ -27,6 +27,7 @@ #include <AK/Function.h> #include <AK/GenericLexer.h> #include <AK/HashMap.h> +#include <AK/SourceGenerator.h> #include <AK/StringBuilder.h> #include <LibCore/File.h> #include <ctype.h> @@ -64,13 +65,13 @@ struct Endpoint { int main(int argc, char** argv) { if (argc != 2) { - printf("usage: %s <IPC endpoint definition file>\n", argv[0]); + outln("usage: {} <IPC endpoint definition file>", argv[0]); return 0; } auto file = Core::File::construct(argv[1]); if (!file->open(Core::IODevice::ReadOnly)) { - fprintf(stderr, "Error: Cannot open %s: %s\n", argv[1], file->error_string()); + warnln("Error: Cannot open {}: {}", argv[1], file->error_string()); return 1; } @@ -81,7 +82,7 @@ int main(int argc, char** argv) auto assert_specific = [&](char ch) { if (lexer.peek() != ch) - warn() << "assert_specific: wanted '" << ch << "', but got '" << lexer.peek() << "' at index " << lexer.tell(); + warnln("assert_specific: wanted '{}', but got '{}' at index {}", ch, lexer.peek(), lexer.tell()); bool saw_expected = lexer.consume_specific(ch); ASSERT(saw_expected); }; @@ -199,38 +200,62 @@ int main(int argc, char** argv) while (lexer.tell() < file_contents.size()) parse_endpoint(); - out() << "#pragma once"; - out() << "#include <AK/MemoryStream.h>"; - out() << "#include <AK/OwnPtr.h>"; - out() << "#include <AK/URL.h>"; - out() << "#include <AK/Utf8View.h>"; - out() << "#include <LibGfx/Color.h>"; - out() << "#include <LibGfx/Rect.h>"; - out() << "#include <LibGfx/ShareableBitmap.h>"; - out() << "#include <LibIPC/Decoder.h>"; - out() << "#include <LibIPC/Dictionary.h>"; - out() << "#include <LibIPC/Encoder.h>"; - out() << "#include <LibIPC/Endpoint.h>"; - out() << "#include <LibIPC/Message.h>"; - out(); + SourceGenerator generator; + + generator.append(R"~~~( +#pragma once +#include <AK/MemoryStream.h> +#include <AK/OwnPtr.h> +#include <AK/URL.h> +#include <AK/Utf8View.h> +#include <LibGfx/Color.h> +#include <LibGfx/Rect.h> +#include <LibGfx/ShareableBitmap.h> +#include <LibIPC/Decoder.h> +#include <LibIPC/Dictionary.h> +#include <LibIPC/Encoder.h> +#include <LibIPC/Endpoint.h> +#include <LibIPC/Message.h> +)~~~"); for (auto& endpoint : endpoints) { - out() << "namespace Messages::" << endpoint.name << " {"; - out(); + SourceGenerator endpoint_generator { generator }; + + endpoint_generator.set("endpoint.name", endpoint.name); + endpoint_generator.set("endpoint.magic", String::number(endpoint.magic)); + + endpoint_generator.append(R"~~~( +namespace Messages::@endpoint.name@ { +)~~~"); HashMap<String, int> message_ids; - out() << "enum class MessageID : i32 {"; + endpoint_generator.append(R"~~~( +enum class MessageID : i32 { +)~~~"); for (auto& message : endpoint.messages) { + SourceGenerator message_generator { endpoint_generator }; + message_ids.set(message.name, message_ids.size() + 1); - out() << " " << message.name << " = " << message_ids.size() << ","; + message_generator.set("message.name", message.name); + message_generator.set("message.id", String::number(message_ids.size())); + + message_generator.append(R"~~~( + @message.name@ = @message.id@, +)~~~"); if (message.is_synchronous) { message_ids.set(message.response_name(), message_ids.size() + 1); - out() << " " << message.response_name() << " = " << message_ids.size() << ","; + message_generator.set("message.name", message.response_name()); + message_generator.set("message.id", String::number(message_ids.size())); + + message_generator.append(R"~~~( + @message.name@ = @message.id@, +)~~~"); } } - out() << "};"; - out(); + endpoint_generator.append(R"~~~( +}; +)~~~"); auto constructor_for_message = [&](const String& name, const Vector<Parameter>& parameters) { StringBuilder builder; @@ -267,31 +292,58 @@ int main(int argc, char** argv) }; auto do_message = [&](const String& name, const Vector<Parameter>& parameters, const String& response_type = {}) { - out() << "class " << name << " final : public IPC::Message {"; - out() << "public:"; + SourceGenerator message_generator { endpoint_generator }; + + message_generator.set("message.name", name); + message_generator.set("message.response_type", response_type); + message_generator.set("message.constructor", constructor_for_message(name, parameters)); + + message_generator.append(R"~~~( +class @message.name@ final : public IPC::Message { +public: +)~~~"); + if (!response_type.is_null()) - out() << " typedef class " << response_type << " ResponseType;"; - out() << " " << constructor_for_message(name, parameters); - out() << " virtual ~" << name << "() override {}"; - out() << " virtual i32 endpoint_magic() const override { return " << endpoint.magic << "; }"; - out() << " virtual i32 message_id() const override { return (int)MessageID::" << name << "; }"; - out() << " static i32 static_message_id() { return (int)MessageID::" << name << "; }"; - out() << " virtual const char* message_name() const override { return \"" << endpoint.name << "::" << name << "\"; }"; - out() << " static OwnPtr<" << name << "> decode(InputMemoryStream& stream, size_t& size_in_bytes)"; - out() << " {"; - - out() << " IPC::Decoder decoder(stream);"; + message_generator.append(R"~~~( + typedef class @message.response_type@ ResponseType; +)~~~"); + + message_generator.append(R"~~~( + @message.constructor@ + virtual ~@message.name@() override {} + + virtual i32 endpoint_magic() const override { return @endpoint.magic@; } + virtual i32 message_id() const override { return (int)MessageID::@message.name@; } + static i32 static_message_id() { return (int)MessageID::@message.name@; } + virtual const char* message_name() const override { return "@endpoint.name@::@message.name@"; } + + static OwnPtr<@message.name@> decode(InputMemoryStream& stream, size_t& size_in_bytes) + { + IPC::Decoder decoder {stream}; +)~~~"); for (auto& parameter : parameters) { - String initial_value = "{}"; + SourceGenerator parameter_generator { message_generator }; + + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); + if (parameter.type == "bool") - initial_value = "false"; - out() << " " << parameter.type << " " << parameter.name << " = " << initial_value << ";"; - out() << " if (!decoder.decode(" << parameter.name << "))"; - out() << " return nullptr;"; + parameter_generator.set("parameter.initial_value", "false"); + else + parameter_generator.set("parameter.initial_value", "{}"); + + parameter_generator.append(R"~~~( + @parameter.type@ @parameter.name@ = @parameter.initial_value@; + if (!decoder.decode(@parameter.name@)) + return nullptr; +)~~~"); + if (parameter.attributes.contains_slow("UTF8")) { - out() << " if (!Utf8View(" << parameter.name << ").validate())"; - out() << " return nullptr;"; + parameter_generator.append(R"~~~( + if (!Utf8View(@parameter.name@).validate()) + return nullptr; +)~~~"); } } @@ -302,29 +354,65 @@ int main(int argc, char** argv) if (i != parameters.size() - 1) builder.append(", "); } - out() << " size_in_bytes = stream.offset();"; - out() << " return make<" << name << ">(" << builder.to_string() << ");"; - out() << " }"; - out() << " virtual IPC::MessageBuffer encode() const override"; - out() << " {"; - out() << " IPC::MessageBuffer buffer;"; - out() << " IPC::Encoder stream(buffer);"; - out() << " stream << endpoint_magic();"; - out() << " stream << (int)MessageID::" << name << ";"; + + message_generator.set("message.constructor_call_parameters", builder.build()); + + message_generator.append(R"~~~( + size_in_bytes = stream.offset(); + return make<@message.name@>(@message.constructor_call_parameters@); + } +)~~~"); + + message_generator.append(R"~~~( + virtual IPC::MessageBuffer encode() const override + { + IPC::MessageBuffer buffer; + IPC::Encoder stream(buffer); + stream << endpoint_magic(); + stream << (int)MessageID::@message.name@; +)~~~"); + for (auto& parameter : parameters) { - out() << " stream << m_" << parameter.name << ";"; + SourceGenerator parameter_generator { message_generator }; + + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.append(R"~~~( + stream << m_@parameter.name@; +)~~~"); } - out() << " return buffer;"; - out() << " }"; + + message_generator.append(R"~~~( + return buffer; + } +)~~~"); + for (auto& parameter : parameters) { - out() << " const " << parameter.type << "& " << parameter.name << "() const { return m_" << parameter.name << "; }"; + SourceGenerator parameter_generator { message_generator }; + + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.append(R"~~~( + const @parameter.type@& @parameter.name@() const { return m_@parameter.name@; } +)~~~"); } - out() << "private:"; + + message_generator.append(R"~~~( +private: + )~~~"); + for (auto& parameter : parameters) { - out() << " " << parameter.type << " m_" << parameter.name << ";"; + SourceGenerator parameter_generator { message_generator }; + + parameter_generator.set("parameter.type", parameter.type); + parameter_generator.set("parameter.name", parameter.name); + parameter_generator.append(R"~~~( + @parameter.type@ m_@parameter.name@; +)~~~"); } - out() << "};"; - out(); + + message_generator.append(R"~~~( +}; + )~~~"); }; for (auto& message : endpoint.messages) { String response_name; @@ -334,94 +422,149 @@ int main(int argc, char** argv) } do_message(message.name, message.inputs, response_name); } - out() << "}"; - out(); - - out() << "class " << endpoint.name << "Endpoint : public IPC::Endpoint {"; - out() << "public:"; - out() << " " << endpoint.name << "Endpoint() {}"; - out() << " virtual ~" << endpoint.name << "Endpoint() override {}"; - out() << " static int static_magic() { return " << endpoint.magic << "; }"; - out() << " virtual int magic() const override { return " << endpoint.magic << "; }"; - out() << " static String static_name() { return \"" << endpoint.name << "\"; };"; - out() << " virtual String name() const override { return \"" << endpoint.name << "\"; };"; - out() << " static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer, size_t& size_in_bytes)"; - out() << " {"; - out() << " InputMemoryStream stream { buffer };"; - out() << " i32 message_endpoint_magic = 0;"; - out() << " stream >> message_endpoint_magic;"; - out() << " if (stream.handle_any_error()) {"; + + endpoint_generator.append(R"~~~( +} // namespace Messages::@endpoint.name@ + )~~~"); + + endpoint_generator.append(R"~~~( +class @endpoint.name@Endpoint : public IPC::Endpoint { +public: + @endpoint.name@Endpoint() { } + virtual ~@endpoint.name@Endpoint() override { } + + static int static_magic() { return @endpoint.magic@; } + virtual int magic() const override { return @endpoint.magic@; } + static String static_name() { return "@endpoint.name@"; } + virtual String name() const override { return "@endpoint.name@"; } + + static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer, size_t& size_in_bytes) + { + InputMemoryStream stream { buffer }; + i32 message_endpoint_magic = 0; + stream >> message_endpoint_magic; + if (stream.handle_any_error()) { +)~~~"); #ifdef GENERATE_DEBUG_CODE - out() << " dbg() << \"Failed to read message endpoint magic\";"; + endpoint_generator.append(R"~~~( + dbgln("Failed to read message endpoint magic"); +)~~~"); #endif - out() << " return nullptr;"; - out() << " }"; - out() << " if (message_endpoint_magic != " << endpoint.magic << ") {"; + endpoint_generator.append(R"~~~( + return nullptr; + } + + if (message_endpoint_magic != @endpoint.magic@) { +)~~~"); #ifdef GENERATE_DEBUG_CODE - out() << " dbg() << \"endpoint magic \" << message_endpoint_magic << \" != " << endpoint.magic << "\";"; + endpoint_generator.append(R"~~~( + dbgln("Endpoint magic number message_endpoint_magic != @endpoint.magic@"); +)~~~"); #endif - out() << " return nullptr;"; - out() << " }"; - out() << " i32 message_id = 0;"; - out() << " stream >> message_id;"; - out() << " if (stream.handle_any_error()) {"; + endpoint_generator.append(R"~~~( + return nullptr; + } + + i32 message_id = 0; + stream >> message_id; + if (stream.handle_any_error()) { +)~~~"); #ifdef GENERATE_DEBUG_CODE - out() << " dbg() << \"Failed to read message ID\";"; + endpoint_generator.append(R"~~~( + dbgln("Failed to read message ID"); +)~~~"); #endif - out() << " return nullptr;"; - out() << " }"; - out() << " OwnPtr<IPC::Message> message;"; - out() << " switch (message_id) {"; + endpoint_generator.append(R"~~~( + return nullptr; + } + + OwnPtr<IPC::Message> message; + switch (message_id) { +)~~~"); + for (auto& message : endpoint.messages) { auto do_decode_message = [&](const String& name) { - out() << " case (int)Messages::" << endpoint.name << "::MessageID::" << name << ":"; - out() << " message = Messages::" << endpoint.name << "::" << name << "::decode(stream, size_in_bytes);"; - out() << " break;"; + SourceGenerator message_generator { endpoint_generator }; + + message_generator.set("message.name", name); + + message_generator.append(R"~~~( + case (int)Messages::@endpoint.name@::MessageID::@message.name@: + message = Messages::@endpoint.name@::@message.name@::decode(stream, size_in_bytes); + break; +)~~~"); }; + do_decode_message(message.name); if (message.is_synchronous) do_decode_message(message.response_name()); } - out() << " default:"; + + endpoint_generator.append(R"~~~( + default: +)~~~"); #ifdef GENERATE_DEBUG_CODE - out() << " dbg() << \"Failed to decode " << endpoint.name << ".(\" << message_id << \")\";"; + endpoint_generator.append(R"~~~( + dbgln("Failed to decode @endpoint.name@.({})", message_id); +)~~~"); #endif - out() << " return nullptr;"; + endpoint_generator.append(R"~~~( + return nullptr; + } - out() << " }"; - out() << " if (stream.handle_any_error()) {"; + if (stream.handle_any_error()) { +)~~~"); #ifdef GENERATE_DEBUG_CODE - out() << " dbg() << \"Failed to read the message\";"; + endpoint_generator.append(R"~~~( + dbgln("Failed to read the message"); +)~~~"); #endif - out() << " return nullptr;"; - out() << " }"; - out() << " return message;"; - out() << " }"; - out(); - out() << " virtual OwnPtr<IPC::Message> handle(const IPC::Message& message) override"; - out() << " {"; - out() << " switch (message.message_id()) {"; + endpoint_generator.append(R"~~~( + return nullptr; + } + + return message; + } + + virtual OwnPtr<IPC::Message> handle(const IPC::Message& message) override + { + switch (message.message_id()) { +)~~~"); for (auto& message : endpoint.messages) { auto do_decode_message = [&](const String& name, bool returns_something) { - out() << " case (int)Messages::" << endpoint.name << "::MessageID::" << name << ":"; + SourceGenerator message_generator { endpoint_generator }; + + message_generator.set("message.name", name); + message_generator.append(R"~~~( + case (int)Messages::@endpoint.name@::MessageID::@message.name@: +)~~~"); if (returns_something) { - out() << " return handle(static_cast<const Messages::" << endpoint.name << "::" << name << "&>(message));"; + message_generator.append(R"~~~( + return handle(static_cast<const Messages::@endpoint.name@::@message.name@&>(message)); +)~~~"); } else { - out() << " handle(static_cast<const Messages::" << endpoint.name << "::" << name << "&>(message));"; - out() << " return nullptr;"; + message_generator.append(R"~~~( + handle(static_cast<const Messages::@endpoint.name@::@message.name@&>(message)); + return nullptr; +)~~~"); } }; do_decode_message(message.name, message.is_synchronous); if (message.is_synchronous) do_decode_message(message.response_name(), false); } - out() << " default:"; - out() << " return nullptr;"; - - out() << " }"; - out() << " }"; + endpoint_generator.append(R"~~~( + default: + return nullptr; + } + } +)~~~"); for (auto& message : endpoint.messages) { + SourceGenerator message_generator { endpoint_generator }; + + message_generator.set("message.name", message.name); + String return_type = "void"; if (message.is_synchronous) { StringBuilder builder; @@ -433,30 +576,38 @@ int main(int argc, char** argv) builder.append(">"); return_type = builder.to_string(); } - out() << " virtual " << return_type << " handle(const Messages::" << endpoint.name << "::" << message.name << "&) = 0;"; + message_generator.set("message.complex_return_type", return_type); + + message_generator.append(R"~~~( + virtual @message.complex_return_type@ handle(const Messages::@endpoint.name@::@message.name@&) = 0; +)~~~"); } - out() << "private:"; - out() << "};"; + endpoint_generator.append(R"~~~( +private: +}; +)~~~"); } + outln("{}", generator.generate()); + #ifdef DEBUG for (auto& endpoint : endpoints) { - warn() << "Endpoint: '" << endpoint.name << "' (magic: " << endpoint.magic << ")"; + warnln("Endpoint '{}' (magic: {})", endpoint.name, endpoint.magic); for (auto& message : endpoint.messages) { - warn() << " Message: '" << message.name << "'"; - warn() << " Sync: " << message.is_synchronous; - warn() << " Inputs:"; + warnln(" Message: '{}'", message.name); + warnln(" Sync: {}", message.is_synchronous); + warnln(" Inputs:"); for (auto& parameter : message.inputs) - warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; + warnln(" Parameter: {} ({})", parameter.name, parameter.type); if (message.inputs.is_empty()) - warn() << " (none)"; + warnln(" (none)"); if (message.is_synchronous) { - warn() << " Outputs:"; + warnln(" Outputs:"); for (auto& parameter : message.outputs) - warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; + warnln(" Parameter: {} ({})", parameter.name, parameter.type); if (message.outputs.is_empty()) - warn() << " (none)"; + warnln(" (none)"); } } } |