feat(autogen): added operators to data types

This commit is contained in:
maelstrom 2025-06-13 09:55:02 +02:00
parent 8c6f038b9f
commit 70b164ddc2
14 changed files with 164 additions and 8 deletions

View file

@ -121,6 +121,33 @@ static void processMethod(CXCursor cur, ClassAnalysis* state) {
state->methods.push_back(anly); state->methods.push_back(anly);
} }
static void processOperator(CXCursor cur, ClassAnalysis* state) {
std::optional<std::string> operatorDef = findAnnotation(cur, "OB::def_data_op");
if (!operatorDef) return;
OperatorAnalysis anly;
std::string symbolName = x_clang_toString(clang_getCursorSpelling(cur));
if (!symbolName.starts_with("operator"))
return;
std::string opName = symbolName.substr(8);
// Special case: Unary minus gets its own type
if (clang_Cursor_getNumArguments(cur) == 0)
opName = "-()";
anly.type = opName;
if (clang_Cursor_getNumArguments(cur) != 0) {
CXCursor arg = clang_Cursor_getArgument(cur, 0);
CXType type = clang_getCursorType(arg);
anly.param_type = x_clang_toString(clang_getTypeSpelling(type));
}
state->operators[opName].push_back(anly);
}
// This processes both methods and fields // This processes both methods and fields
static void processProperty(CXCursor cur, ClassAnalysis* state) { static void processProperty(CXCursor cur, ClassAnalysis* state) {
std::optional<std::string> propertyDef = findAnnotation(cur, "OB::def_data_prop"); std::optional<std::string> propertyDef = findAnnotation(cur, "OB::def_data_prop");
@ -219,6 +246,7 @@ static void processClass(CXCursor cur, AnalysisState* state, std::string classNa
if (kind == CXCursor_CXXMethod) { if (kind == CXCursor_CXXMethod) {
processMethod(cur, &anly); processMethod(cur, &anly);
processOperator(cur, &anly);
} }
return CXChildVisit_Continue; return CXChildVisit_Continue;

View file

@ -19,6 +19,11 @@ struct PropertyAnalysis {
std::string valueType; std::string valueType;
}; };
struct OperatorAnalysis {
std::string type;
std::string param_type;
};
struct MethodParameter { struct MethodParameter {
std::string name; std::string name;
std::string type; std::string type;
@ -43,6 +48,7 @@ struct ClassAnalysis {
std::vector<MethodAnalysis> methods; std::vector<MethodAnalysis> methods;
std::vector<PropertyAnalysis> staticProperties; std::vector<PropertyAnalysis> staticProperties;
std::vector<MethodAnalysis> staticMethods; std::vector<MethodAnalysis> staticMethods;
std::map<std::string, std::vector<OperatorAnalysis>> operators;
}; };
struct AnalysisState { struct AnalysisState {

View file

@ -33,6 +33,17 @@ static std::map<std::string, std::string> LUA_PUSH_FUNCS = {
// { "std::string", "lua_pushstring" }, // { "std::string", "lua_pushstring" },
}; };
static std::map<std::string, std::string> LUA_OP_NAME = {
{ "==", "__eq" },
{ "<", "__lt" },
{ "<=", "__le" },
{ "+", "__add" },
{ "-", "__sub" },
{ "-()", "__unm" },
{ "*", "__mul" },
{ "/", "__div" },
};
static std::string getLuaMethodFqn(std::string className, std::string methodName) { static std::string getLuaMethodFqn(std::string className, std::string methodName) {
return "__lua_impl__" + className + "__" + methodName; return "__lua_impl__" + className + "__" + methodName;
} }
@ -237,14 +248,27 @@ static void writeLuaMethodImpls(std::ofstream& out, ClassAnalysis& state) {
static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) { static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = state.name; std::string fqn = state.name;
// Insert additional operators
for (auto& [key, ops] : state.operators) {
std::string opname = LUA_OP_NAME[key];
out << "static int data_" << state.name << opname << "(lua_State*);\n";
}
out << "static int data_" << state.name << "_gc(lua_State*);\n" out << "static int data_" << state.name << "_gc(lua_State*);\n"
"static int data_" << state.name << "_index(lua_State*);\n" "static int data_" << state.name << "_index(lua_State*);\n"
"static int data_" << state.name << "_tostring(lua_State*);\n" "static int data_" << state.name << "_tostring(lua_State*);\n"
"static const struct luaL_Reg " << state.name << "_metatable [] = {\n" "static const struct luaL_Reg " << state.name << "_metatable [] = {\n"
" {\"__gc\", data_" << state.name << "_gc},\n" " {\"__gc\", data_" << state.name << "_gc},\n"
" {\"__index\", data_" << state.name << "_index},\n" " {\"__index\", data_" << state.name << "_index},\n"
" {\"__tostring\", data_" << state.name << "_tostring},\n" " {\"__tostring\", data_" << state.name << "_tostring},\n";
" {NULL, NULL} /* end of array */\n"
// Insert additional operators
for (auto& [key, ops] : state.operators) {
std::string opname = LUA_OP_NAME[key];
out << " {\"" + opname + "\", data_" << state.name << opname << "},\n";
}
out << " {NULL, NULL} /* end of array */\n"
"};\n\n"; "};\n\n";
out << "void " << state.name << "::PushLuaValue(lua_State* L) const {\n" out << "void " << state.name << "::PushLuaValue(lua_State* L) const {\n"
@ -337,6 +361,55 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
"}\n\n"; "}\n\n";
} }
static void writeLuaOperatorImpls(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = "" + state.name;
for (auto& [name, ops] : state.operators) {
out << "static int data_" << state.name << LUA_OP_NAME[name] << "(lua_State* L) {\n"
" " << fqn << "* this_ = *(" << fqn << "**)luaL_checkudata(L, 1, \"__mt_" << state.name << "\");\n"
" int n = lua_gettop(L);\n";
out << " ";
// Support multiple overloads of the same function
bool first = true;
for (OperatorAnalysis op : ops) {
if (!first) out << " else ";
first = false;
// Check to see if the arguments possibly match this implementation's parameter types
out << "if (";
// Check number of arguments
out << "n == " << std::to_string(name == "-()" ? 2 : op.param_type == "" ? 1 : 2); // Account for first argument as 'this'
if (op.param_type != "") {
out << " && ";
writeLuaTestArgument(out, op.param_type, 0, true);
}
out << ") {\n"; // End if condition, start if body
if (op.param_type != "") {
writeLuaGetArgument(out, op.param_type, 0, true);
}
if (name == "-()") {
out << " Variant(-*this_).PushLuaValue(L);\n";
} else {
out << " Variant(*this_ " << name << " arg0).PushLuaValue(L);\n";
}
out << " return 1;\n"
" }";
}
// No function implementation matched
out << "\n\n return luaL_error(L, \"Cannot apply '" << name << "' to values of type " << state.name << " and %s \", x_luaL_udatatname(L, 2));\n";
out << "}\n\n"; // End function
}
}
static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) { static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = state.name; std::string fqn = state.name;
@ -451,5 +524,6 @@ void data::writeCodeForClass(std::ofstream& out, std::string headerPath, ClassAn
writeLuaMethodImpls(out, state); writeLuaMethodImpls(out, state);
writeLuaValueGenerator(out, state); writeLuaValueGenerator(out, state);
writeLuaOperatorImpls(out, state);
writeLuaLibraryGenerator(out, state); writeLuaLibraryGenerator(out, state);
} }

View file

@ -8,6 +8,7 @@
#define def_data_prop(...) clang::annotate("OB::def_data_prop", #__VA_ARGS__) #define def_data_prop(...) clang::annotate("OB::def_data_prop", #__VA_ARGS__)
#define def_data_method(...) clang::annotate("OB::def_data_method", #__VA_ARGS__) #define def_data_method(...) clang::annotate("OB::def_data_method", #__VA_ARGS__)
#define def_data_ctor(...) clang::annotate("OB::def_data_ctor", #__VA_ARGS__) #define def_data_ctor(...) clang::annotate("OB::def_data_ctor", #__VA_ARGS__)
#define def_data_op(...) clang::annotate("OB::def_data_op", #__VA_ARGS__)
#else #else
#define def_data(...) #define def_data(...)
#define def_data_prop(...) #define def_data_prop(...)

View file

@ -117,6 +117,10 @@ CFrame CFrame::operator -(Vector3 vector) const {
return *this + -vector; return *this + -vector;
} }
bool CFrame::operator ==(CFrame other) const {
return this->Position() == other.Position() && this->rotation == other.rotation;
}
// Serialization // Serialization
void CFrame::Serialize(pugi::xml_node node) const { void CFrame::Serialize(pugi::xml_node node) const {

View file

@ -72,4 +72,6 @@ public:
inline CFrame operator *=(CFrame otherFrame) { return *this = *this * otherFrame; } inline CFrame operator *=(CFrame otherFrame) { return *this = *this * otherFrame; }
inline CFrame operator +=(Vector3 offset) { return *this = *this + offset; } inline CFrame operator +=(Vector3 offset) { return *this = *this + offset; }
inline CFrame operator -=(Vector3 offset) { return *this = *this - offset; } inline CFrame operator -=(Vector3 offset) { return *this = *this - offset; }
DEF_DATA_OP bool operator ==(CFrame) const;
}; };

View file

@ -35,6 +35,10 @@ Color3 Color3::FromHex(std::string hex) {
return Color3(r, g, b); return Color3(r, g, b);
} }
bool Color3::operator ==(Color3 other) const {
return this->r == other.r && this->g == other.g && this->b == other.b;
}
// Serialization // Serialization
void Color3::Serialize(pugi::xml_node node) const { void Color3::Serialize(pugi::xml_node node) const {

View file

@ -31,4 +31,6 @@ public:
DEF_DATA_PROP inline float R() const { return r; } DEF_DATA_PROP inline float R() const { return r; }
DEF_DATA_PROP inline float G() const { return g; } DEF_DATA_PROP inline float G() const { return g; }
DEF_DATA_PROP inline float B() const { return b; } DEF_DATA_PROP inline float B() const { return b; }
DEF_DATA_OP bool operator ==(Color3) const;
}; };

