diff --git a/autogen/CMakeLists.txt b/autogen/CMakeLists.txt index 2249577..d77d05e 100644 --- a/autogen/CMakeLists.txt +++ b/autogen/CMakeLists.txt @@ -8,6 +8,8 @@ add_executable(autogen src/object/codegen.cpp src/data/analysis.cpp src/data/codegen.cpp + src/enum/analysis.cpp + src/enum/codegen.cpp ) set_target_properties(autogen PROPERTIES OUTPUT_NAME "autogen") diff --git a/autogen/src/enum/analysis.cpp b/autogen/src/enum/analysis.cpp new file mode 100644 index 0000000..bd85c32 --- /dev/null +++ b/autogen/src/enum/analysis.cpp @@ -0,0 +1,89 @@ +#include "analysis.h" +#include "../util.h" +#include +#include +#include +#include +#include + +using namespace enum_; + +static int findEnumEntryValue(CXCursor cur, bool* success = nullptr) { + int ret = -1; + if (success != nullptr) *success = false; + x_clang_visitChildren(cur, [&](CXCursor cur, CXCursor parent) { + CXCursorKind kind = clang_getCursorKind(cur); + + if (kind != CXCursor_IntegerLiteral) return CXChildVisit_Recurse; + + // https://stackoverflow.com/a/63859988/16255372 + auto res = clang_Cursor_Evaluate(cur); + ret = clang_EvalResult_getAsInt(res); + clang_EvalResult_dispose(res); + + if (success != nullptr) *success = true; + return CXChildVisit_Break; + }); + + return ret; +} + +static void processEnumEntry(CXCursor cur, EnumAnalysis* state, int* lastValue) { + EnumEntry anly; + + std::string name = x_clang_toString(clang_getCursorSpelling(cur)); + bool success; + int value = findEnumEntryValue(cur, &success); + + // Default to lastValue + 1 + if (!success) value = ++(*lastValue); + *lastValue = value; + + anly.name = name; + anly.value = value; + + state->entries.push_back(anly); +} + +static void processEnum(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) { + EnumAnalysis anly; + + anly.name = className; + + int lastValue = -1; + + x_clang_visitChildren(cur, [&](CXCursor cur, CXCursor parent) { + CXCursorKind kind = clang_getCursorKind(cur); + + if (kind == CXCursor_EnumConstantDecl) { + processEnumEntry(cur, &anly, &lastValue); + } + + return CXChildVisit_Continue; + }); + + state->classes[className] = anly; +} + +bool enum_::analyzeClasses(CXCursor cursor, std::string srcRoot, AnalysisState* state) { + // Search for classes + x_clang_visitChildren(cursor, [&](CXCursor cur, CXCursor parent) { + CXCursorKind kind = clang_getCursorKind(cur); + if (kind == CXCursor_Namespace) return CXChildVisit_Recurse; + if (kind != CXCursor_EnumDecl) return CXChildVisit_Continue; + + CXSourceLocation loc = clang_getCursorLocation(cur); + if (!clang_Location_isFromMainFile(loc)) return CXChildVisit_Continue; // This class is not from this header. Skip + + std::string className = x_clang_toString(clang_getCursorDisplayName(cur)); + // Forward-decls can slip through the cracks, this prevents that, but also allows us to filter non-instance classes in the src/objects directory + if (!findAnnotation(cur, "OB::def_enum")) 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... + + processEnum(cur, state, className, srcRoot); + + return CXChildVisit_Continue; + }); + + return true; +} \ No newline at end of file diff --git a/autogen/src/enum/analysis.h b/autogen/src/enum/analysis.h new file mode 100644 index 0000000..091bf53 --- /dev/null +++ b/autogen/src/enum/analysis.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include + +namespace enum_ { + +struct EnumEntry { + std::string name; + int value; +}; + +struct EnumAnalysis { + std::string name; + std::vector entries; +}; + +struct AnalysisState { + std::map classes; +}; + +bool analyzeClasses(CXCursor cursor, std::string srcRoot, AnalysisState* state); + +} \ No newline at end of file diff --git a/autogen/src/enum/codegen.cpp b/autogen/src/enum/codegen.cpp new file mode 100644 index 0000000..97e897b --- /dev/null +++ b/autogen/src/enum/codegen.cpp @@ -0,0 +1,31 @@ +#include "codegen.h" +#include "analysis.h" +#include +#include +#include +#include +#include + +using namespace enum_; + +void enum_::writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAnalysis& state) { + out << "#include \"datatypes/enum.h\"\n\n"; + + out << "static std::pair __values_" << state.name << "[] = {\n"; + + for (auto entry : state.entries) { + out << " { " << entry.value << ", \"" << entry.name << "\" },\n"; + } + + out << "};"; + + out << "static _EnumData __data_" << state.name << " = {\n" + << " \"" << state.name << "\",\n" + << " __values_" << state.name << ",\n" + << " " << state.entries.size() << "\n" + << "};\n\n"; + + out << "namespace EnumType {\n" + << " const Enum " << state.name << "(&__data_" << state.name << ");\n" + << "}\n\n"; +} \ No newline at end of file diff --git a/autogen/src/enum/codegen.h b/autogen/src/enum/codegen.h new file mode 100644 index 0000000..3d295f4 --- /dev/null +++ b/autogen/src/enum/codegen.h @@ -0,0 +1,10 @@ +#pragma once + +#include "analysis.h" +#include + +namespace enum_ { + +void writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAnalysis& state); + +} \ No newline at end of file diff --git a/autogen/src/main.cpp b/autogen/src/main.cpp index b694687..14944a5 100644 --- a/autogen/src/main.cpp +++ b/autogen/src/main.cpp @@ -6,6 +6,8 @@ #include #include #include +#include "enum/analysis.h" +#include "enum/codegen.h" #include "object/analysis.h" #include "object/codegen.h" #include "data/analysis.h" @@ -50,11 +52,13 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) { object::AnalysisState objectAnlyState; data::AnalysisState dataAnlyState; + enum_::AnalysisState enumAnlyState; fs::path relpath = fs::relative(srcPath, srcRoot); printf("[AUTOGEN] Processing file %s...\n", relpath.c_str()); object::analyzeClasses(cursor, srcRoot, &objectAnlyState); - analyzeClasses(cursor, srcRoot, &dataAnlyState); + data::analyzeClasses(cursor, srcRoot, &dataAnlyState); + enum_::analyzeClasses(cursor, srcRoot, &enumAnlyState); fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it @@ -72,7 +76,11 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) { } for (auto& [_, clazz] : dataAnlyState.classes) { - writeCodeForClass(outStream, relpath, clazz); + data::writeCodeForClass(outStream, relpath, clazz); + } + + for (auto& [_, clazz] : enumAnlyState.classes) { + enum_::writeCodeForClass(outStream, relpath, clazz); } outStream.close(); diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 4408f15..b7f9ee1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(LUAJIT REQUIRED luajit) # Run autogen -file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" "src/objects/*.h" "src/datatypes/*.h") +file(GLOB_RECURSE AUTOGEN_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src" "src/objects/*.h" "src/datatypes/*.h" "src/enum/*.h") # https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html foreach (SRC ${AUTOGEN_SOURCES}) diff --git a/core/src/datatypes/enum.h b/core/src/datatypes/enum.h index 1e976cc..0cbc8e4 100644 --- a/core/src/datatypes/enum.h +++ b/core/src/datatypes/enum.h @@ -9,8 +9,8 @@ #include "lua.h" struct _EnumData { - std::pair* values; std::string name; + std::pair* values; int count; }; diff --git a/core/src/enum/annotation.h b/core/src/enum/annotation.h new file mode 100644 index 0000000..f5299fd --- /dev/null +++ b/core/src/enum/annotation.h @@ -0,0 +1,13 @@ +#pragma once + +// Markers for the autogen engine to generate getters, setters, lua, etc. + +// Base macros +#ifdef __AUTOGEN__ +#define def_enum(...) clang::annotate("OB::def_enum", #__VA_ARGS__) +#else +#define def_enum(...) +#endif + +// Helper macros +#define DEF_ENUM [[ def_enum() ]] \ No newline at end of file diff --git a/core/src/rendering/surface.cpp b/core/src/enum/surface.cpp similarity index 100% rename from core/src/rendering/surface.cpp rename to core/src/enum/surface.cpp diff --git a/core/src/rendering/surface.h b/core/src/enum/surface.h similarity index 64% rename from core/src/rendering/surface.h rename to core/src/enum/surface.h index 0c83e3b..505c6e4 100644 --- a/core/src/rendering/surface.h +++ b/core/src/enum/surface.h @@ -1,6 +1,9 @@ #pragma once -enum NormalId { +#include "datatypes/enum.h" +#include "enum/annotation.h" + +enum DEF_ENUM NormalId { Right = 0, Top = 1, Back = 2, @@ -9,7 +12,7 @@ enum NormalId { Front = 5 }; -enum SurfaceType { +enum DEF_ENUM SurfaceType { SurfaceSmooth = 0, SurfaceGlue = 1, SurfaceWeld = 2, @@ -20,6 +23,11 @@ enum SurfaceType { SurfaceMotor = 7, }; +namespace EnumType { + extern const Enum NormalId; + extern const Enum SurfaceType; +}; + class Vector3; NormalId faceFromNormal(Vector3); Vector3 normalFromFace(NormalId); \ No newline at end of file diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index f7a842c..144568f 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -13,7 +13,7 @@ #include "objects/joint/jointinstance.h" #include "objects/joint/snap.h" #include "rendering/renderer.h" -#include "rendering/surface.h" +#include "enum/surface.h" #include #include #include diff --git a/core/src/objects/part.h b/core/src/objects/part.h index 27c7987..7237bfb 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -8,7 +8,7 @@ #include "datatypes/signal.h" #include "datatypes/vector.h" #include "objects/base/instance.h" -#include "rendering/surface.h" +#include "enum/surface.h" #include #include #include diff --git a/core/src/rendering/renderer.cpp b/core/src/rendering/renderer.cpp index 5c52920..0b25c90 100644 --- a/core/src/rendering/renderer.cpp +++ b/core/src/rendering/renderer.cpp @@ -28,7 +28,7 @@ #include "../common.h" #include "../objects/part.h" #include "skybox.h" -#include "surface.h" +#include "enum/surface.h" #include "texture3d.h" #include "renderer.h" diff --git a/editor/placedocument.cpp b/editor/placedocument.cpp index d295cf9..bebb18d 100644 --- a/editor/placedocument.cpp +++ b/editor/placedocument.cpp @@ -5,7 +5,7 @@ #include "objects/joint/snap.h" #include "objects/script.h" #include "objects/script/scriptcontext.h" -#include "rendering/surface.h" +#include "enum/surface.h" #include #include #include