From f5727f3b03f3b71ed2dbb5f13d1e08bb53ea46bc Mon Sep 17 00:00:00 2001 From: maelstrom Date: Sun, 4 May 2025 19:04:37 +0200 Subject: [PATCH] feat(autogen): implement tostring and miscellania --- autogen/src/data/analysis.cpp | 8 +++ autogen/src/data/analysis.h | 2 + autogen/src/data/codegen.cpp | 26 ++++++-- core/src/datatypes/annotation.h | 2 + core/src/datatypes/cframe.cpp | 11 ---- core/src/datatypes/cframe.h | 13 ++-- core/src/datatypes/color3.cpp | 12 ---- core/src/datatypes/color3.h | 6 +- core/src/datatypes/vector.cpp | 103 -------------------------------- core/src/datatypes/vector.h | 8 +-- 10 files changed, 44 insertions(+), 147 deletions(-) diff --git a/autogen/src/data/analysis.cpp b/autogen/src/data/analysis.cpp index 32aec43..5a73d44 100644 --- a/autogen/src/data/analysis.cpp +++ b/autogen/src/data/analysis.cpp @@ -83,7 +83,15 @@ static void processProperty(CXCursor cur, ClassAnalysis* state) { static void processClass(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) { ClassAnalysis anly; + std::string propertyDef = findAnnotation(cur, "OB::def_data").value(); + auto result = parseAnnotationString(propertyDef); + anly.name = className; + anly.serializedName = result["name"]; + anly.hasFromString = result.count("from_string") > 0; + + if (anly.serializedName == "") + anly.serializedName = className; x_clang_visitChildren(cur, [&](CXCursor cur, CXCursor parent) { CXCursorKind kind = clang_getCursorKind(cur); diff --git a/autogen/src/data/analysis.h b/autogen/src/data/analysis.h index bb55c43..2e2c5b2 100644 --- a/autogen/src/data/analysis.h +++ b/autogen/src/data/analysis.h @@ -33,7 +33,9 @@ struct MethodAnalysis { struct ClassAnalysis { std::string name; + std::string serializedName; std::string headerPath; + bool hasFromString = false; std::vector properties; std::vector methods; std::vector staticProperties; diff --git a/autogen/src/data/codegen.cpp b/autogen/src/data/codegen.cpp index ca95a9b..c356228 100644 --- a/autogen/src/data/codegen.cpp +++ b/autogen/src/data/codegen.cpp @@ -130,9 +130,11 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) { out << "static int data_gc(lua_State*);\n" "static int data_index(lua_State*);\n" + "static int data_tostring(lua_State*);\n" "static const struct luaL_Reg metatable [] = {\n" " {\"__gc\", data_gc},\n" " {\"__index\", data_index},\n" + " {\"__tostring\", data_tostring},\n" " {NULL, NULL} /* end of array */\n" "};\n\n"; @@ -152,6 +154,14 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) { " lua_setmetatable(L, n+1);\n" "}\n\n"; + + out << "result Data::" << state.name << "::FromLuaValue(lua_State* L, int idx) {\n" + " " << fqn << "* userdata = (" << fqn << "*) luaL_testudata(L, idx, \"" << getMtName(state.name) << "\");\n" + " if (userdata == nullptr)\n" + " return LuaCastError(lua_typename(L, idx), \"" << state.name << "\");\n" + " return Data::Variant(*userdata);\n" + "}\n\n"; + // Indexing methods and properties out << "static int data_index(lua_State* L) {\n" @@ -206,6 +216,14 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) { " return luaL_error(L, \"%s is not a valid member of %s\\n\", key.c_str(), \"" << state.name << "\");\n" "}\n\n"; + // ToString + + out << "\nint data_tostring(lua_State* L) {\n" + " auto this_ = (" << fqn << "*)lua_touserdata(L, 1);\n" + " lua_pushstring(L, std::string(this_->ToString()).c_str());\n" + " return 1;\n" + "}\n\n"; + // Destructor out << "\nint data_gc(lua_State* L) {\n" @@ -215,7 +233,6 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) { "}\n\n"; } - void data::writeCodeForClass(std::ofstream& out, std::string headerPath, ClassAnalysis& state) { std::string fqn = "Data::" + state.name; @@ -224,9 +241,10 @@ void data::writeCodeForClass(std::ofstream& out, std::string headerPath, ClassAn out << "#include \"datatypes/meta.h\"\n"; out << "#include \"lua.h\"\n\n"; out << "const Data::TypeInfo " << fqn << "::TYPE = {\n" - << " .name = \"" << fqn << "\",\n" - << " .deserializer = &" << fqn << "::Deserialize,\n" - << " .fromLuaValue = &" << fqn << "::FromLuaValue,\n" + << " .name = \"" << state.serializedName << "\",\n" + << " .deserializer = &" << fqn << "::Deserialize,\n"; + if (state.hasFromString) out << " .fromString = &" << fqn << "::FromString,\n"; + out << " .fromLuaValue = &" << fqn << "::FromLuaValue,\n" << "};\n\n"; out << "const Data::TypeInfo& " << fqn << "::GetType() const {\n" diff --git a/core/src/datatypes/annotation.h b/core/src/datatypes/annotation.h index 2e3f1f3..ff5b760 100644 --- a/core/src/datatypes/annotation.h +++ b/core/src/datatypes/annotation.h @@ -18,6 +18,7 @@ // Helper macros #define DEF_DATA [[ def_data() ]] // Data declaration +#define DEF_DATA_(...) [[ def_data(__VA_ARGS__) ]] #define DEF_DATA_PROP [[ def_data_prop() ]] // Property. Getter or field #define DEF_DATA_METHOD [[ def_data_method() ]] // Method #define DEF_DATA_CTOR [[ def_data_ctor() ]] // Constructor (i.e. .new) @@ -28,4 +29,5 @@ public: \ virtual const TypeInfo& GetType() const override; \ static const TypeInfo TYPE; \ virtual void PushLuaValue(lua_State*) const override; \ +static result FromLuaValue(lua_State*, int idx); \ private: diff --git a/core/src/datatypes/cframe.cpp b/core/src/datatypes/cframe.cpp index 66297db..031c683 100644 --- a/core/src/datatypes/cframe.cpp +++ b/core/src/datatypes/cframe.cpp @@ -56,12 +56,6 @@ Data::CFrame::CFrame(Vector3 position, Vector3 lookAt, Vector3 up) } Data::CFrame::~CFrame() = default; -const Data::TypeInfo Data::CFrame::TYPE = { - .name = "CoordinateFrame", - .deserializer = &Data::CFrame::Deserialize, -}; - -const Data::TypeInfo& Data::CFrame::GetType() const { return Vector3::TYPE; }; const Data::String Data::CFrame::ToString() const { return std::to_string(X()) + ", " + std::to_string(Y()) + ", " + std::to_string(Z()); @@ -149,9 +143,4 @@ Data::Variant Data::CFrame::Deserialize(pugi::xml_node node) { node.child("R21").text().as_float(), node.child("R22").text().as_float() ); -} - -void Data::CFrame::PushLuaValue(lua_State* L) const { - // TODO: - panic(); } \ No newline at end of file diff --git a/core/src/datatypes/cframe.h b/core/src/datatypes/cframe.h index 392213a..4de284b 100644 --- a/core/src/datatypes/cframe.h +++ b/core/src/datatypes/cframe.h @@ -1,6 +1,7 @@ #pragma once #include "base.h" +#include "datatypes/annotation.h" #include "datatypes/vector.h" #include #include @@ -11,7 +12,9 @@ namespace rp = reactphysics3d; namespace Data { - class DEF_DATA CFrame : public Base { + class DEF_DATA_(name="CoordinateFrame") CFrame : public Base { + AUTOGEN_PREAMBLE_DATA + glm::vec3 translation; glm::mat3 rotation; @@ -33,22 +36,18 @@ namespace Data { DEF_DATA_PROP static const CFrame IDENTITY; static const CFrame YToZ; - virtual const TypeInfo& GetType() const override; - static const TypeInfo TYPE; - virtual const Data::String ToString() const override; virtual void Serialize(pugi::xml_node parent) const override; static Data::Variant Deserialize(pugi::xml_node node); - virtual void PushLuaValue(lua_State*) const override; static void PushLuaLibrary(lua_State*); operator glm::mat4() const; operator rp::Transform() const; //inline static CFrame identity() { } - DEF_DATA_METHOD inline Vector3 Position() const { return translation; } - DEF_DATA_METHOD inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; } + DEF_DATA_PROP inline Vector3 Position() const { return translation; } + DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; } DEF_DATA_METHOD CFrame Inverse() const; DEF_DATA_PROP inline float X() const { return translation.x; } DEF_DATA_PROP inline float Y() const { return translation.y; } diff --git a/core/src/datatypes/color3.cpp b/core/src/datatypes/color3.cpp index f0c9bb7..8c2d155 100644 --- a/core/src/datatypes/color3.cpp +++ b/core/src/datatypes/color3.cpp @@ -6,12 +6,6 @@ Data::Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g( Data::Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {}; Data::Color3::~Color3() = default; -const Data::TypeInfo Data::Color3::TYPE = { - .name = "Color3", - .deserializer = &Data::Color3::Deserialize, -}; - -const Data::TypeInfo& Data::Color3::GetType() const { return Data::Color3::TYPE; }; const Data::String Data::Color3::ToString() const { return std::to_string(int(r*256)) + ", " + std::to_string(int(g*256)) + ", " + std::to_string(int(b*256)); @@ -45,10 +39,4 @@ void Data::Color3::Serialize(pugi::xml_node node) const { Data::Variant Data::Color3::Deserialize(pugi::xml_node node) { return Color3::FromHex(node.text().get()); -} - - -void Data::Color3::PushLuaValue(lua_State* L) const { - // TODO: - panic(); } \ No newline at end of file diff --git a/core/src/datatypes/color3.h b/core/src/datatypes/color3.h index 14e36e0..c240345 100644 --- a/core/src/datatypes/color3.h +++ b/core/src/datatypes/color3.h @@ -8,6 +8,8 @@ namespace Data { class DEF_DATA Color3 : public Base { + AUTOGEN_PREAMBLE_DATA + float r; float g; float b; @@ -19,15 +21,11 @@ namespace Data { DEF_DATA_METHOD static Color3 FromHex(std::string hex); - virtual const TypeInfo& GetType() const override; - static const TypeInfo TYPE; - virtual const Data::String ToString() const override; DEF_DATA_METHOD std::string ToHex() const; virtual void Serialize(pugi::xml_node node) const override; static Data::Variant Deserialize(pugi::xml_node node); - virtual void PushLuaValue(lua_State*) const override; static void PushLuaLibrary(lua_State*); operator glm::vec3() const; diff --git a/core/src/datatypes/vector.cpp b/core/src/datatypes/vector.cpp index 7bd8fa7..5acff69 100644 --- a/core/src/datatypes/vector.cpp +++ b/core/src/datatypes/vector.cpp @@ -12,13 +12,6 @@ Data::Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, Data::Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {}; Data::Vector3::~Vector3() = default; -const Data::TypeInfo Data::Vector3::TYPE = { - .name = "Vector3", - .deserializer = &Data::Vector3::Deserialize, - .fromString = &Data::Vector3::FromString, -}; - -const Data::TypeInfo& Data::Vector3::GetType() const { return Data::Vector3::TYPE; }; Data::Vector3 Data::Vector3::ZERO(0, 0, 0); Data::Vector3 Data::Vector3::ONE(1, 1, 1); @@ -111,100 +104,4 @@ std::optional Data::Vector3::FromString(std::string string) { } return Data::Vector3(components[0], components[1], components[2]); -} - -// Lua (TEMPORARY) -#include "lua.h" - -static int lib_index(lua_State*); -static const struct luaL_Reg lib_metatable [] = { - {"__index", lib_index}, - {NULL, NULL} /* end of array */ -}; - -static int lib_index(lua_State* L) { - std::string key(lua_tostring(L, 2)); - lua_pop(L, 2); - - if (key == "test") { - Data::String("mabaref").PushLuaValue(L); - return 1; - } - - return luaL_error(L, "%s is not a valid member of %s\n", key.c_str(), "Vector3"); -} - -static int data_index(lua_State*); -static const struct luaL_Reg metatable [] = { - {"__index", data_index}, - {NULL, NULL} /* end of array */ -}; - -static int data_index(lua_State* L) { - auto this__ = (Data::Base*)lua_touserdata(L, 1); - this__->GetType(); - if (&this__->GetType() != &Vector3::TYPE) return luaL_typerror(L, 0, "Vector3"); - Vector3* this_ = (Vector3*)this__; - - std::string key(lua_tostring(L, 2)); - lua_pop(L, 2); - - if (key == "X") { - Data::Float(this_->X()).PushLuaValue(L); - return 1; - } else if (key == "Magnitude") { - lua_pushcfunction(L, [](lua_State* L) { - auto this__ = (Data::Base*)lua_touserdata(L, 1); - if (&this__->GetType() != &Vector3::TYPE) return luaL_typerror(L, 0, "Vector3"); - Vector3* this_ = (Vector3*)this__; - - Data::Float(this_->Magnitude()).PushLuaValue(L); - return 1; - }); - return 1; - } else if (key == "Dot") { - lua_pushcfunction(L, [](lua_State* L) { - auto this__ = (Data::Base*)lua_touserdata(L, 1); - if (&this__->GetType() != &Vector3::TYPE) return luaL_typerror(L, 0, "Vector3"); - Vector3* this_ = (Vector3*)this__; - - auto arg0_ = (Data::Base*)lua_touserdata(L, 2); - if (&arg0_->GetType() != &Vector3::TYPE) return luaL_typerror(L, 1, "Vector3"); - Vector3* arg0 = (Vector3*)arg0_; - - Data::Float(this_->Dot(*arg0)).PushLuaValue(L); - return 1; - }); - return 1; - } - - return luaL_error(L, "%s is not a valid member of %s\n", key.c_str(), "Vector3"); -} - -void Data::Vector3::PushLuaLibrary(lua_State* L) { - int n = lua_gettop(L); - - lua_newuserdata(L, 0); - - // Create the library's metatable - luaL_newmetatable(L, "__mt_lib_Vector3"); - luaL_register(L, NULL, lib_metatable); - - lua_setmetatable(L, n+1); -} - -void Data::Vector3::PushLuaValue(lua_State* L) const { - int n = lua_gettop(L); - - // I'm torn... should this be Data::Variant, or Data::Base? - // If I ever decouple typing from Data::Base, I'll switch it to variant, - // otherwise, it doesn't make much sense to represent it as one - Vector3* userdata = (Vector3*)lua_newuserdata(L, sizeof(Vector3)); - new(userdata) Vector3(*this); - - // Create the library's metatable - luaL_newmetatable(L, "__mt_Vector3"); - luaL_register(L, NULL, metatable); - - lua_setmetatable(L, n+1); } \ No newline at end of file diff --git a/core/src/datatypes/vector.h b/core/src/datatypes/vector.h index 47b4269..dc08469 100644 --- a/core/src/datatypes/vector.h +++ b/core/src/datatypes/vector.h @@ -9,7 +9,8 @@ namespace rp = reactphysics3d; namespace Data { - class DEF_DATA Vector3 : public Base { + class DEF_DATA_(from_string) Vector3 : public Base { + AUTOGEN_PREAMBLE_DATA glm::vec3 vector; public: @@ -19,9 +20,6 @@ namespace Data { DEF_DATA_CTOR Vector3(const rp::Vector3&); ~Vector3(); - virtual const TypeInfo& GetType() const override; - static const TypeInfo TYPE; - DEF_DATA_PROP static Data::Vector3 ZERO; DEF_DATA_PROP static Data::Vector3 ONE; @@ -31,8 +29,6 @@ namespace Data { static Data::Variant Deserialize(pugi::xml_node node); static std::optional FromString(std::string); - static result FromLuaValue(lua_State*, int idx); - virtual void PushLuaValue(lua_State*) const override; static void PushLuaLibrary(lua_State*); operator glm::vec3() const;