View file

@ -40,16 +40,18 @@ EnumItem Enum::FromValueInternal(int value) const {
return result.value(); return result.value();
} }
EnumItem::EnumItem(_EnumData* parentData, std::string name, int value) : parentData(parentData), name(name), value(value) {}
//
std::string Enum::ToString() const { std::string Enum::ToString() const {
return "Enum." + this->data->name; return "Enum." + this->data->name;
} }
bool Enum::operator ==(Enum other) const {
return this->data == other.data;
}
// //
EnumItem::EnumItem(_EnumData* parentData, std::string name, int value) : parentData(parentData), name(name), value(value) {}
std::string EnumItem::ToString() const { std::string EnumItem::ToString() const {
return "Enum." + parentData->name + "." + name; return "Enum." + parentData->name + "." + name;
} }
@ -69,4 +71,8 @@ result<EnumItem, DataParseError> EnumItem::FromString(std::string string, const
auto result = info.enum_->FromName(string); auto result = info.enum_->FromName(string);
if (result.has_value()) return result.value(); if (result.has_value()) return result.value();
return DataParseError(string, "EnumItem"); return DataParseError(string, "EnumItem");
}
bool EnumItem::operator ==(EnumItem other) const {
return this->parentData == other.parentData && this->value == other.value;
} }

