feat(autogen): added enums
This commit is contained in:
parent
53b1788588
commit
46856a06e2
15 changed files with 197 additions and 10 deletions
|
@ -8,6 +8,8 @@ add_executable(autogen
|
||||||
src/object/codegen.cpp
|
src/object/codegen.cpp
|
||||||
src/data/analysis.cpp
|
src/data/analysis.cpp
|
||||||
src/data/codegen.cpp
|
src/data/codegen.cpp
|
||||||
|
src/enum/analysis.cpp
|
||||||
|
src/enum/codegen.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(autogen PROPERTIES OUTPUT_NAME "autogen")
|
set_target_properties(autogen PROPERTIES OUTPUT_NAME "autogen")
|
||||||
|
|
89
autogen/src/enum/analysis.cpp
Normal file
89
autogen/src/enum/analysis.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#include "analysis.h"
|
||||||
|
#include "../util.h"
|
||||||
|
#include <clang-c/CXFile.h>
|
||||||
|
#include <clang-c/CXSourceLocation.h>
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
26
autogen/src/enum/analysis.h
Normal file
26
autogen/src/enum/analysis.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <clang-c/Index.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace enum_ {
|
||||||
|
|
||||||
|
struct EnumEntry {
|
||||||
|
std::string name;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EnumAnalysis {
|
||||||
|
std::string name;
|
||||||
|
std::vector<EnumEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnalysisState {
|
||||||
|
std::map<std::string, EnumAnalysis> classes;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool analyzeClasses(CXCursor cursor, std::string srcRoot, AnalysisState* state);
|
||||||
|
|
||||||
|
}
|
31
autogen/src/enum/codegen.cpp
Normal file
31
autogen/src/enum/codegen.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "codegen.h"
|
||||||
|
#include "analysis.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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<int, std::string> __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";
|
||||||
|
}
|
10
autogen/src/enum/codegen.h
Normal file
10
autogen/src/enum/codegen.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "analysis.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace enum_ {
|
||||||
|
|
||||||
|
void writeCodeForClass(std::ofstream& out, std::string headerPath, EnumAnalysis& state);
|
||||||
|
|
||||||
|
}
|
|
@ -6,6 +6,8 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include "enum/analysis.h"
|
||||||
|
#include "enum/codegen.h"
|
||||||
#include "object/analysis.h"
|
#include "object/analysis.h"
|
||||||
#include "object/codegen.h"
|
#include "object/codegen.h"
|
||||||
#include "data/analysis.h"
|
#include "data/analysis.h"
|
||||||
|
@ -50,11 +52,13 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
||||||
|
|
||||||
object::AnalysisState objectAnlyState;
|
object::AnalysisState objectAnlyState;
|
||||||
data::AnalysisState dataAnlyState;
|
data::AnalysisState dataAnlyState;
|
||||||
|
enum_::AnalysisState enumAnlyState;
|
||||||
|
|
||||||
fs::path relpath = fs::relative(srcPath, srcRoot);
|
fs::path relpath = fs::relative(srcPath, srcRoot);
|
||||||
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
|
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
|
||||||
object::analyzeClasses(cursor, srcRoot, &objectAnlyState);
|
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
|
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) {
|
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();
|
outStream.close();
|
||||||
|
|
|
@ -16,7 +16,7 @@ find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(LUAJIT REQUIRED luajit)
|
pkg_check_modules(LUAJIT REQUIRED luajit)
|
||||||
|
|
||||||
# Run autogen
|
# 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
|
# https://cmake.org/cmake/help/book/mastering-cmake/chapter/Custom%20Commands.html
|
||||||
foreach (SRC ${AUTOGEN_SOURCES})
|
foreach (SRC ${AUTOGEN_SOURCES})
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
struct _EnumData {
|
struct _EnumData {
|
||||||
std::pair<int, std::string>* values;
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::pair<int, std::string>* values;
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
13
core/src/enum/annotation.h
Normal file
13
core/src/enum/annotation.h
Normal file
|
@ -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() ]]
|
|
@ -1,6 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
enum NormalId {
|
#include "datatypes/enum.h"
|
||||||
|
#include "enum/annotation.h"
|
||||||
|
|
||||||
|
enum DEF_ENUM NormalId {
|
||||||
Right = 0,
|
Right = 0,
|
||||||
Top = 1,
|
Top = 1,
|
||||||
Back = 2,
|
Back = 2,
|
||||||
|
@ -9,7 +12,7 @@ enum NormalId {
|
||||||
Front = 5
|
Front = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SurfaceType {
|
enum DEF_ENUM SurfaceType {
|
||||||
SurfaceSmooth = 0,
|
SurfaceSmooth = 0,
|
||||||
SurfaceGlue = 1,
|
SurfaceGlue = 1,
|
||||||
SurfaceWeld = 2,
|
SurfaceWeld = 2,
|
||||||
|
@ -20,6 +23,11 @@ enum SurfaceType {
|
||||||
SurfaceMotor = 7,
|
SurfaceMotor = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace EnumType {
|
||||||
|
extern const Enum NormalId;
|
||||||
|
extern const Enum SurfaceType;
|
||||||
|
};
|
||||||
|
|
||||||
class Vector3;
|
class Vector3;
|
||||||
NormalId faceFromNormal(Vector3);
|
NormalId faceFromNormal(Vector3);
|
||||||
Vector3 normalFromFace(NormalId);
|
Vector3 normalFromFace(NormalId);
|
|
@ -13,7 +13,7 @@
|
||||||
#include "objects/joint/jointinstance.h"
|
#include "objects/joint/jointinstance.h"
|
||||||
#include "objects/joint/snap.h"
|
#include "objects/joint/snap.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "rendering/surface.h"
|
#include "enum/surface.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "datatypes/signal.h"
|
#include "datatypes/signal.h"
|
||||||
#include "datatypes/vector.h"
|
#include "datatypes/vector.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
#include "rendering/surface.h"
|
#include "enum/surface.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <reactphysics3d/reactphysics3d.h>
|
#include <reactphysics3d/reactphysics3d.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
#include "../objects/part.h"
|
#include "../objects/part.h"
|
||||||
#include "skybox.h"
|
#include "skybox.h"
|
||||||
#include "surface.h"
|
#include "enum/surface.h"
|
||||||
#include "texture3d.h"
|
#include "texture3d.h"
|
||||||
|
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "objects/joint/snap.h"
|
#include "objects/joint/snap.h"
|
||||||
#include "objects/script.h"
|
#include "objects/script.h"
|
||||||
#include "objects/script/scriptcontext.h"
|
#include "objects/script/scriptcontext.h"
|
||||||
#include "rendering/surface.h"
|
#include "enum/surface.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <qboxlayout.h>
|
#include <qboxlayout.h>
|
||||||
|
|
Loading…
Add table
Reference in a new issue