feat(autogen): integrate autogen and add method for setters

This commit is contained in:
maelstrom 2025-04-26 11:04:50 +02:00
parent 8049d45b43
commit 8f20c11b36
10 changed files with 100 additions and 31 deletions

View file

@ -5,6 +5,8 @@ set(OpenGL_GL_PREFERENCE "GLVND")
set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
add_subdirectory(autogen)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )

View file

@ -211,13 +211,13 @@ void processClass(CXCursor cur, AnalysisState* state, std::string className, std
// https://clang.llvm.org/docs/LibClang.html // https://clang.llvm.org/docs/LibClang.html
bool analyzeClasses(std::string path, std::string srcRoot, AnalysisState* state) { bool analyzeClasses(std::string path, std::string srcRoot, AnalysisState* state) {
const char* cargs[] = { "-x", "c++", "-I", srcRoot.c_str(), 0 }; const char* cargs[] = { "-x", "c++", "-I", srcRoot.c_str(), "-D__AUTOGEN__", 0 };
// THANK YOU SO MUCH THIS STACKOVERFLOW ANSWER IS SO HELPFUL // THANK YOU SO MUCH THIS STACKOVERFLOW ANSWER IS SO HELPFUL
// https://stackoverflow.com/a/59206378/16255372 // https://stackoverflow.com/a/59206378/16255372
CXIndex index = clang_createIndex(0, 0); CXIndex index = clang_createIndex(0, 0);
CXTranslationUnit unit = clang_parseTranslationUnit( CXTranslationUnit unit = clang_parseTranslationUnit(
index, index,
path.c_str(), cargs, 4, path.c_str(), cargs, 5,
nullptr, 0, nullptr, 0,
CXTranslationUnit_None); CXTranslationUnit_None);

View file

@ -1,5 +1,54 @@
#include "codegen.h" #include "codegen.h"
#include "analysis.h" #include "analysis.h"
#include <map>
#include <string>
#include <variant>
std::map<std::string, std::string> MAPPED_TYPE = {
{ "bool", "Data::Bool" },
{ "int", "Data::Int" },
{ "float", "Data::Float" },
{ "std::string", "Data::String" },
{ "std::weak_ptr<Instance>", "Data::InstanceRef" },
{ "glm::vec3", "Vector3" },
};
std::map<std::string, std::monostate> ENUM_TYPES = {
{ "SurfaceType", std::monostate() }
};
std::string castFromVariant(std::string valueStr, std::string fieldType) {
// Manual exception for now, enums will get their own system eventually
if (fieldType == "SurfaceType") {
return "(SurfaceType)(int)" + valueStr + ".get<Data::Int>()";
}
std::string mappedType = MAPPED_TYPE[fieldType];
return valueStr + ".get<" + (!mappedType.empty() ? mappedType : fieldType) + ">()";
}
void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
out << "fallible<MemberNotFound, AssignToReadOnlyMember> " << state.name << "::InternalSetPropertyValue(std::string name, Data::Variant value) {";
out << "\n ";
bool first = true;
for (auto& prop : state.properties) {
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
if (prop.flags & PropertyFlag_Readonly) {
out << "\n return AssignToReadOnlyMember(\"" << state.name << "\", name)";
} else {
out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";";
}
out << "\n }";
first = false;
}
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n};\n\n";
}
void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) { void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
std::string strFlags; std::string strFlags;
@ -24,4 +73,6 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
out << "const InstanceType* " << state.name << "::GetClass() {\n" out << "const InstanceType* " << state.name << "::GetClass() {\n"
<< " return &TYPE;\n" << " return &TYPE;\n"
<< "};\n\n"; << "};\n\n";
writePropertySetHandler(out, state);
} }

View file

@ -40,17 +40,7 @@ int main(int argc, char** argv) {
AnalysisState state; AnalysisState state;
analyzeClasses("../core/src/objects/part.h", argv[1], &state); // 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) { // for (auto& [_, clazz] : state.classes) {
// printf("Class: %s\n", clazz.name.c_str()); // printf("Class: %s\n", clazz.name.c_str());
// if (clazz.baseClass != "") // if (clazz.baseClass != "")
@ -74,11 +64,21 @@ int main(int argc, char** argv) {
// } // }
// First-pass: Analyze type hierarchy // First-pass: Analyze type hierarchy
// for (std::string path : headerFiles) { for (std::string path : headerFiles) {
// fs::path relpath = fs::relative(path, argv[1]); fs::path relpath = fs::relative(path, argv[1]);
// printf("[AUTOGEN] Processing file %s...\n", relpath.c_str()); printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
// analyzeClasses(path, argv[1], &state); analyzeClasses(path, 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();
}
flushCaches(argv[3]); flushCaches(argv[3]);
} }

