From 8049d45b43072ea6b8889832da62f3c5f32497cc Mon Sep 17 00:00:00 2001 From: maelstrom Date: Sat, 26 Apr 2025 02:14:39 +0200 Subject: [PATCH] feat(autogen): generate basis for instance --- autogen/CMakeLists.txt | 1 + autogen/src/analysis.cpp | 17 +++++++++++++++-- autogen/src/analysis.h | 1 + autogen/src/codegen.cpp | 27 +++++++++++++++++++++++++++ autogen/src/codegen.h | 6 ++++++ autogen/src/main.cpp | 10 ++++++++++ 6 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 autogen/src/codegen.cpp create mode 100644 autogen/src/codegen.h diff --git a/autogen/CMakeLists.txt b/autogen/CMakeLists.txt index b143633..994b2df 100644 --- a/autogen/CMakeLists.txt +++ b/autogen/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(autogen src/util.cpp src/cache.cpp src/analysis.cpp + src/codegen.cpp ) set_target_properties(autogen PROPERTIES OUTPUT_NAME "autogen") diff --git a/autogen/src/analysis.cpp b/autogen/src/analysis.cpp index 531aef0..2a5da85 100644 --- a/autogen/src/analysis.cpp +++ b/autogen/src/analysis.cpp @@ -1,9 +1,13 @@ #include "analysis.h" #include "util.h" +#include +#include #include #include #include +#include +namespace fs = std::filesystem; // Very simple parser // Example format: @@ -161,14 +165,23 @@ void processField(CXCursor cur, ClassAnalysis* state) { state->properties.push_back(anly); } -void processClass(CXCursor cur, AnalysisState* state, std::string className) { +void processClass(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) { ClassAnalysis anly; // Find base class std::string baseClass = findBaseClass(cur); + // Find header file + CXSourceLocation loc = clang_getCursorLocation(cur); + CXFile file; + unsigned line, column, off; + clang_getFileLocation(loc, &file, &line, &column, &off); + std::string headerName = x_clang_toString(clang_getFileName(file)); + fs::path headerPath = fs::relative(headerName, srcRoot); + anly.name = className; anly.baseClass = baseClass; + anly.headerPath = headerPath; // Add misc flags and options auto instanceDef = findAnnotation(cur, "OB::def_inst"); @@ -237,7 +250,7 @@ bool analyzeClasses(std::string path, std::string srcRoot, AnalysisState* state) if (!findInstanceAnnotation(cur)) return CXChildVisit_Continue; // Class is not "primary" declaration/is not instance, skip if (state->classes.count(className) > 0) return CXChildVisit_Continue; // Class has already been analyzed, skip... - processClass(cur, state, className); + processClass(cur, state, className, srcRoot); return CXChildVisit_Continue; }); diff --git a/autogen/src/analysis.h b/autogen/src/analysis.h index 03cb720..3a48e5b 100644 --- a/autogen/src/analysis.h +++ b/autogen/src/analysis.h @@ -38,6 +38,7 @@ inline PropertyFlags operator|(PropertyFlags a, PropertyFlags b) { struct ClassAnalysis { std::string name; std::string baseClass; + std::string headerPath; std::vector properties; ClassFlags flags = (ClassFlags)0; std::string explorerIcon; diff --git a/autogen/src/codegen.cpp b/autogen/src/codegen.cpp new file mode 100644 index 0000000..9a04598 --- /dev/null +++ b/autogen/src/codegen.cpp @@ -0,0 +1,27 @@ +#include "codegen.h" +#include "analysis.h" + +void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) { + std::string strFlags; + if (state.flags & ClassFlag_NotCreatable) + strFlags += " | INSTANCE_NOT_CREATABLE"; + if (state.flags & ClassFlag_Service) + strFlags += " | INSTANCE_SERVICE"; + if (state.flags & ClassFlag_Hidden) + strFlags += " | INSTANCE_HIDDEN"; + if (!strFlags.empty()) strFlags = strFlags.substr(3); // Remove leading pipe + else strFlags = "0"; // 0 == No option + + out << "#include \"" << state.headerPath << "\"\n\n"; + out << "const InstanceType " << state.name << "::TYPE = {\n" + << " .super = &" << state.baseClass << "::TYPE,\n" + << " .className = \"" << state.name << "\",\n" + << " .constructor = &" << state.name << "::CreateGeneric,\n" + << " .explorerIcon = \"" << state.explorerIcon << "\",\n" + << " .flags = " << strFlags << ",\n" + << "};\n\n"; + + out << "const InstanceType* " << state.name << "::GetClass() {\n" + << " return &TYPE;\n" + << "};\n\n"; +} \ No newline at end of file diff --git a/autogen/src/codegen.h b/autogen/src/codegen.h new file mode 100644 index 0000000..c3a155b --- /dev/null +++ b/autogen/src/codegen.h @@ -0,0 +1,6 @@ +#pragma once + +#include "analysis.h" +#include + +void writeCodeForClass(std::ofstream& out, ClassAnalysis& state); \ No newline at end of file diff --git a/autogen/src/main.cpp b/autogen/src/main.cpp index 446d145..d430785 100644 --- a/autogen/src/main.cpp +++ b/autogen/src/main.cpp @@ -4,11 +4,13 @@ #include #include #include +#include #include #include #include #include "analysis.h" #include "cache.h" +#include "codegen.h" namespace fs = std::filesystem; @@ -40,6 +42,14 @@ int main(int argc, char** argv) { analyzeClasses("../core/src/objects/part.h", argv[1], &state); + printf("[AUTOGEN] Generating cpp files...\n"); + for (auto& [_, clazz] : state.classes) { + fs::path outPath = fs::path(argv[3]) / ("class_" + clazz.name + ".cpp"); + std::ofstream outStream(outPath); + + writeCodeForClass(outStream, clazz); + outStream.close(); + } // for (auto& [_, clazz] : state.classes) { // printf("Class: %s\n", clazz.name.c_str());