|
@@ -28,13 +28,12 @@ typedef luaL_Reg ClassMethod; |
|
|
typedef lua_State State; |
|
|
typedef lua_State State; |
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
//----------------------------------------------------------------------------- |
|
|
template <typename T> |
|
|
|
|
|
class ObjectDef |
|
|
class ObjectDef |
|
|
{ |
|
|
{ |
|
|
public: |
|
|
public: |
|
|
ObjectDef() { } |
|
|
ObjectDef() { } |
|
|
virtual ~ObjectDef() { } |
|
|
virtual ~ObjectDef() { } |
|
|
static ObjectDef<T>* New(State* l, int arg_nb) |
|
|
|
|
|
|
|
|
static ObjectDef* New(State* l, int arg_nb) |
|
|
{ |
|
|
{ |
|
|
UNUSED(l); |
|
|
UNUSED(l); |
|
|
UNUSED(arg_nb); |
|
|
UNUSED(arg_nb); |
|
@@ -46,9 +45,6 @@ public: |
|
|
static const char* GetClassInstName() { ASSERT(false); return nullptr; } |
|
|
static const char* GetClassInstName() { ASSERT(false); return nullptr; } |
|
|
static const ClassMethod* GetStaticMethods() { ASSERT(false); return nullptr; } |
|
|
static const ClassMethod* GetStaticMethods() { ASSERT(false); return nullptr; } |
|
|
static const ClassMethod* GetInstanceMethods() { ASSERT(false); return nullptr; } |
|
|
static const ClassMethod* GetInstanceMethods() { ASSERT(false); return nullptr; } |
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
T* m_instance = nullptr; |
|
|
|
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
//----------------------------------------------------------------------------- |
|
@@ -285,351 +281,6 @@ private: |
|
|
Lolua::State* m_lua_state; |
|
|
Lolua::State* m_lua_state; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//class T definition |
|
|
|
|
|
//class T |
|
|
|
|
|
//{ |
|
|
|
|
|
//public: |
|
|
|
|
|
// int Ctor(lua_State* l) { return 0; } |
|
|
|
|
|
// static const char* m_class_name; |
|
|
|
|
|
// static const Class<T>::Variable* m_variables; |
|
|
|
|
|
// static const Class<T>::Method* m_methods; |
|
|
|
|
|
//}; |
|
|
|
|
|
/* |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
template<typename T> |
|
|
|
|
|
class ClassTest |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
struct Variable |
|
|
|
|
|
{ |
|
|
|
|
|
const char* m_name; |
|
|
|
|
|
int(*Getter)(lua_State*); |
|
|
|
|
|
int(*Setter)(lua_State*); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
struct Method |
|
|
|
|
|
{ |
|
|
|
|
|
const char* m_name; |
|
|
|
|
|
int(*Func)(lua_State*); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//Register: Register class in Lua. Leave library empty to store class in global scope. |
|
|
|
|
|
static void Register(lua_State* l, const char *library = NULL) |
|
|
|
|
|
{ |
|
|
|
|
|
if (library && strlen(library)) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_getglobal(l, library); |
|
|
|
|
|
//Create library if not present |
|
|
|
|
|
if (lua_isnil(l, -1)) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_newtable(l); |
|
|
|
|
|
//Duplicate table pointer since setglobal pops the value |
|
|
|
|
|
lua_pushvalue(l, -1); |
|
|
|
|
|
lua_setglobal(l, library); |
|
|
|
|
|
} |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Ctor); |
|
|
|
|
|
//lua_setfield(l, -2, T::m_class_name); |
|
|
|
|
|
//lua_pop(l, 1); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Ctor); |
|
|
|
|
|
//lua_setglobal(l, T::m_class_name); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
luaL_newmetatable(l, T::m_class_name); |
|
|
|
|
|
int metatable = lua_gettop(l); |
|
|
|
|
|
|
|
|
|
|
|
//Register all m_methods: Register Name for fun_call and number for choice |
|
|
|
|
|
for (int i = 0; T::m_methods[i].m_name; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_pushstring(l, T::m_methods[i].m_name); |
|
|
|
|
|
lua_pushcfunction(l, T::m_methods[i].Func); |
|
|
|
|
|
lua_settable(l, metatable); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__gc"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Dtor); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__tostring"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::ToString); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__eq"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Equals); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__index"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Getter); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__newindex"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Setter); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
////Register all properties: Register Name for fun_call and number for choice |
|
|
|
|
|
//for (int i = 0; T::m_variables[i].m_name; i++) |
|
|
|
|
|
//{ |
|
|
|
|
|
// lua_pushstring(l, T::m_variables[i].m_name); |
|
|
|
|
|
// lua_pushnumber(l, i); |
|
|
|
|
|
// lua_settable(l, metatable); |
|
|
|
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
////Register all m_methods: Register Name for fun_call and number for choice |
|
|
|
|
|
//for (int i = 0; T::m_methods[i].m_name; i++) |
|
|
|
|
|
//{ |
|
|
|
|
|
// lua_pushstring(l, T::m_methods[i].m_name); |
|
|
|
|
|
// //Add (1 << 8) to identify function on call |
|
|
|
|
|
// lua_pushnumber(l, i | (1 << 8)); |
|
|
|
|
|
// lua_settable(l, metatable); |
|
|
|
|
|
//} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
template<typename T> |
|
|
|
|
|
class Class |
|
|
|
|
|
{ |
|
|
|
|
|
public: |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
struct Variable |
|
|
|
|
|
{ |
|
|
|
|
|
const char* m_name; |
|
|
|
|
|
int (T::*Getter)(lua_State*); |
|
|
|
|
|
int (T::*Setter)(lua_State*); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
struct Method |
|
|
|
|
|
{ |
|
|
|
|
|
const char* m_name; |
|
|
|
|
|
int (T::*Func)(lua_State*); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
|
|
//Check: Raise an exception if FAIL |
|
|
|
|
|
static T* Check(lua_State * l, int narg) |
|
|
|
|
|
{ |
|
|
|
|
|
T** obj = static_cast <T **>(luaL_checkudata(l, narg, T::m_class_name)); |
|
|
|
|
|
return !obj ? nullptr : *obj; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//LightCheck: Returns nullptr if FAIL |
|
|
|
|
|
static T* LightCheck(lua_State* l, int num_args) |
|
|
|
|
|
{ |
|
|
|
|
|
T** obj = static_cast <T **>(luaL_testudata(l, num_args, T::m_class_name)); |
|
|
|
|
|
return !obj ? nullptr : *obj; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Register: Register class in Lua. Leave library empty to store class in global scope. |
|
|
|
|
|
static void Register(lua_State* l, const char *library = NULL) |
|
|
|
|
|
{ |
|
|
|
|
|
if (library && strlen(library)) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_getglobal(l, library); |
|
|
|
|
|
//Create library if not present |
|
|
|
|
|
if (lua_isnil(l, -1)) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_newtable(l); |
|
|
|
|
|
//Duplicate table pointer since setglobal pops the value |
|
|
|
|
|
lua_pushvalue(l, -1); |
|
|
|
|
|
lua_setglobal(l, library); |
|
|
|
|
|
} |
|
|
|
|
|
lua_pushcfunction(l, &Class<T>::Ctor); |
|
|
|
|
|
lua_setfield(l, -2, T::m_class_name); |
|
|
|
|
|
lua_pop(l, 1); |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
lua_pushcfunction(l, &Class<T>::Ctor); |
|
|
|
|
|
lua_setglobal(l, T::m_class_name); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
luaL_newmetatable(l, T::m_class_name); |
|
|
|
|
|
int metatable = lua_gettop(l); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__gc"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Dtor); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__tostring"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::ToString); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//lua_pushstring(l, "__eq"); |
|
|
|
|
|
//lua_pushcfunction(l, &Class<T>::Equals); |
|
|
|
|
|
//lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
lua_pushstring(l, "__index"); |
|
|
|
|
|
lua_pushcfunction(l, &Class<T>::Getter); |
|
|
|
|
|
lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
lua_pushstring(l, "__newindex"); |
|
|
|
|
|
lua_pushcfunction(l, &Class<T>::Setter); |
|
|
|
|
|
lua_settable(l, metatable); |
|
|
|
|
|
|
|
|
|
|
|
//Register all properties: Register Name for fun_call and number for choice |
|
|
|
|
|
for (int i = 0; T::m_variables[i].m_name; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_pushstring(l, T::m_variables[i].m_name); |
|
|
|
|
|
lua_pushnumber(l, i); |
|
|
|
|
|
lua_settable(l, metatable); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Register all m_methods: Register Name for fun_call and number for choice |
|
|
|
|
|
for (int i = 0; T::m_methods[i].m_name; i++) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_pushstring(l, T::m_methods[i].m_name); |
|
|
|
|
|
//Add (1 << 8) to identify function on call |
|
|
|
|
|
lua_pushnumber(l, i | (1 << 8)); |
|
|
|
|
|
lua_settable(l, metatable); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
//Ctor |
|
|
|
|
|
static int Ctor(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
T* obj = new T(l); |
|
|
|
|
|
T** lua_obj = static_cast<T**>(lua_newuserdata(l, sizeof(T*))); // Push value = userdata |
|
|
|
|
|
*lua_obj = obj; |
|
|
|
|
|
|
|
|
|
|
|
luaL_getmetatable(l, T::m_class_name); // Fetch global metatable T::classname |
|
|
|
|
|
lua_setmetatable(l, -2); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Dtor |
|
|
|
|
|
static int Dtor(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
T** lua_obj = static_cast<T**>(lua_touserdata(l, -1)); |
|
|
|
|
|
if (lua_obj && *lua_obj) |
|
|
|
|
|
delete(*lua_obj); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//AddInstance |
|
|
|
|
|
static void AddInstance(lua_State* l, T* instance) |
|
|
|
|
|
{ |
|
|
|
|
|
T** a = (T**)lua_newuserdata(l, sizeof(T*)); // Create userdata |
|
|
|
|
|
*a = instance; |
|
|
|
|
|
|
|
|
|
|
|
luaL_getmetatable(l, T::m_class_name); |
|
|
|
|
|
lua_setmetatable(l, -2); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//---- |
|
|
|
|
|
static void GetVarIndex(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_getmetatable(l, 1); //Look up the index of a m_name |
|
|
|
|
|
lua_pushvalue(l, 2); //Push the m_name |
|
|
|
|
|
lua_rawget(l, -2); //Get the index |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//---- |
|
|
|
|
|
static void PrepareGetSet(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
lua_pop(l, 2); // Pop metatable and idx |
|
|
|
|
|
lua_remove(l, 1); // Remove userdata |
|
|
|
|
|
lua_remove(l, 1); // Remove [key] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Getter: Call a func or a getter var |
|
|
|
|
|
static int Getter(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
GetVarIndex(l); |
|
|
|
|
|
//Check if we got a valid index |
|
|
|
|
|
if (lua_isnumber(l, -1)) |
|
|
|
|
|
{ |
|
|
|
|
|
int idx = lua_tonumber(l, -1); |
|
|
|
|
|
T** obj = static_cast<T**>(lua_touserdata(l, 1)); |
|
|
|
|
|
lua_pushvalue(l, 3); |
|
|
|
|
|
|
|
|
|
|
|
//It's a method |
|
|
|
|
|
if (idx & (1 << 8)) |
|
|
|
|
|
{ |
|
|
|
|
|
//Push the Method index and call the function |
|
|
|
|
|
lua_pushnumber(l, idx ^ (1 << 8)); |
|
|
|
|
|
lua_pushlightuserdata(l, obj); |
|
|
|
|
|
lua_pushcclosure(l, &Class<T>::CallMethod, 2); |
|
|
|
|
|
// Return a Method |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PrepareGetSet(l); |
|
|
|
|
|
return ((*obj)->*(T::m_variables[idx].Getter))(l); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Getter: Class a setter var or error if func |
|
|
|
|
|
static int Setter(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
GetVarIndex(l); |
|
|
|
|
|
//Check if we got a valid index |
|
|
|
|
|
if (lua_isnumber(l, -1)) |
|
|
|
|
|
{ |
|
|
|
|
|
int idx = lua_tonumber(l, -1); |
|
|
|
|
|
T** obj = static_cast<T**>(lua_touserdata(l, 1)); |
|
|
|
|
|
if (!obj || !*obj) |
|
|
|
|
|
{ |
|
|
|
|
|
luaL_error(l, "Internal error, no object given!"); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Try to set a Method - FAIL |
|
|
|
|
|
if (idx & (1 << 8)) |
|
|
|
|
|
{ |
|
|
|
|
|
String s = String::Printf("Trying to set the method [%s] of class [%s]", (*obj)->T::m_methods[idx ^ (1 << 8)].m_name, T::m_class_name); |
|
|
|
|
|
luaL_error(l, s.C()); |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
PrepareGetSet(l); |
|
|
|
|
|
return ((*obj)->*(T::m_variables[idx].Setter))(l); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//CallMethod: Actually calls the method on the object |
|
|
|
|
|
static int CallMethod(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
int i = (int)lua_tonumber(l, lua_upvalueindex(1)); |
|
|
|
|
|
T** obj = static_cast <T**>(lua_touserdata(l, lua_upvalueindex(2))); |
|
|
|
|
|
return ((*obj)->*(T::m_methods[i].Func))(l); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//ToString: |
|
|
|
|
|
static int ToString(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
T** obj = static_cast<T**>(lua_touserdata(l, -1)); |
|
|
|
|
|
if (obj) |
|
|
|
|
|
lua_pushfstring(l, "%s (%p)", T::m_class_name, (void*)*obj); |
|
|
|
|
|
else |
|
|
|
|
|
lua_pushstring(l, "Empty object"); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//Equals: |
|
|
|
|
|
static int Equals(lua_State* l) |
|
|
|
|
|
{ |
|
|
|
|
|
T** obj1 = static_cast<T**>(lua_touserdata(l, -1)); |
|
|
|
|
|
T** obj2 = static_cast<T**>(lua_touserdata(l, 1)); |
|
|
|
|
|
lua_pushboolean(l, *obj1 == *obj2); |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
} /* namespace Lolua */ |
|
|
} /* namespace Lolua */ |
|
|
|
|
|
|
|
|
} /* namespace lol */ |
|
|
} /* namespace lol */ |