View file

@ -15,7 +15,12 @@ include_directories(${Stb_INCLUDE_DIR})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(LUAJIT REQUIRED luajit) pkg_check_modules(LUAJIT REQUIRED luajit)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h") # Run autogen
add_custom_target(build_autogen ALL
COMMAND "${CMAKE_BINARY_DIR}/autogen/autogen" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src/objects" "${CMAKE_BINARY_DIR}/generated"
)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h" "${CMAKE_BINARY_DIR}/generated/*.cpp")
add_library(openblocks STATIC ${SOURCES}) add_library(openblocks STATIC ${SOURCES})
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks") set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml) target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml)

View file

@ -2,9 +2,23 @@
// Markers for the autogen engine to generate getters, setters, lua, etc. // Markers for the autogen engine to generate getters, setters, lua, etc.
#ifdef __AUTOGEN__
#define def_inst(...) clang::annotate("OB::def_inst", #__VA_ARGS__) #define def_inst(...) clang::annotate("OB::def_inst", #__VA_ARGS__)
#define def_prop(...) clang::annotate("OB::def_prop", #__VA_ARGS__) #define def_prop(...) clang::annotate("OB::def_prop", #__VA_ARGS__)
#define cframe_position_prop(...) clang::annotate("OB::cframe_position_prop", #__VA_ARGS__) #define cframe_position_prop(...) clang::annotate("OB::cframe_position_prop", #__VA_ARGS__)
#define cframe_rotation_prop(...) clang::annotate("OB::cframe_rotation_prop", #__VA_ARGS__) #define cframe_rotation_prop(...) clang::annotate("OB::cframe_rotation_prop", #__VA_ARGS__)
#else
#define def_inst(...)
#define def_prop(...)
#define cframe_position_prop(...)
#define cframe_rotation_prop(...)
#endif
#define AUTOGEN_PREAMBLE \
private: \
result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name) override; \
fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value) override; \
result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
private:

View file

@ -211,6 +211,9 @@ fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std:
return {}; return {};
} }
if (InternalSetPropertyValue(name, value).isSuccess())
return {};
auto meta_ = GetPropertyMeta(name); auto meta_ = GetPropertyMeta(name);
if (!meta_) return MemberNotFound(GetClass()->className, name); if (!meta_) return MemberNotFound(GetClass()->className, name);
auto meta = meta_.expect(); auto meta = meta_.expect();

View file

@ -70,6 +70,10 @@ protected:
Instance(const InstanceType*); Instance(const InstanceType*);
virtual ~Instance(); virtual ~Instance();
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name);
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value);
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name);
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent); virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
virtual void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent); virtual void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);
virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace); virtual void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace);

View file

@ -50,17 +50,6 @@ constexpr FieldCodec cframeRotationCodec() {
}; };
} }
const InstanceType Part::TYPE = {
.super = &Instance::TYPE,
.className = "Part",
.constructor = &Part::CreateGeneric,
.explorerIcon = "part",
};
const InstanceType* Part::GetClass() {
return &TYPE;
}
Part::Part(): Part(PartConstructParams { .size = glm::vec3(2, 1.2, 4), .color = Color3(0.639216f, 0.635294f, 0.647059f) }) { Part::Part(): Part(PartConstructParams { .size = glm::vec3(2, 1.2, 4), .color = Color3(0.639216f, 0.635294f, 0.647059f) }) {
} }

View file

@ -29,6 +29,7 @@ struct PartConstructParams {
class Snap; class Snap;
class [[ def_inst(explorer_icon="part") ]] Part : public Instance { class [[ def_inst(explorer_icon="part") ]] Part : public Instance {
AUTOGEN_PREAMBLE
protected: protected:
// Joints where this part is Part0 // Joints where this part is Part0
std::vector<std::weak_ptr<JointInstance>> primaryJoints; std::vector<std::weak_ptr<JointInstance>> primaryJoints;