diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bebd26..8713c74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ set(OpenGL_GL_PREFERENCE "GLVND") set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) +add_subdirectory(autogen) + set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) diff --git a/autogen/src/analysis.cpp b/autogen/src/analysis.cpp index 2a5da85..45cc3a1 100644 --- a/autogen/src/analysis.cpp +++ b/autogen/src/analysis.cpp @@ -211,13 +211,13 @@ void processClass(CXCursor cur, AnalysisState* state, std::string className, std // https://clang.llvm.org/docs/LibClang.html 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 // https://stackoverflow.com/a/59206378/16255372 CXIndex index = clang_createIndex(0, 0); CXTranslationUnit unit = clang_parseTranslationUnit( index, - path.c_str(), cargs, 4, + path.c_str(), cargs, 5, nullptr, 0, CXTranslationUnit_None); diff --git a/autogen/src/codegen.cpp b/autogen/src/codegen.cpp index 9a04598..21157ab 100644 --- a/autogen/src/codegen.cpp +++ b/autogen/src/codegen.cpp @@ -1,5 +1,54 @@ #include "codegen.h" #include "analysis.h" +#include +#include +#include + +std::map MAPPED_TYPE = { + { "bool", "Data::Bool" }, + { "int", "Data::Int" }, + { "float", "Data::Float" }, + { "std::string", "Data::String" }, + { "std::weak_ptr", "Data::InstanceRef" }, + { "glm::vec3", "Vector3" }, +}; + +std::map 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()"; + } + + std::string mappedType = MAPPED_TYPE[fieldType]; + return valueStr + ".get<" + (!mappedType.empty() ? mappedType : fieldType) + ">()"; +} + +void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) { + out << "fallible " << 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) { std::string strFlags; @@ -24,4 +73,6 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) { out << "const InstanceType* " << state.name << "::GetClass() {\n" << " return &TYPE;\n" << "};\n\n"; + + writePropertySetHandler(out, state); } \ No newline at end of file diff --git a/autogen/src/main.cpp b/autogen/src/main.cpp index d430785..6439db9 100644 --- a/autogen/src/main.cpp +++ b/autogen/src/main.cpp @@ -40,17 +40,7 @@ int main(int argc, char** argv) { AnalysisState 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(); - } - + // analyzeClasses("../core/src/objects/part.h", argv[1], &state); // for (auto& [_, clazz] : state.classes) { // printf("Class: %s\n", clazz.name.c_str()); // if (clazz.baseClass != "") @@ -74,11 +64,21 @@ int main(int argc, char** argv) { // } // First-pass: Analyze type hierarchy - // for (std::string path : headerFiles) { - // fs::path relpath = fs::relative(path, argv[1]); - // printf("[AUTOGEN] Processing file %s...\n", relpath.c_str()); - // analyzeClasses(path, argv[1], &state); - // } + for (std::string path : headerFiles) { + fs::path relpath = fs::relative(path, argv[1]); + printf("[AUTOGEN] Processing file %s...\n", relpath.c_str()); + 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]); } \ No newline at end of file diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index d9efe80..5e2f6b1 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -15,7 +15,12 @@ include_directories(${Stb_INCLUDE_DIR}) find_package(PkgConfig REQUIRED) 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}) set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks") target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml) diff --git a/core/src/objects/annotation.h b/core/src/objects/annotation.h index 1b7303f..be7e8b7 100644 --- a/core/src/objects/annotation.h +++ b/core/src/objects/annotation.h @@ -2,9 +2,23 @@ // 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_prop(...) clang::annotate("OB::def_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__) \ No newline at end of file +#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 InternalGetPropertyMeta(std::string name) override; \ +fallible InternalSetPropertyValue(std::string name, Data::Variant value) override; \ +result InternalGetPropertyValue(std::string name) override; \ +private: diff --git a/core/src/objects/base/instance.cpp b/core/src/objects/base/instance.cpp index 2bac961..6f750af 100644 --- a/core/src/objects/base/instance.cpp +++ b/core/src/objects/base/instance.cpp @@ -211,6 +211,9 @@ fallible Instance::SetPropertyValue(std: return {}; } + if (InternalSetPropertyValue(name, value).isSuccess()) + return {}; + auto meta_ = GetPropertyMeta(name); if (!meta_) return MemberNotFound(GetClass()->className, name); auto meta = meta_.expect(); diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 44fda8c..0fcb997 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -70,6 +70,10 @@ protected: Instance(const InstanceType*); virtual ~Instance(); + virtual result InternalGetPropertyValue(std::string name); + virtual fallible InternalSetPropertyValue(std::string name, Data::Variant value); + virtual result InternalGetPropertyMeta(std::string name); + virtual void OnParentUpdated(std::optional> oldParent, std::optional> newParent); virtual void OnAncestryChanged(std::optional> child, std::optional> newParent); virtual void OnWorkspaceAdded(std::optional> oldWorkspace, std::shared_ptr newWorkspace); diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 4a6fc38..3fc00a4 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -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) }) { } diff --git a/core/src/objects/part.h b/core/src/objects/part.h index aa70932..131fc5d 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -29,6 +29,7 @@ struct PartConstructParams { class Snap; class [[ def_inst(explorer_icon="part") ]] Part : public Instance { + AUTOGEN_PREAMBLE protected: // Joints where this part is Part0 std::vector> primaryJoints;