View file

@ -31,6 +31,8 @@ public:
EnumItem FromValueInternal(int) const; EnumItem FromValueInternal(int) const;
DEF_DATA_OP bool operator ==(Enum) const;
std::string ToString() const; std::string ToString() const;
void PushLuaValue(lua_State*) const; void PushLuaValue(lua_State*) const;
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int); static result<Variant, LuaCastError> FromLuaValue(lua_State*, int);
@ -50,6 +52,8 @@ public:
inline int Value() const { return this->value; } inline int Value() const { return this->value; }
inline Enum EnumType() const { return Enum(this->parentData); } inline Enum EnumType() const { return Enum(this->parentData); }
DEF_DATA_OP bool operator ==(EnumItem) const;
static result<EnumItem, DataParseError> FromString(std::string, const TypeMeta); static result<EnumItem, DataParseError> FromString(std::string, const TypeMeta);
std::string ToString() const; std::string ToString() const;
void Serialize(pugi::xml_node) const; void Serialize(pugi::xml_node) const;

View file

@ -117,6 +117,8 @@ public:
operator std::weak_ptr<Signal>(); operator std::weak_ptr<Signal>();
DEF_DATA_OP bool operator ==(SignalRef) const;
virtual const std::string ToString() const; virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const; virtual void Serialize(pugi::xml_node node) const;
virtual void PushLuaValue(lua_State*) const; virtual void PushLuaValue(lua_State*) const;
@ -134,6 +136,8 @@ public:
operator std::weak_ptr<SignalConnection>(); operator std::weak_ptr<SignalConnection>();
DEF_DATA_OP bool operator ==(SignalConnectionRef) const;
virtual const std::string ToString() const; virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const; virtual void Serialize(pugi::xml_node node) const;
virtual void PushLuaValue(lua_State*) const; virtual void PushLuaValue(lua_State*) const;

