feat(autogen): implement tostring and miscellania

This commit is contained in:
maelstrom 2025-05-04 19:04:37 +02:00
parent 49dfeec18c
commit f5727f3b03
10 changed files with 44 additions and 147 deletions

View file

@ -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);

View file

@ -33,7 +33,9 @@ struct MethodAnalysis {
struct ClassAnalysis {
std::string name;
std::string serializedName;
std::string headerPath;
bool hasFromString = false;
std::vector<PropertyAnalysis> properties;
std::vector<MethodAnalysis> methods;
std::vector<PropertyAnalysis> staticProperties;

View file

@ -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::Variant, LuaCastError> 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"

View file

@ -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<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \
private:

View file

@ -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();
}

View file

@ -1,6 +1,7 @@
#pragma once
#include "base.h"
#include "datatypes/annotation.h"
#include "datatypes/vector.h"
#include <glm/ext/quaternion_float.hpp>
#include <glm/gtc/matrix_access.hpp>
@ -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; }

View file

@ -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();
}

View file

@ -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;

View file

@ -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::Variant> 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);
}

View file

@ -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<Data::Variant> FromString(std::string);
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
virtual void PushLuaValue(lua_State*) const override;
static void PushLuaLibrary(lua_State*);
operator glm::vec3() const;