#include #include #include #include #include #include #include #include #include #include #include namespace { enum class MetaCoreReflectedKind { Struct, Class, Enum }; struct MetaCoreReflectedField { std::string Name{}; }; struct MetaCoreReflectedType { MetaCoreReflectedKind Kind = MetaCoreReflectedKind::Struct; std::string Name{}; std::vector Fields{}; }; [[nodiscard]] std::string MetaCoreTrim(std::string value) { auto isWhitespace = [](unsigned char character) { return std::isspace(character) != 0; }; while (!value.empty() && isWhitespace(static_cast(value.front()))) { value.erase(value.begin()); } while (!value.empty() && isWhitespace(static_cast(value.back()))) { value.pop_back(); } return value; } [[nodiscard]] std::string MetaCoreBuildIncludePath(const std::filesystem::path& path) { const std::string full = path.generic_string(); constexpr std::string_view marker = "/Public/"; const std::size_t markerIndex = full.find(marker); if (markerIndex == std::string::npos) { return path.filename().generic_string(); } return full.substr(markerIndex + marker.size()); } [[nodiscard]] std::vector MetaCoreParseHeader(const std::filesystem::path& path) { std::ifstream input(path); if (!input.is_open()) { throw std::runtime_error("Unable to open header: " + path.string()); } const std::regex typeRegex(R"(^(struct|class|enum\s+class)\s+([A-Za-z_]\w*))"); const std::regex fieldRegex(R"(^(.+?)\s+([A-Za-z_]\w*)\s*(?:\{.*\}|=.*)?;$)"); std::vector reflectedTypes; std::optional pendingKind; MetaCoreReflectedType* currentType = nullptr; bool expectingField = false; std::string line; while (std::getline(input, line)) { const std::string trimmed = MetaCoreTrim(line); if (trimmed.empty() || trimmed.starts_with("//")) { continue; } if (trimmed.starts_with("MC_STRUCT")) { pendingKind = MetaCoreReflectedKind::Struct; continue; } if (trimmed.starts_with("MC_CLASS")) { pendingKind = MetaCoreReflectedKind::Class; continue; } if (trimmed.starts_with("MC_ENUM")) { pendingKind = MetaCoreReflectedKind::Enum; continue; } if (trimmed.starts_with("MC_PROPERTY")) { expectingField = true; continue; } if (trimmed.starts_with("MC_GENERATED_BODY")) { continue; } if (pendingKind.has_value()) { std::smatch match; if (std::regex_search(trimmed, match, typeRegex)) { reflectedTypes.push_back(MetaCoreReflectedType{ pendingKind.value(), match[2].str(), {} }); currentType = &reflectedTypes.back(); pendingKind.reset(); expectingField = false; continue; } } if (currentType != nullptr && trimmed == "};") { currentType = nullptr; expectingField = false; continue; } if (currentType == nullptr || currentType->Kind == MetaCoreReflectedKind::Enum || !expectingField) { continue; } std::smatch match; if (!std::regex_search(trimmed, match, fieldRegex)) { throw std::runtime_error("Unable to parse reflected field in " + path.string() + ": " + trimmed); } currentType->Fields.push_back(MetaCoreReflectedField{ match[2].str() }); expectingField = false; } return reflectedTypes; } [[nodiscard]] std::string MetaCoreBuildOutput( const std::string& functionName, const std::vector& headers ) { std::vector reflectedTypes; for (const auto& header : headers) { const auto parsed = MetaCoreParseHeader(header); reflectedTypes.insert(reflectedTypes.end(), parsed.begin(), parsed.end()); } std::ostringstream output; output << "#include \"MetaCoreFoundation/MetaCoreGeneratedReflection.h\"\n"; output << "#include \"MetaCoreFoundation/MetaCoreReflection.h\"\n"; for (const auto& header : headers) { output << "#include \"" << MetaCoreBuildIncludePath(header) << "\"\n"; } output << "\nnamespace MetaCore {\n\n"; output << "void " << functionName << "(MetaCoreTypeRegistry& registry) {\n"; for (const auto& reflectedType : reflectedTypes) { if (reflectedType.Kind == MetaCoreReflectedKind::Enum) { output << " MetaCoreRegisterGeneratedEnum<" << reflectedType.Name << ">(registry, \"" << reflectedType.Name << "\");\n"; continue; } output << " auto " << reflectedType.Name << "Builder = MetaCoreRegisterGeneratedStruct<" << reflectedType.Name << ">(registry, \"" << reflectedType.Name << "\");\n"; for (const auto& field : reflectedType.Fields) { output << " " << reflectedType.Name << "Builder.Field<&" << reflectedType.Name << "::" << field.Name << ">(\"" << field.Name << "\");\n"; } } output << "}\n\n} // namespace MetaCore\n"; return output.str(); } } // namespace int main(int argc, char** argv) { std::filesystem::path outputPath; std::string functionName; std::vector headers; for (int index = 1; index < argc; ++index) { const std::string_view argument(argv[index]); if (argument == "--output" && index + 1 < argc) { outputPath = argv[++index]; continue; } if (argument == "--function" && index + 1 < argc) { functionName = argv[++index]; continue; } if (argument == "--module" && index + 1 < argc) { ++index; continue; } headers.emplace_back(argv[index]); } if (outputPath.empty() || functionName.empty() || headers.empty()) { std::cerr << "Usage: MetaCoreHeaderTool --output --function [--module ] \n"; return 1; } try { const std::string output = MetaCoreBuildOutput(functionName, headers); std::ofstream file(outputPath, std::ios::trunc); if (!file.is_open()) { std::cerr << "Unable to open output file: " << outputPath << '\n'; return 1; } file << output; } catch (const std::exception& exception) { std::cerr << exception.what() << '\n'; return 1; } return 0; }