View file

@ -72,10 +72,18 @@ bool Vector3::operator <(Vector3 other) const {
return X() < other.X() && Y() < other.Y() && Z() < other.Z(); return X() < other.X() && Y() < other.Y() && Z() < other.Z();
} }
bool Vector3::operator <=(Vector3 other) const {
return X() <= other.X() && Y() <= other.Y() && Z() <= other.Z();
}
bool Vector3::operator >(Vector3 other) const { bool Vector3::operator >(Vector3 other) const {
return X() > other.X() && Y() > other.Y() && Z() > other.Z(); return X() > other.X() && Y() > other.Y() && Z() > other.Z();
} }
bool Vector3::operator >=(Vector3 other) const {
return X() >= other.X() && Y() >= other.Y() && Z() >= other.Z();
}
Vector3 Vector3::Cross(Vector3 other) const { Vector3 Vector3::Cross(Vector3 other) const {
return glm::cross(this->vector, other.vector); return glm::cross(this->vector, other.vector);
} }

View file

@ -55,8 +55,9 @@ public:
DEF_DATA_OP Vector3 operator -() const; DEF_DATA_OP Vector3 operator -() const;
DEF_DATA_OP bool operator <(Vector3) const; DEF_DATA_OP bool operator <(Vector3) const;
DEF_DATA_OP bool operator >(Vector3) const; DEF_DATA_OP bool operator <=(Vector3) const;
bool operator >(Vector3) const;
bool operator >=(Vector3) const;
DEF_DATA_OP bool operator ==(Vector3) const; DEF_DATA_OP bool operator ==(Vector3) const;
// Augmented shorthands // Augmented shorthands

View file

@ -4,4 +4,16 @@ extern "C" {
#include <lauxlib.h> #include <lauxlib.h>
#include <lualib.h> #include <lualib.h>
#include <lua.h> #include <lua.h>
}
inline const char* x_luaL_udatatname (lua_State *L, int ud) {
void *p = lua_touserdata(L, ud);
if (p != NULL) {
lua_getmetatable(L, ud);
lua_getfield(L, -1, "__name");
const char* str = lua_tostring(L, -1);
lua_pop(L, 2);
return str;
}
return NULL;
} }