1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:17:35 +00:00

IPCCompiler: Use new SourceGenerator class.

This commit is contained in:
asynts 2020-10-11 19:57:53 +02:00 committed by Andreas Kling
parent b99cebf63a
commit 0c5497829e

View file

@ -27,6 +27,7 @@
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/GenericLexer.h> #include <AK/GenericLexer.h>
#include <AK/HashMap.h> #include <AK/HashMap.h>
#include <AK/SourceGenerator.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibCore/File.h> #include <LibCore/File.h>
#include <ctype.h> #include <ctype.h>
@ -64,13 +65,13 @@ struct Endpoint {
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
if (argc != 2) { if (argc != 2) {
printf("usage: %s <IPC endpoint definition file>\n", argv[0]); outln("usage: {} <IPC endpoint definition file>", argv[0]);
return 0; return 0;
} }
auto file = Core::File::construct(argv[1]); auto file = Core::File::construct(argv[1]);
if (!file->open(Core::IODevice::ReadOnly)) { 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; return 1;
} }
@ -81,7 +82,7 @@ int main(int argc, char** argv)
auto assert_specific = [&](char ch) { auto assert_specific = [&](char ch) {
if (lexer.peek() != 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); bool saw_expected = lexer.consume_specific(ch);
ASSERT(saw_expected); ASSERT(saw_expected);
}; };
@ -199,38 +200,62 @@ int main(int argc, char** argv)
while (lexer.tell() < file_contents.size()) while (lexer.tell() < file_contents.size())
parse_endpoint(); parse_endpoint();
out() << "#pragma once"; SourceGenerator generator;
out() << "#include <AK/MemoryStream.h>";
out() << "#include <AK/OwnPtr.h>"; generator.append(R"~~~(
out() << "#include <AK/URL.h>"; #pragma once
out() << "#include <AK/Utf8View.h>"; #include <AK/MemoryStream.h>
out() << "#include <LibGfx/Color.h>"; #include <AK/OwnPtr.h>
out() << "#include <LibGfx/Rect.h>"; #include <AK/URL.h>
out() << "#include <LibGfx/ShareableBitmap.h>"; #include <AK/Utf8View.h>
out() << "#include <LibIPC/Decoder.h>"; #include <LibGfx/Color.h>
out() << "#include <LibIPC/Dictionary.h>"; #include <LibGfx/Rect.h>
out() << "#include <LibIPC/Encoder.h>"; #include <LibGfx/ShareableBitmap.h>
out() << "#include <LibIPC/Endpoint.h>"; #include <LibIPC/Decoder.h>
out() << "#include <LibIPC/Message.h>"; #include <LibIPC/Dictionary.h>
out(); #include <LibIPC/Encoder.h>
#include <LibIPC/Endpoint.h>
#include <LibIPC/Message.h>
)~~~");
for (auto& endpoint : endpoints) { for (auto& endpoint : endpoints) {
out() << "namespace Messages::" << endpoint.name << " {"; SourceGenerator endpoint_generator { generator };
out();
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; HashMap<String, int> message_ids;
out() << "enum class MessageID : i32 {"; endpoint_generator.append(R"~~~(
enum class MessageID : i32 {
)~~~");
for (auto& message : endpoint.messages) { for (auto& message : endpoint.messages) {
SourceGenerator message_generator { endpoint_generator };
message_ids.set(message.name, message_ids.size() + 1); 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) { if (message.is_synchronous) {
message_ids.set(message.response_name(), message_ids.size() + 1); 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() << "};"; endpoint_generator.append(R"~~~(
out(); };
)~~~");
auto constructor_for_message = [&](const String& name, const Vector<Parameter>& parameters) { auto constructor_for_message = [&](const String& name, const Vector<Parameter>& parameters) {
StringBuilder builder; 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 = {}) { auto do_message = [&](const String& name, const Vector<Parameter>& parameters, const String& response_type = {}) {
out() << "class " << name << " final : public IPC::Message {"; SourceGenerator message_generator { endpoint_generator };
out() << "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.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())
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) { 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") if (parameter.type == "bool")
initial_value = "false"; parameter_generator.set("parameter.initial_value", "false");
out() << " " << parameter.type << " " << parameter.name << " = " << initial_value << ";"; else
out() << " if (!decoder.decode(" << parameter.name << "))"; parameter_generator.set("parameter.initial_value", "{}");
out() << " return nullptr;";
parameter_generator.append(R"~~~(
@parameter.type@ @parameter.name@ = @parameter.initial_value@;
if (!decoder.decode(@parameter.name@))
return nullptr;
)~~~");
if (parameter.attributes.contains_slow("UTF8")) { if (parameter.attributes.contains_slow("UTF8")) {
out() << " if (!Utf8View(" << parameter.name << ").validate())"; parameter_generator.append(R"~~~(
out() << " return nullptr;"; if (!Utf8View(@parameter.name@).validate())
return nullptr;
)~~~");
} }
} }
@ -302,29 +354,65 @@ int main(int argc, char** argv)
if (i != parameters.size() - 1) if (i != parameters.size() - 1)
builder.append(", "); builder.append(", ");
} }
out() << " size_in_bytes = stream.offset();";
out() << " return make<" << name << ">(" << builder.to_string() << ");"; message_generator.set("message.constructor_call_parameters", builder.build());
out() << " }";
out() << " virtual IPC::MessageBuffer encode() const override"; message_generator.append(R"~~~(
out() << " {"; size_in_bytes = stream.offset();
out() << " IPC::MessageBuffer buffer;"; return make<@message.name@>(@message.constructor_call_parameters@);
out() << " IPC::Encoder stream(buffer);"; }
out() << " stream << endpoint_magic();"; )~~~");
out() << " stream << (int)MessageID::" << name << ";";
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) { 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) { 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) { 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) { for (auto& message : endpoint.messages) {
String response_name; String response_name;
@ -334,94 +422,149 @@ int main(int argc, char** argv)
} }
do_message(message.name, message.inputs, response_name); do_message(message.name, message.inputs, response_name);
} }
out() << "}";
out();
out() << "class " << endpoint.name << "Endpoint : public IPC::Endpoint {"; endpoint_generator.append(R"~~~(
out() << "public:"; } // namespace Messages::@endpoint.name@
out() << " " << endpoint.name << "Endpoint() {}"; )~~~");
out() << " virtual ~" << endpoint.name << "Endpoint() override {}";
out() << " static int static_magic() { return " << endpoint.magic << "; }"; endpoint_generator.append(R"~~~(
out() << " virtual int magic() const override { return " << endpoint.magic << "; }"; class @endpoint.name@Endpoint : public IPC::Endpoint {
out() << " static String static_name() { return \"" << endpoint.name << "\"; };"; public:
out() << " virtual String name() const override { return \"" << endpoint.name << "\"; };"; @endpoint.name@Endpoint() { }
out() << " static OwnPtr<IPC::Message> decode_message(const ByteBuffer& buffer, size_t& size_in_bytes)"; virtual ~@endpoint.name@Endpoint() override { }
out() << " {";
out() << " InputMemoryStream stream { buffer };"; static int static_magic() { return @endpoint.magic@; }
out() << " i32 message_endpoint_magic = 0;"; virtual int magic() const override { return @endpoint.magic@; }
out() << " stream >> message_endpoint_magic;"; static String static_name() { return "@endpoint.name@"; }
out() << " if (stream.handle_any_error()) {"; 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 #ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to read message endpoint magic\";"; endpoint_generator.append(R"~~~(
dbgln("Failed to read message endpoint magic");
)~~~");
#endif #endif
out() << " return nullptr;"; endpoint_generator.append(R"~~~(
out() << " }"; return nullptr;
out() << " if (message_endpoint_magic != " << endpoint.magic << ") {"; }
if (message_endpoint_magic != @endpoint.magic@) {
)~~~");
#ifdef GENERATE_DEBUG_CODE #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 #endif
out() << " return nullptr;"; endpoint_generator.append(R"~~~(
out() << " }"; return nullptr;
out() << " i32 message_id = 0;"; }
out() << " stream >> message_id;";
out() << " if (stream.handle_any_error()) {"; i32 message_id = 0;
stream >> message_id;
if (stream.handle_any_error()) {
)~~~");
#ifdef GENERATE_DEBUG_CODE #ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to read message ID\";"; endpoint_generator.append(R"~~~(
dbgln("Failed to read message ID");
)~~~");
#endif #endif
out() << " return nullptr;"; endpoint_generator.append(R"~~~(
out() << " }"; return nullptr;
out() << " OwnPtr<IPC::Message> message;"; }
out() << " switch (message_id) {";
OwnPtr<IPC::Message> message;
switch (message_id) {
)~~~");
for (auto& message : endpoint.messages) { for (auto& message : endpoint.messages) {
auto do_decode_message = [&](const String& name) { auto do_decode_message = [&](const String& name) {
out() << " case (int)Messages::" << endpoint.name << "::MessageID::" << name << ":"; SourceGenerator message_generator { endpoint_generator };
out() << " message = Messages::" << endpoint.name << "::" << name << "::decode(stream, size_in_bytes);";
out() << " break;"; 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); do_decode_message(message.name);
if (message.is_synchronous) if (message.is_synchronous)
do_decode_message(message.response_name()); do_decode_message(message.response_name());
} }
out() << " default:";
#ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to decode " << endpoint.name << ".(\" << message_id << \")\";";
#endif
out() << " return nullptr;";
out() << " }"; endpoint_generator.append(R"~~~(
out() << " if (stream.handle_any_error()) {"; default:
)~~~");
#ifdef GENERATE_DEBUG_CODE #ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to read the message\";"; endpoint_generator.append(R"~~~(
dbgln("Failed to decode @endpoint.name@.({})", message_id);
)~~~");
#endif #endif
out() << " return nullptr;"; endpoint_generator.append(R"~~~(
out() << " }"; return nullptr;
out() << " return message;"; }
out() << " }";
out(); if (stream.handle_any_error()) {
out() << " virtual OwnPtr<IPC::Message> handle(const IPC::Message& message) override"; )~~~");
out() << " {"; #ifdef GENERATE_DEBUG_CODE
out() << " switch (message.message_id()) {"; endpoint_generator.append(R"~~~(
dbgln("Failed to read the message");
)~~~");
#endif
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) { for (auto& message : endpoint.messages) {
auto do_decode_message = [&](const String& name, bool returns_something) { 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) { 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 { } else {
out() << " handle(static_cast<const Messages::" << endpoint.name << "::" << name << "&>(message));"; message_generator.append(R"~~~(
out() << " return nullptr;"; handle(static_cast<const Messages::@endpoint.name@::@message.name@&>(message));
return nullptr;
)~~~");
} }
}; };
do_decode_message(message.name, message.is_synchronous); do_decode_message(message.name, message.is_synchronous);
if (message.is_synchronous) if (message.is_synchronous)
do_decode_message(message.response_name(), false); do_decode_message(message.response_name(), false);
} }
out() << " default:"; endpoint_generator.append(R"~~~(
out() << " return nullptr;"; default:
return nullptr;
out() << " }"; }
out() << " }"; }
)~~~");
for (auto& message : endpoint.messages) { for (auto& message : endpoint.messages) {
SourceGenerator message_generator { endpoint_generator };
message_generator.set("message.name", message.name);
String return_type = "void"; String return_type = "void";
if (message.is_synchronous) { if (message.is_synchronous) {
StringBuilder builder; StringBuilder builder;
@ -433,30 +576,38 @@ int main(int argc, char** argv)
builder.append(">"); builder.append(">");
return_type = builder.to_string(); 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:"; endpoint_generator.append(R"~~~(
out() << "};"; private:
};
)~~~");
} }
outln("{}", generator.generate());
#ifdef DEBUG #ifdef DEBUG
for (auto& endpoint : endpoints) { for (auto& endpoint : endpoints) {
warn() << "Endpoint: '" << endpoint.name << "' (magic: " << endpoint.magic << ")"; warnln("Endpoint '{}' (magic: {})", endpoint.name, endpoint.magic);
for (auto& message : endpoint.messages) { for (auto& message : endpoint.messages) {
warn() << " Message: '" << message.name << "'"; warnln(" Message: '{}'", message.name);
warn() << " Sync: " << message.is_synchronous; warnln(" Sync: {}", message.is_synchronous);
warn() << " Inputs:"; warnln(" Inputs:");
for (auto& parameter : message.inputs) for (auto& parameter : message.inputs)
warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; warnln(" Parameter: {} ({})", parameter.name, parameter.type);
if (message.inputs.is_empty()) if (message.inputs.is_empty())
warn() << " (none)"; warnln(" (none)");
if (message.is_synchronous) { if (message.is_synchronous) {
warn() << " Outputs:"; warnln(" Outputs:");
for (auto& parameter : message.outputs) for (auto& parameter : message.outputs)
warn() << " Parameter: " << parameter.name << " (" << parameter.type << ")"; warnln(" Parameter: {} ({})", parameter.name, parameter.type);
if (message.outputs.is_empty()) if (message.outputs.is_empty())
warn() << " (none)"; warnln(" (none)");
} }
} }
} }