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
Notes: sideshowbarker 2024-07-19 01:55:57 +09:00

View file

@ -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:";
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() << " {";
SourceGenerator message_generator { endpoint_generator };
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) {
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:";
#ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to decode " << endpoint.name << ".(\" << message_id << \")\";";
#endif
out() << " return nullptr;";
out() << " }";
out() << " if (stream.handle_any_error()) {";
endpoint_generator.append(R"~~~(
default:
)~~~");
#ifdef GENERATE_DEBUG_CODE
out() << " dbg() << \"Failed to read the message\";";
endpoint_generator.append(R"~~~(
dbgln("Failed to decode @endpoint.name@.({})", message_id);
)~~~");
#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;
}
if (stream.handle_any_error()) {
)~~~");
#ifdef GENERATE_DEBUG_CODE
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) {
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)");
}
}
}