Serenity Operating System
at master 832 lines 30 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/Debug.h> 8#include <AK/Function.h> 9#include <AK/GenericLexer.h> 10#include <AK/HashMap.h> 11#include <AK/SourceGenerator.h> 12#include <AK/StringBuilder.h> 13#include <LibCore/File.h> 14#include <LibMain/Main.h> 15#include <ctype.h> 16#include <stdio.h> 17 18struct Parameter { 19 Vector<DeprecatedString> attributes; 20 DeprecatedString type; 21 DeprecatedString name; 22}; 23 24static DeprecatedString pascal_case(DeprecatedString const& identifier) 25{ 26 StringBuilder builder; 27 bool was_new_word = true; 28 for (auto ch : identifier) { 29 if (ch == '_') { 30 was_new_word = true; 31 continue; 32 } 33 if (was_new_word) { 34 builder.append(toupper(ch)); 35 was_new_word = false; 36 } else 37 builder.append(ch); 38 } 39 return builder.to_deprecated_string(); 40} 41 42struct Message { 43 DeprecatedString name; 44 bool is_synchronous { false }; 45 Vector<Parameter> inputs; 46 Vector<Parameter> outputs; 47 48 DeprecatedString response_name() const 49 { 50 StringBuilder builder; 51 builder.append(pascal_case(name)); 52 builder.append("Response"sv); 53 return builder.to_deprecated_string(); 54 } 55}; 56 57struct Endpoint { 58 Vector<DeprecatedString> includes; 59 DeprecatedString name; 60 u32 magic; 61 Vector<Message> messages; 62}; 63 64static bool is_primitive_type(DeprecatedString const& type) 65{ 66 return type.is_one_of("u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "size_t", "bool", "double", "float", "int", "unsigned", "unsigned int"); 67} 68 69static bool is_simple_type(DeprecatedString const& type) 70{ 71 // Small types that it makes sense just to pass by value. 72 return type.is_one_of("Gfx::Color", "Gfx::IntPoint", "Gfx::FloatPoint", "Gfx::IntSize", "Gfx::FloatSize", "Core::File::OpenMode"); 73} 74 75static bool is_primitive_or_simple_type(DeprecatedString const& type) 76{ 77 return is_primitive_type(type) || is_simple_type(type); 78} 79 80static DeprecatedString message_name(DeprecatedString const& endpoint, DeprecatedString const& message, bool is_response) 81{ 82 StringBuilder builder; 83 builder.append("Messages::"sv); 84 builder.append(endpoint); 85 builder.append("::"sv); 86 builder.append(pascal_case(message)); 87 if (is_response) 88 builder.append("Response"sv); 89 return builder.to_deprecated_string(); 90} 91 92Vector<Endpoint> parse(ByteBuffer const& file_contents) 93{ 94 GenericLexer lexer(file_contents); 95 96 Vector<Endpoint> endpoints; 97 98 auto assert_specific = [&lexer](char ch) { 99 if (lexer.peek() != ch) 100 warnln("assert_specific: wanted '{}', but got '{}' at index {}", ch, lexer.peek(), lexer.tell()); 101 bool saw_expected = lexer.consume_specific(ch); 102 VERIFY(saw_expected); 103 }; 104 105 auto consume_whitespace = [&lexer] { 106 lexer.ignore_while([](char ch) { return isspace(ch); }); 107 if (lexer.peek() == '/' && lexer.peek(1) == '/') 108 lexer.ignore_until('\n'); 109 }; 110 111 auto parse_parameter = [&](Vector<Parameter>& storage) { 112 for (;;) { 113 Parameter parameter; 114 if (lexer.is_eof()) { 115 warnln("EOF when parsing parameter"); 116 VERIFY_NOT_REACHED(); 117 } 118 consume_whitespace(); 119 if (lexer.peek() == ')') 120 break; 121 if (lexer.consume_specific('[')) { 122 for (;;) { 123 if (lexer.consume_specific(']')) { 124 consume_whitespace(); 125 break; 126 } 127 if (lexer.consume_specific(',')) { 128 consume_whitespace(); 129 } 130 auto attribute = lexer.consume_until([](char ch) { return ch == ']' || ch == ','; }); 131 parameter.attributes.append(attribute); 132 consume_whitespace(); 133 } 134 } 135 // FIXME: This is not entirely correct. Types can have spaces, for example `HashMap<int, DeprecatedString>`. 136 // Maybe we should use LibCpp::Parser for parsing types. 137 parameter.type = lexer.consume_until([](char ch) { return isspace(ch); }); 138 VERIFY(!lexer.is_eof()); 139 consume_whitespace(); 140 parameter.name = lexer.consume_until([](char ch) { return isspace(ch) || ch == ',' || ch == ')'; }); 141 consume_whitespace(); 142 storage.append(move(parameter)); 143 if (lexer.consume_specific(',')) 144 continue; 145 if (lexer.peek() == ')') 146 break; 147 } 148 }; 149 150 auto parse_parameters = [&](Vector<Parameter>& storage) { 151 for (;;) { 152 consume_whitespace(); 153 parse_parameter(storage); 154 consume_whitespace(); 155 if (lexer.consume_specific(',')) 156 continue; 157 if (lexer.peek() == ')') 158 break; 159 } 160 }; 161 162 auto parse_message = [&] { 163 Message message; 164 consume_whitespace(); 165 message.name = lexer.consume_until([](char ch) { return isspace(ch) || ch == '('; }); 166 consume_whitespace(); 167 assert_specific('('); 168 parse_parameters(message.inputs); 169 assert_specific(')'); 170 consume_whitespace(); 171 assert_specific('='); 172 173 auto type = lexer.consume(); 174 if (type == '>') 175 message.is_synchronous = true; 176 else if (type == '|') 177 message.is_synchronous = false; 178 else 179 VERIFY_NOT_REACHED(); 180 181 consume_whitespace(); 182 183 if (message.is_synchronous) { 184 assert_specific('('); 185 parse_parameters(message.outputs); 186 assert_specific(')'); 187 } 188 189 consume_whitespace(); 190 191 endpoints.last().messages.append(move(message)); 192 }; 193 194 auto parse_messages = [&] { 195 for (;;) { 196 consume_whitespace(); 197 if (lexer.peek() == '}') 198 break; 199 parse_message(); 200 consume_whitespace(); 201 } 202 }; 203 204 auto parse_include = [&] { 205 DeprecatedString include; 206 consume_whitespace(); 207 include = lexer.consume_while([](char ch) { return ch != '\n'; }); 208 consume_whitespace(); 209 210 endpoints.last().includes.append(move(include)); 211 }; 212 213 auto parse_includes = [&] { 214 for (;;) { 215 consume_whitespace(); 216 if (lexer.peek() != '#') 217 break; 218 parse_include(); 219 consume_whitespace(); 220 } 221 }; 222 223 auto parse_endpoint = [&] { 224 endpoints.empend(); 225 consume_whitespace(); 226 parse_includes(); 227 consume_whitespace(); 228 lexer.consume_specific("endpoint"); 229 consume_whitespace(); 230 endpoints.last().name = lexer.consume_while([](char ch) { return !isspace(ch); }); 231 endpoints.last().magic = Traits<DeprecatedString>::hash(endpoints.last().name); 232 consume_whitespace(); 233 assert_specific('{'); 234 parse_messages(); 235 assert_specific('}'); 236 consume_whitespace(); 237 }; 238 239 while (lexer.tell() < file_contents.size()) 240 parse_endpoint(); 241 242 return endpoints; 243} 244 245HashMap<DeprecatedString, int> build_message_ids_for_endpoint(SourceGenerator generator, Endpoint const& endpoint) 246{ 247 HashMap<DeprecatedString, int> message_ids; 248 249 generator.appendln("\nenum class MessageID : i32 {"); 250 for (auto const& message : endpoint.messages) { 251 252 message_ids.set(message.name, message_ids.size() + 1); 253 generator.set("message.pascal_name", pascal_case(message.name)); 254 generator.set("message.id", DeprecatedString::number(message_ids.size())); 255 256 generator.appendln(" @message.pascal_name@ = @message.id@,"); 257 if (message.is_synchronous) { 258 message_ids.set(message.response_name(), message_ids.size() + 1); 259 generator.set("message.pascal_name", pascal_case(message.response_name())); 260 generator.set("message.id", DeprecatedString::number(message_ids.size())); 261 262 generator.appendln(" @message.pascal_name@ = @message.id@,"); 263 } 264 } 265 generator.appendln("};"); 266 return message_ids; 267} 268 269DeprecatedString constructor_for_message(DeprecatedString const& name, Vector<Parameter> const& parameters) 270{ 271 StringBuilder builder; 272 builder.append(name); 273 274 if (parameters.is_empty()) { 275 builder.append("() {}"sv); 276 return builder.to_deprecated_string(); 277 } 278 builder.append('('); 279 for (size_t i = 0; i < parameters.size(); ++i) { 280 auto const& parameter = parameters[i]; 281 builder.appendff("{} {}", parameter.type, parameter.name); 282 if (i != parameters.size() - 1) 283 builder.append(", "sv); 284 } 285 builder.append(") : "sv); 286 for (size_t i = 0; i < parameters.size(); ++i) { 287 auto const& parameter = parameters[i]; 288 builder.appendff("m_{}(move({}))", parameter.name, parameter.name); 289 if (i != parameters.size() - 1) 290 builder.append(", "sv); 291 } 292 builder.append(" {}"sv); 293 return builder.to_deprecated_string(); 294} 295 296void do_message(SourceGenerator message_generator, DeprecatedString const& name, Vector<Parameter> const& parameters, DeprecatedString const& response_type = {}) 297{ 298 auto pascal_name = pascal_case(name); 299 message_generator.set("message.name", name); 300 message_generator.set("message.pascal_name", pascal_name); 301 message_generator.set("message.response_type", response_type); 302 message_generator.set("message.constructor", constructor_for_message(pascal_name, parameters)); 303 304 message_generator.appendln(R"~~~( 305class @message.pascal_name@ final : public IPC::Message { 306public:)~~~"); 307 308 if (!response_type.is_null()) 309 message_generator.appendln(R"~~~( 310 typedef class @message.response_type@ ResponseType;)~~~"); 311 312 message_generator.appendln(R"~~~( 313 @message.pascal_name@(decltype(nullptr)) : m_ipc_message_valid(false) { } 314 @message.pascal_name@(@message.pascal_name@ const&) = default; 315 @message.pascal_name@(@message.pascal_name@&&) = default; 316 @message.pascal_name@& operator=(@message.pascal_name@ const&) = default; 317 @message.constructor@)~~~"); 318 319 if (parameters.size() == 1) { 320 auto const& parameter = parameters[0]; 321 message_generator.set("parameter.type"sv, parameter.type); 322 message_generator.set("parameter.name"sv, parameter.name); 323 324 message_generator.appendln(R"~~~( 325 template <typename WrappedReturnType> 326 requires(!SameAs<WrappedReturnType, @parameter.type@>) 327 @message.pascal_name@(WrappedReturnType&& value) 328 : m_@parameter.name@(forward<WrappedReturnType>(value)) 329 { 330 })~~~"); 331 } 332 333 message_generator.appendln(R"~~~( 334 virtual ~@message.pascal_name@() override {} 335 336 virtual u32 endpoint_magic() const override { return @endpoint.magic@; } 337 virtual i32 message_id() const override { return (int)MessageID::@message.pascal_name@; } 338 static i32 static_message_id() { return (int)MessageID::@message.pascal_name@; } 339 virtual const char* message_name() const override { return "@endpoint.name@::@message.pascal_name@"; } 340 341 static ErrorOr<NonnullOwnPtr<@message.pascal_name@>> decode(Stream& stream, Core::LocalSocket& socket) 342 { 343 IPC::Decoder decoder { stream, socket };)~~~"); 344 345 for (auto const& parameter : parameters) { 346 auto parameter_generator = message_generator.fork(); 347 348 parameter_generator.set("parameter.type", parameter.type); 349 parameter_generator.set("parameter.name", parameter.name); 350 351 if (parameter.type == "bool") 352 parameter_generator.set("parameter.initial_value", "false"); 353 else 354 parameter_generator.set("parameter.initial_value", "{}"); 355 356 parameter_generator.appendln(R"~~~( 357 auto @parameter.name@ = TRY((decoder.decode<@parameter.type@>()));)~~~"); 358 359 if (parameter.attributes.contains_slow("UTF8")) { 360 parameter_generator.appendln(R"~~~( 361 if (!Utf8View(@parameter.name@).validate()) 362 return Error::from_string_literal("Decoded @parameter.name@ is invalid UTF-8");)~~~"); 363 } 364 } 365 366 StringBuilder builder; 367 for (size_t i = 0; i < parameters.size(); ++i) { 368 auto const& parameter = parameters[i]; 369 builder.appendff("move({})", parameter.name); 370 if (i != parameters.size() - 1) 371 builder.append(", "sv); 372 } 373 374 message_generator.set("message.constructor_call_parameters", builder.to_deprecated_string()); 375 message_generator.appendln(R"~~~( 376 return make<@message.pascal_name@>(@message.constructor_call_parameters@); 377 })~~~"); 378 379 message_generator.appendln(R"~~~( 380 virtual bool valid() const override { return m_ipc_message_valid; } 381 382 virtual ErrorOr<IPC::MessageBuffer> encode() const override 383 { 384 VERIFY(valid()); 385 386 IPC::MessageBuffer buffer; 387 IPC::Encoder stream(buffer); 388 TRY(stream.encode(endpoint_magic())); 389 TRY(stream.encode((int)MessageID::@message.pascal_name@));)~~~"); 390 391 for (auto const& parameter : parameters) { 392 auto parameter_generator = message_generator.fork(); 393 394 parameter_generator.set("parameter.name", parameter.name); 395 parameter_generator.appendln(R"~~~( 396 TRY(stream.encode(m_@parameter.name@));)~~~"); 397 } 398 399 message_generator.appendln(R"~~~( 400 return buffer; 401 })~~~"); 402 403 for (auto const& parameter : parameters) { 404 auto parameter_generator = message_generator.fork(); 405 parameter_generator.set("parameter.type", parameter.type); 406 parameter_generator.set("parameter.name", parameter.name); 407 parameter_generator.appendln(R"~~~( 408 const @parameter.type@& @parameter.name@() const { return m_@parameter.name@; } 409 @parameter.type@ take_@parameter.name@() { return move(m_@parameter.name@); })~~~"); 410 } 411 412 message_generator.appendln(R"~~~( 413private: 414 bool m_ipc_message_valid { true };)~~~"); 415 416 for (auto const& parameter : parameters) { 417 auto parameter_generator = message_generator.fork(); 418 parameter_generator.set("parameter.type", parameter.type); 419 parameter_generator.set("parameter.name", parameter.name); 420 parameter_generator.appendln(R"~~~( 421 @parameter.type@ m_@parameter.name@ {};)~~~"); 422 } 423 424 message_generator.appendln("\n};"); 425} 426 427void do_message_for_proxy(SourceGenerator message_generator, Endpoint const& endpoint, Message const& message) 428{ 429 auto do_implement_proxy = [&](DeprecatedString const& name, Vector<Parameter> const& parameters, bool is_synchronous, bool is_try) { 430 DeprecatedString return_type = "void"; 431 if (is_synchronous) { 432 if (message.outputs.size() == 1) 433 return_type = message.outputs[0].type; 434 else if (!message.outputs.is_empty()) 435 return_type = message_name(endpoint.name, message.name, true); 436 } 437 DeprecatedString inner_return_type = return_type; 438 if (is_try) 439 return_type = DeprecatedString::formatted("IPC::IPCErrorOr<{}>", return_type); 440 441 message_generator.set("message.name", message.name); 442 message_generator.set("message.pascal_name", pascal_case(message.name)); 443 message_generator.set("message.complex_return_type", return_type); 444 message_generator.set("async_prefix_maybe", is_synchronous ? "" : "async_"); 445 message_generator.set("try_prefix_maybe", is_try ? "try_" : ""); 446 447 message_generator.set("handler_name", name); 448 message_generator.appendln(R"~~~( 449 @message.complex_return_type@ @try_prefix_maybe@@async_prefix_maybe@@handler_name@()~~~"); 450 451 for (size_t i = 0; i < parameters.size(); ++i) { 452 auto const& parameter = parameters[i]; 453 auto argument_generator = message_generator.fork(); 454 argument_generator.set("argument.type", parameter.type); 455 argument_generator.set("argument.name", parameter.name); 456 argument_generator.append("@argument.type@ @argument.name@"); 457 if (i != parameters.size() - 1) 458 argument_generator.append(", "); 459 } 460 461 message_generator.append(") {"); 462 463 if (is_synchronous && !is_try) { 464 if (return_type != "void") { 465 message_generator.append(R"~~~( 466 return )~~~"); 467 if (message.outputs.size() != 1) 468 message_generator.append("move(*"); 469 } else { 470 message_generator.append(R"~~~( 471 (void) )~~~"); 472 } 473 474 message_generator.append("m_connection.template send_sync<Messages::@endpoint.name@::@message.pascal_name@>("); 475 } else if (is_try) { 476 message_generator.append(R"~~~( 477 auto result = m_connection.template send_sync_but_allow_failure<Messages::@endpoint.name@::@message.pascal_name@>()~~~"); 478 } else { 479 message_generator.append(R"~~~( 480 // FIXME: Handle post_message failures. 481 (void) m_connection.post_message(Messages::@endpoint.name@::@message.pascal_name@ { )~~~"); 482 } 483 484 for (size_t i = 0; i < parameters.size(); ++i) { 485 auto const& parameter = parameters[i]; 486 auto argument_generator = message_generator.fork(); 487 argument_generator.set("argument.name", parameter.name); 488 if (is_primitive_or_simple_type(parameters[i].type)) 489 argument_generator.append("@argument.name@"); 490 else 491 argument_generator.append("move(@argument.name@)"); 492 if (i != parameters.size() - 1) 493 argument_generator.append(", "); 494 } 495 496 if (is_synchronous && !is_try) { 497 if (return_type != "void") { 498 message_generator.append(")"); 499 } 500 501 if (message.outputs.size() == 1) { 502 message_generator.append("->take_"); 503 message_generator.append(message.outputs[0].name); 504 message_generator.append("()"); 505 } else 506 message_generator.append(")"); 507 508 message_generator.append(";"); 509 } else if (is_try) { 510 message_generator.append(R"~~~(); 511 if (!result) 512 return IPC::ErrorCode::PeerDisconnected;)~~~"); 513 if (inner_return_type != "void") { 514 message_generator.appendln(R"~~~( 515 return move(*result);)~~~"); 516 } else { 517 message_generator.appendln(R"~~~( 518 return { };)~~~"); 519 } 520 } else { 521 message_generator.appendln(" });"); 522 } 523 524 message_generator.appendln(R"~~~( 525 })~~~"); 526 }; 527 528 do_implement_proxy(message.name, message.inputs, message.is_synchronous, false); 529 if (message.is_synchronous) { 530 do_implement_proxy(message.name, message.inputs, false, false); 531 do_implement_proxy(message.name, message.inputs, true, true); 532 } 533} 534 535void build_endpoint(SourceGenerator generator, Endpoint const& endpoint) 536{ 537 generator.set("endpoint.name", endpoint.name); 538 generator.set("endpoint.magic", DeprecatedString::number(endpoint.magic)); 539 540 generator.appendln("\nnamespace Messages::@endpoint.name@ {"); 541 542 HashMap<DeprecatedString, int> message_ids = build_message_ids_for_endpoint(generator.fork(), endpoint); 543 544 for (auto const& message : endpoint.messages) { 545 DeprecatedString response_name; 546 if (message.is_synchronous) { 547 response_name = message.response_name(); 548 do_message(generator.fork(), response_name, message.outputs); 549 } 550 do_message(generator.fork(), message.name, message.inputs, response_name); 551 } 552 553 generator.appendln(R"~~~( 554} // namespace Messages::@endpoint.name@ 555 556template<typename LocalEndpoint, typename PeerEndpoint> 557class @endpoint.name@Proxy { 558public: 559 // Used to disambiguate the constructor call. 560 struct Tag { }; 561 562 @endpoint.name@Proxy(IPC::Connection<LocalEndpoint, PeerEndpoint>& connection, Tag) 563 : m_connection(connection) 564 { })~~~"); 565 566 for (auto const& message : endpoint.messages) 567 do_message_for_proxy(generator.fork(), endpoint, message); 568 569 generator.appendln(R"~~~( 570private: 571 IPC::Connection<LocalEndpoint, PeerEndpoint>& m_connection; 572};)~~~"); 573 574 generator.append(R"~~~( 575template<typename LocalEndpoint, typename PeerEndpoint> 576class @endpoint.name@Proxy; 577class @endpoint.name@Stub; 578 579class @endpoint.name@Endpoint { 580public: 581 template<typename LocalEndpoint> 582 using Proxy = @endpoint.name@Proxy<LocalEndpoint, @endpoint.name@Endpoint>; 583 using Stub = @endpoint.name@Stub; 584 585 static u32 static_magic() { return @endpoint.magic@; } 586 587 static ErrorOr<NonnullOwnPtr<IPC::Message>> decode_message(ReadonlyBytes buffer, [[maybe_unused]] Core::LocalSocket& socket) 588 { 589 FixedMemoryStream stream { buffer }; 590 auto message_endpoint_magic = TRY(stream.read_value<u32>());)~~~"); 591 generator.append(R"~~~( 592 593 if (message_endpoint_magic != @endpoint.magic@) {)~~~"); 594 if constexpr (GENERATE_DEBUG) { 595 generator.append(R"~~~( 596 dbgln("@endpoint.name@: Endpoint magic number message_endpoint_magic != @endpoint.magic@, not my message! (the other endpoint may have handled it)");)~~~"); 597 } 598 generator.appendln(R"~~~( 599 return Error::from_string_literal("Endpoint magic number mismatch, not my message!"); 600 } 601 602 auto message_id = TRY(stream.read_value<i32>());)~~~"); 603 generator.appendln(R"~~~( 604 605 switch (message_id) {)~~~"); 606 607 for (auto const& message : endpoint.messages) { 608 auto do_decode_message = [&](DeprecatedString const& name) { 609 auto message_generator = generator.fork(); 610 611 message_generator.set("message.name", name); 612 message_generator.set("message.pascal_name", pascal_case(name)); 613 614 message_generator.append(R"~~~( 615 case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@: 616 return TRY(Messages::@endpoint.name@::@message.pascal_name@::decode(stream, socket));)~~~"); 617 }; 618 619 do_decode_message(message.name); 620 if (message.is_synchronous) 621 do_decode_message(message.response_name()); 622 } 623 624 generator.append(R"~~~( 625 default:)~~~"); 626 if constexpr (GENERATE_DEBUG) { 627 generator.append(R"~~~( 628 dbgln("Failed to decode @endpoint.name@.({})", message_id);)~~~"); 629 } 630 generator.appendln(R"~~~( 631 return Error::from_string_literal("Failed to decode @endpoint.name@ message"); 632 })~~~"); 633 634 generator.appendln(R"~~~( 635 VERIFY_NOT_REACHED(); 636 } 637 638}; 639 640class @endpoint.name@Stub : public IPC::Stub { 641public: 642 @endpoint.name@Stub() { } 643 virtual ~@endpoint.name@Stub() override { } 644 645 virtual u32 magic() const override { return @endpoint.magic@; } 646 virtual DeprecatedString name() const override { return "@endpoint.name@"; } 647 648 virtual ErrorOr<OwnPtr<IPC::MessageBuffer>> handle(const IPC::Message& message) override 649 { 650 switch (message.message_id()) {)~~~"); 651 for (auto const& message : endpoint.messages) { 652 auto do_handle_message = [&](DeprecatedString const& name, Vector<Parameter> const& parameters, bool returns_something) { 653 auto message_generator = generator.fork(); 654 655 StringBuilder argument_generator; 656 for (size_t i = 0; i < parameters.size(); ++i) { 657 auto const& parameter = parameters[i]; 658 argument_generator.append("request."sv); 659 argument_generator.append(parameter.name); 660 argument_generator.append("()"sv); 661 if (i != parameters.size() - 1) 662 argument_generator.append(", "sv); 663 } 664 665 message_generator.set("message.pascal_name", pascal_case(name)); 666 message_generator.set("message.response_type", pascal_case(message.response_name())); 667 message_generator.set("handler_name", name); 668 message_generator.set("arguments", argument_generator.to_deprecated_string()); 669 message_generator.appendln(R"~~~( 670 case (int)Messages::@endpoint.name@::MessageID::@message.pascal_name@: {)~~~"); 671 if (returns_something) { 672 if (message.outputs.is_empty()) { 673 message_generator.appendln(R"~~~( 674 [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); 675 @handler_name@(@arguments@); 676 auto response = Messages::@endpoint.name@::@message.response_type@ { }; 677 return make<IPC::MessageBuffer>(TRY(response.encode()));)~~~"); 678 } else { 679 message_generator.appendln(R"~~~( 680 [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); 681 auto response = @handler_name@(@arguments@); 682 if (!response.valid()) 683 return Error::from_string_literal("Failed to handle @endpoint.name@::@message.pascal_name@ message"); 684 return make<IPC::MessageBuffer>(TRY(response.encode()));)~~~"); 685 } 686 } else { 687 message_generator.appendln(R"~~~( 688 [[maybe_unused]] auto& request = static_cast<const Messages::@endpoint.name@::@message.pascal_name@&>(message); 689 @handler_name@(@arguments@); 690 return nullptr;)~~~"); 691 } 692 message_generator.appendln(R"~~~( 693 })~~~"); 694 }; 695 do_handle_message(message.name, message.inputs, message.is_synchronous); 696 } 697 generator.appendln(R"~~~( 698 default: 699 return Error::from_string_literal("Unknown message ID for @endpoint.name@ endpoint"); 700 } 701 })~~~"); 702 703 for (auto const& message : endpoint.messages) { 704 auto message_generator = generator.fork(); 705 706 auto do_handle_message_decl = [&](DeprecatedString const& name, Vector<Parameter> const& parameters, bool is_response) { 707 DeprecatedString return_type = "void"; 708 if (message.is_synchronous && !message.outputs.is_empty() && !is_response) 709 return_type = message_name(endpoint.name, message.name, true); 710 message_generator.set("message.complex_return_type", return_type); 711 712 message_generator.set("handler_name", name); 713 message_generator.appendln(R"~~~( 714 virtual @message.complex_return_type@ @handler_name@()~~~"); 715 716 auto make_argument_type = [](DeprecatedString const& type) { 717 StringBuilder builder; 718 719 bool const_ref = !is_primitive_or_simple_type(type); 720 721 builder.append(type); 722 if (const_ref) 723 builder.append(" const&"sv); 724 725 return builder.to_deprecated_string(); 726 }; 727 728 for (size_t i = 0; i < parameters.size(); ++i) { 729 auto const& parameter = parameters[i]; 730 auto argument_generator = message_generator.fork(); 731 argument_generator.set("argument.type", make_argument_type(parameter.type)); 732 argument_generator.set("argument.name", parameter.name); 733 argument_generator.append("[[maybe_unused]] @argument.type@ @argument.name@"); 734 if (i != parameters.size() - 1) 735 argument_generator.append(", "); 736 } 737 738 if (is_response) { 739 message_generator.append(") { };"); 740 } else { 741 message_generator.appendln(") = 0;"); 742 } 743 }; 744 745 do_handle_message_decl(message.name, message.inputs, false); 746 } 747 748 generator.appendln(R"~~~( 749private: 750}; 751 752#if defined(AK_COMPILER_CLANG) 753#pragma clang diagnostic pop 754#endif)~~~"); 755} 756 757void build(StringBuilder& builder, Vector<Endpoint> const& endpoints) 758{ 759 SourceGenerator generator { builder }; 760 761 generator.appendln("#pragma once"); 762 763 // This must occur before LibIPC/Decoder.h 764 for (auto const& endpoint : endpoints) { 765 for (auto const& include : endpoint.includes) { 766 generator.appendln(include); 767 } 768 } 769 770 generator.appendln(R"~~~(#include <AK/Error.h> 771#include <AK/MemoryStream.h> 772#include <AK/OwnPtr.h> 773#include <AK/Result.h> 774#include <AK/Utf8View.h> 775#include <LibIPC/Connection.h> 776#include <LibIPC/Decoder.h> 777#include <LibIPC/Dictionary.h> 778#include <LibIPC/Encoder.h> 779#include <LibIPC/File.h> 780#include <LibIPC/Message.h> 781#include <LibIPC/Stub.h> 782 783#if defined(AK_COMPILER_CLANG) 784#pragma clang diagnostic push 785#pragma clang diagnostic ignored "-Wdefaulted-function-deleted" 786#endif)~~~"); 787 788 for (auto const& endpoint : endpoints) 789 build_endpoint(generator.fork(), endpoint); 790} 791 792ErrorOr<int> serenity_main(Main::Arguments arguments) 793{ 794 if (arguments.argc != 2) { 795 outln("usage: {} <IPC endpoint definition file>", arguments.strings[0]); 796 return 1; 797 } 798 799 auto file = TRY(Core::File::open(arguments.strings[1], Core::File::OpenMode::Read)); 800 801 auto file_contents = TRY(file->read_until_eof()); 802 803 auto endpoints = parse(file_contents); 804 805 StringBuilder builder; 806 build(builder, endpoints); 807 808 outln("{}", builder.string_view()); 809 810 if constexpr (GENERATE_DEBUG) { 811 for (auto& endpoint : endpoints) { 812 warnln("Endpoint '{}' (magic: {})", endpoint.name, endpoint.magic); 813 for (auto& message : endpoint.messages) { 814 warnln(" Message: '{}'", message.name); 815 warnln(" Sync: {}", message.is_synchronous); 816 warnln(" Inputs:"); 817 for (auto& parameter : message.inputs) 818 warnln(" Parameter: {} ({})", parameter.name, parameter.type); 819 if (message.inputs.is_empty()) 820 warnln(" (none)"); 821 if (message.is_synchronous) { 822 warnln(" Outputs:"); 823 for (auto& parameter : message.outputs) 824 warnln(" Parameter: {} ({})", parameter.name, parameter.type); 825 if (message.outputs.is_empty()) 826 warnln(" (none)"); 827 } 828 } 829 } 830 } 831 return 0; 832}