diff --git a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp index 21b3ce5cb01..5eafb9d7e71 100644 --- a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp @@ -102,10 +102,11 @@ static ErrorOr include_path_for(StringView class_name, LexicalPath const } // Each entry is an include path, without the "#include" itself. -static ErrorOr> extract_necessary_includes(GUI::GML::Object const& gml_hierarchy, LexicalPath const& gml_file_name) +static ErrorOr> extract_necessary_includes(GUI::GML::Object const& gml_hierarchy, LexicalPath const& gml_file_name, bool is_root = false) { HashTable necessary_includes; - TRY(necessary_includes.try_set(TRY(include_path_for(gml_hierarchy.name(), gml_file_name)))); + if (!is_root) + TRY(necessary_includes.try_set(TRY(include_path_for(gml_hierarchy.name(), gml_file_name)))); if (gml_hierarchy.layout_object() != nullptr) TRY(necessary_includes.try_set(TRY(include_path_for(gml_hierarchy.layout_object()->name(), gml_file_name)))); @@ -126,6 +127,22 @@ static char const header[] = R"~~~( )~~~"; +static char const class_declaration[] = R"~~~( +// A barebones definition of @main_class_name@ used to emit the symbol try_create. +// Requirements: +// - Inherits from GUI::Widget (indirectly, is declared as 'class') +// - Has a default ctor +// - Has declared a compatible static ErrorOr> try_create(). +namespace @class_namespace@ { +class @pure_class_name@ : public GUI::Widget { +public: + @pure_class_name@(); + static ErrorOr> try_create(); +}; +} + +)~~~"; + static char const function_start[] = R"~~~( // Creates a @main_class_name@ and initializes it. // This function was auto-generated by the GML compiler. @@ -350,7 +367,7 @@ static ErrorOr generate_cpp(NonnullRefPtr gml, Lexica generator.append(header); auto& main_class = gml->main_class(); - auto necessary_includes = TRY(extract_necessary_includes(main_class, gml_file_name)); + auto necessary_includes = TRY(extract_necessary_includes(main_class, gml_file_name, true)); static String const always_necessary_includes[] = { ""_string, ""_string, @@ -367,8 +384,24 @@ static ErrorOr generate_cpp(NonnullRefPtr gml, Lexica for (auto const& include : necessary_includes) generator.appendln(TRY(String::formatted("#include {}", include))); + auto main_file_header = TRY(include_path_for(main_class.name(), gml_file_name)); + generator.appendln(TRY(String::formatted("#if __has_include({})", main_file_header))); + generator.appendln(TRY(String::formatted("#include {}", main_file_header))); + generator.appendln("#else"); + // FIXME: Use a UTF-8 aware function once possible. + auto ns_position = main_class.name().find_last("::"sv); + auto ns = main_class.name().substring_view(0, ns_position.value_or(0)); + auto pure_class_name = main_class.name().substring_view(ns_position.map([](auto x) { return x + 2; }).value_or(0)); + + generator.set("class_namespace", ns); + generator.set("pure_class_name", pure_class_name); generator.set("main_class_name", main_class.name()); + + generator.append(class_declaration); + + generator.appendln("#endif // __has_include(...)"); + generator.append(function_start); TRY(generate_loader_for_object(main_class, generator.fork(), "main_object"_string, 2, UseObjectConstructor::No));