Created
September 7, 2012 00:09
-
-
Save Quit/3661692 to your computer and use it in GitHub Desktop.
Current version of the lua wrapper, + debugging stuff and a bit lacking documentation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "lua/lua.h" | |
#include "lua/lauxlib.h" | |
#include <cassert> | |
namespace gle { | |
//! Wrapper base class - no need to initiate those. | |
class LuaObjectBase { | |
private: | |
LuaObjectBase(const LuaObjectBase& b) {} | |
protected: | |
LuaObjectBase() {} | |
public: | |
virtual ~LuaObjectBase() {} | |
}; | |
//! The wrapper. Holds an object of type T. | |
template<typename T> class LuaObject : public LuaObjectBase { | |
T* m_ptr; | |
bool m_weak, m_valid; | |
lua_State* m_L; | |
private: | |
LuaObject(const LuaObject<T>& b) {} | |
public: | |
//! The name of this class - used in errors. Has to be the same as the metatable one. | |
static const char* NAME; | |
//! Creates a new LuaObject. | |
//! if "weak" is set to "false", the object will be deleted upon invalidation. | |
LuaObject(lua_State* L, T& object, bool weak = true): | |
m_L(L), m_ptr(&object), m_weak(weak), m_valid(true) | |
{ | |
} | |
//! Destructor. o7 wrapper. | |
virtual ~LuaObject() { | |
// If we aren't weak and valid, invalidate us. | |
// This will erase any lua information stored about this object. | |
if (!m_weak) | |
invalidate(); | |
// otherwise, if we are still valid, remove the ptr reference. | |
else if (m_valid) { | |
// Remove the wrapper from the wrapper list. | |
// -0, +1 ; X + 1 | |
lua_pushliteral(m_L, "LuaObjects"); | |
lua_rawget(m_L, LUA_REGISTRYINDEX); | |
if (lua_isnil(m_L, -1)) | |
luaL_error(m_L, "LuaObjects registry does not exist - did you forget to call LUA_OBJECT_OPEN?"); | |
// -0, +2 ; X + 3 | |
lua_pushlightuserdata(m_L, m_ptr); | |
lua_pushnil(m_L); | |
// -2, +0 ; X + 1 | |
lua_rawset(m_L, -3); | |
// -1, +0 ; X | |
lua_pop(m_L, 1); | |
/* | |
// Simply remove the wrapper for now. | |
// -0, +1 ; X + 1 | |
lua_pushlightuserdata(m_L, m_ptr); | |
// -1, +1 ; X + 1 | |
lua_rawget(m_L, LUA_REGISTRYINDEX); | |
// -0, +1 ; X + 2 | |
lua_pushliteral(m_L, "__wrapper"); | |
// -0, +1 ; X + 3 | |
lua_pushnil(m_L); | |
// -2, +0 ; X + 1 | |
lua_rawset(m_L, -3); | |
// -1, +0 ; X | |
lua_pop(m_L, 1); | |
*/ | |
} | |
} | |
//! Returns the object. | |
//! WARNING: If we aren't valid, this will be an ACCESS VIOLATION. | |
T* object() { return m_ptr; } | |
//! Accesses the object. | |
//! WARNING: If we aren't valid, this will be an ACCESS VIOLATION. | |
T* operator->() { return m_ptr; } | |
//! Invalidates this wrapper. | |
void invalidate() { | |
if (!m_valid) | |
return; | |
// First things first, INVALIDATE. | |
m_valid = false; | |
// If we aren't weak, kill our object now. | |
if (!m_weak) { | |
// We still want to do stuff with the wrapper though - assure that we still exist. | |
// Set our value to a lightuserdata. | |
lua_pushliteral(m_L, "LuaObjects"); | |
lua_rawget(m_L, LUA_REGISTRYINDEX); | |
//lua_pushlightuserdata(m_L, m_ptr); | |
//lua_pushlightuserdata(m_L, this); | |
//lua_rawset(m_L, -3); | |
delete m_ptr; | |
lua_pushlightuserdata(m_L, m_ptr); | |
lua_pushnil(m_L); | |
lua_rawset(m_L, -3); | |
lua_pop(m_L, 1); | |
} | |
// Get rid of our userdata. | |
lua_pushlightuserdata(m_L, m_ptr); | |
// Push NIL. | |
lua_pushnil(m_L); | |
lua_rawset(m_L, LUA_REGISTRYINDEX); | |
// Get the wrapper table. | |
// -0, +1 ; X + 1 | |
lua_pushliteral(m_L, "LuaObjects"); | |
lua_rawget(m_L, LUA_REGISTRYINDEX); | |
// Delete the entry for this userdata. | |
// -0, +0 ; X + 1 | |
lua_pushlightuserdata(m_L, m_ptr); | |
lua_pushnil(m_L); | |
lua_rawset(m_L, -3); | |
// Pop. | |
// -1, +0 ; X + 1 | |
lua_pop(m_L, 1); | |
// Officially dead now. | |
m_ptr = NULL; | |
} | |
//! Returns if this object is still valid. | |
bool valid() const { return m_valid; } | |
//! Returns the state. | |
lua_State* state() const { return m_L; } | |
}; | |
//! Tries to convert a lua value to a LuaObject of that type. | |
//! May throw an argerror. | |
//! [ -0, +0, e ] | |
template<typename T> LuaObject<T>& getObject(lua_State* L, int index) { | |
if (!lua_isuserdata(L, index)) { | |
const char *msg = lua_pushfstring(L, "%s expected, got %s", LuaObject<T>::NAME, luaL_typename(L, index)); | |
luaL_argerror(L, index, msg); | |
} | |
LuaObjectBase* base = static_cast<LuaObjectBase*>(lua_touserdata(L, index)); | |
LuaObject<T>* object = dynamic_cast<LuaObject<T>*>(base); | |
if (object == NULL) { | |
const char *msg = lua_pushfstring(L, "%s expected, got %s", LuaObject<T>::NAME, objectName(L, index).c_str()); | |
luaL_argerror(L, index, msg); | |
} | |
return *object; | |
} | |
//! Pushes the wrapper for this object onto the stack. | |
//! Should the object already exist within lua, it is simply pushed by value. | |
//! Returns the wrapper. | |
//! [ -0, +1, e ] | |
//! `weak': If set to "false", invalidating the object will delete it from C++. | |
template<typename T> LuaObject<T>& pushObject(lua_State* L, T& object, bool weak = true) { | |
// COMMENT FORMAT: | |
// -popping, +pushing ; index after operation | |
// Start: | |
// -0, +0 ; X (unknown stack location) | |
// First step: Check if we already exist. | |
// Push the pointer to lua. | |
// -0, +1 ; X+1 | |
lua_pushlightuserdata(L, &object); | |
// Get the registry. | |
// -1, +1 ; X+1 | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
// Is the registry entry available? | |
if (lua_isnil(L, -1)) { | |
// Negative - create one. | |
// Pop nil. | |
// -1, 0 ; X | |
lua_pop(L, 1); | |
// Make a key. | |
// -0, +1 ; X+1 | |
lua_pushlightuserdata(L, &object); | |
// Create a new table. | |
// -0, +1 ; X+2 | |
lua_newtable(L); | |
// Set it. | |
// -2, +0 ; X | |
lua_rawset(L, LUA_REGISTRYINDEX); | |
// Push the table again if we are weak | |
if (weak) { | |
lua_pushlightuserdata(L, &object); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
} | |
} | |
else if (!weak) { | |
// We are at X + 1. The registry table is at X + 1. | |
// Now that we know that the registry index exists, pop it. | |
lua_pop(L, 1); | |
} | |
// Try to get the object. | |
// NEW CODE. Get LuaObjects. | |
// -0, +1 ; X + Y + 1 | |
lua_pushliteral(L, "LuaObjects"); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "LuaObjects registry does not exist - did you forget to call LUA_OBJECT_OPEN?"); | |
// Get the object for that object. (hurr.) | |
// -0, +1 ; X + Y + 2 | |
lua_pushlightuserdata(L, &object); | |
lua_rawget(L, -2); | |
// nil? | |
if (lua_isnil(L, -1)) { | |
// Pop. | |
// -1, +0 ; X + Y + 1 | |
lua_pop(L, 1); | |
// Push the key - again. | |
// -0, +1 ; X + Y + 2 | |
lua_pushlightuserdata(L, &object); | |
// Push the space for the wrapper and create it. | |
// -0, +1 ; X + Y + 3 | |
LuaObject<T>* lObject = new (lua_newuserdata(L, sizeof(LuaObject<T>))) LuaObject<T>(L, object, weak); | |
// Set the metatable for the wrapper. | |
// -0, +0 ; X + Y + 3 | |
luaL_setmetatable(L, LuaObject<T>::NAME); | |
// Associate _wrapper with the object. | |
// -2, +0 ; X + Y + 1 | |
lua_rawset(L, -3); | |
// We have to get the object again - we can't simply copy it because rawset is stoopid. | |
// -0, +1 ; X + Y + 2 | |
lua_pushlightuserdata(L, &object); | |
lua_rawget(L, -2); | |
// the wrapper is now at X + Y + 2 = -1 | |
// If we were weak, we have one element above this one - the registry table. | |
if (weak) { | |
lua_pushliteral(L, "__wrapper"); | |
lua_pushvalue(L, -2); | |
// -1 is the wrapper, -2 is "__wrapper", -3 is the wrapper, -4 is LuaObjects, -5 is the object registry. | |
lua_rawset(L, -5); | |
// -1 is the wrapper, -2 LuaObjects, -3 the object registry | |
lua_remove(L, -3); | |
} | |
// Remove LuaObjects. | |
// -1, +0 ; X + 1 | |
lua_remove(L, -2); | |
return *lObject; | |
} | |
// The wrapper exists and is now at X + Y + 2 = -1. | |
else { | |
// Remove the registry table. | |
// -1, +0 ; X + Y + 1 | |
lua_remove(L, -2); | |
// If we were weak, do magic. | |
if (weak) { | |
// -1 is the wrapper, -2 the LuaObjects table | |
lua_pushlightuserdata(L, &object); | |
lua_pushvalue(L, -2); | |
lua_rawset(L, -4); | |
} | |
// Simply cast the object - if it's userdata. Lightuserdata? | |
//if (lua_islightuserdata(L, -1)) | |
//return **static_cast<LuaObject<T>**>(lua_touserdata(L, -1)); | |
// WARNING: This is assuming that nobody messes around with the registry. | |
// If somebody does, you're going to have a bad time. | |
// Return the userdata. | |
// -0, +0 ; X + 1 | |
return *static_cast<LuaObject<T>*>(lua_touserdata(L, -1)); | |
} | |
} | |
//! Frees any space that wrappers may hold. | |
//! If there is a chance that this object was passed to lua, it is recommended | |
//! to call this function in the dtor to properly clean up. | |
//! `markInvalid': In case the object isn't valid anymore (ex. you are calling freeObject in a destructor), | |
//! it is necessary to inform the wrapper to NOT delete the element - only to remove its data. | |
template<typename T> void freeObject(lua_State* L, T& object) { | |
// Get the wrapper. | |
lua_pushliteral(L, "LuaObjects"); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
lua_pushlightuserdata(L, &object); | |
lua_rawget(L, -2); | |
// Already removed...? | |
if (lua_isnil(L, -1)) { | |
// Make sure by also deleting the entry. | |
lua_pushlightuserdata(L, &object); | |
lua_pushnil(L); | |
lua_rawset(L, LUA_REGISTRYINDEX); | |
lua_pop(L, 1); | |
return; | |
} | |
// That object is to be terminated. | |
// Invalidate it. | |
LuaObject<T>& lObject = getObject<T>(L, -1); | |
// Clean up. LuaObjects and the object. | |
lua_pop(L, 2); | |
// Terminate the object. | |
lObject.invalidate(); | |
} | |
//! A function that can be added to __cfuncs. Returns if the wrapper is still valid. | |
template<typename T> int LOC_IsValid(lua_State* L) { | |
// Get the wrapper. | |
LuaObject<T>& object = getObject<T>(L, 1); | |
lua_pushboolean(L, object.valid() ? 1 : 0); | |
return 1; | |
} | |
//! The __index function to be used with LuaObjects inside their metatable. | |
template<typename T> int LOM__index(lua_State* L) { | |
// 1: the userdata that was indexed | |
// 2: the string/number/whatsoever that was indexed | |
// Get the wrapper. | |
// -0, +0 ; 2 | |
LuaObject<T>& object = getObject<T>(L, 1); | |
// Object was invalid => we return nil. | |
if (!object.valid()) { | |
lua_pushnil(L); | |
return 1; | |
} | |
//// Assure it's not '__wrapper'. | |
//// -0, +1 ; 3 | |
//lua_pushliteral(L, "__wrapper"); | |
//// -0, +0 ; 3 | |
//if (lua_compare(L, 2, 3, LUA_OPEQ)) | |
// luaL_error(L, "attempt to access __wrapper on LuaObject<%s>!", LuaObject<T>::NAME); | |
//// Pop _wrapper again. | |
//// -1, +0 ; 2 | |
//lua_pop(L, 1); | |
// Push the lightuserdata. | |
// -0, +1 ; 3 | |
lua_pushlightuserdata(L, object.object()); | |
// Get the registry entry for this object. | |
// -1, +1 ; 3 | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
// nil? | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "LuaObject<%s> has no valid registry entry anmyore", LuaObject<T>::NAME); | |
// Check if there's a field in the registry entry for it. | |
// Reuse the string. | |
// -0, +1 ; 4 | |
lua_pushvalue(L, 2); | |
// Look it up in the registry entry. | |
// -1, +1 ; 4 | |
lua_rawget(L, -2); | |
// not nil? return it. | |
if (!lua_isnil(L, -1)) | |
return 1; | |
// Get the metatable. | |
// -0, +1 ; 5 | |
if (!lua_getmetatable(L, 1)) | |
luaL_error(L, "LuaObject<%s> has no metatable anymore", LuaObject<T>::NAME); | |
// Search within "__cdef" | |
// -0, +1 ; 6 | |
lua_pushliteral(L, "__cdef"); | |
// -1, +1 ; 6 | |
lua_rawget(L, -2); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "LuaObject<%s> has no __cdef anymore", LuaObject<T>::NAME); | |
// Push the index, again. | |
// -0, +1 ; 7 | |
lua_pushvalue(L, 2); | |
// Rawget | |
// -1, +1 ; 7 | |
lua_rawget(L, -2); | |
// Return whatever this may is now. | |
return 1; | |
} | |
//! The __newindex to be used with LuaObjects inside their metatable. | |
template<typename T> int LOM__newindex(lua_State* L) { | |
// Get the object. | |
// -0, +0 ; 3 | |
LuaObject<T>& object = getObject<T>(L, 1); | |
if (!object.valid()) | |
luaL_error(L, "attempt to set index on invalid LuaObject<%s>!", LuaObject<T>::NAME); | |
//// Make sure it isn't __wrapper. | |
//// -0, +1 ; 4 | |
//lua_pushliteral(L, "__wrapper"); | |
//if (lua_compare(L, 2, -1, LUA_OPEQ)) | |
// luaL_error(L, "attempt to set __wrapper on LuaObject<%s>!", LuaObject<T>::NAME); | |
//// Pop it. | |
//// -1, 0 ; 3 | |
//lua_pop(L, 1); | |
// 1: object | |
// 2: key | |
// 3: value | |
// Push the userdata to the registry. | |
// -0, +1 ; 4 | |
lua_pushlightuserdata(L, object.object()); | |
// Get the entry. | |
// -1, +1 ; 4 | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
// Copy the key | |
// -0, +1 ; 5 | |
lua_pushvalue(L, 2); | |
// Copy the value. | |
// -0, +1 ; 6 | |
lua_pushvalue(L, 3); | |
// set | |
lua_rawset(L, -3); | |
return 0; | |
} | |
//! The __gc to be used with LuaObjects inside their metatable. | |
template<typename T> int LOM__gc(lua_State* L) { | |
// Get the object. | |
// -0, +0 ; 1 | |
LuaObject<T>& object = getObject<T>(L, 1); | |
// Resurrect the item for now | |
if (object.valid()) { | |
lua_pushliteral(L, "LuaObjects"); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
assert(lua_istable(L, -1)); | |
lua_pushlightuserdata(L, object.object()); | |
lua_pushvalue(L, 1); | |
lua_rawset(L, -3); | |
lua_pop(L, 1); | |
} | |
// Call the destructor. | |
object.~LuaObject(); | |
// This will have invalidated the object already. | |
return 0; | |
} | |
//! Default __tostring function. Optional; has to be included in __cdef manually. | |
template<typename T> int LOM__tostring(lua_State* L) { | |
// Get the name. Simple as that. | |
lua_pushstring(L, LuaObject<T>::NAME); | |
return 1; | |
} | |
//! Adds tostring for this class - assumes that the last index (-1) is the opened metatable. | |
# define LUA_OBJECT_ADD_TOSTRING(L, _class) lua_pushliteral(L, "__tostring"); lua_pushcfunction(L, gle::LOM__tostring< _class >); lua_rawset(L, -3); | |
//! Returns the name of an userdata object. | |
std::string objectName(lua_State* L, int idx) { | |
// Make sure it's an userobject. | |
if (!lua_isuserdata(L, idx)) | |
luaL_error(L, "cannot determine name of non-userdata"); | |
// Get its metatable. | |
// +1 ; 1 | |
if (!lua_getmetatable(L, idx)) | |
luaL_error(L, "userdata has no metatable"); | |
// Get __name. | |
// +1 ; 2 | |
lua_pushliteral(L, "__name"); | |
lua_rawget(L, -2); | |
std::string result(lua_tostring(L, -1)); | |
// Pop. | |
lua_pop(L, 2); | |
return result; | |
} | |
//! Pushes the method for that object and its wrapper onto the stack. | |
//! If available, it will search for the lua-overwritten-method first. | |
//! If that is not available, it will search in the metatable's cdef for one. | |
//! Pushes the function onto the stack if available, otherwise nothing. | |
//! If either the lua-defined or the metatable aren't functions, an exception is thrown. | |
//! If neither are defined or the object hasn't been exported to lua yet, this function returns false. | |
//! TODO: This function has several, severe flaws: | |
//! If called on non-weak objects and the wrapper has already been garbage collected, there is a chance that this fails. | |
//! as in "lua error" - I think that should return false. Definitely ... | |
bool objectCall(lua_State* L, const void* object, const char* functionName) { | |
// Get the registry. | |
// -0, +1 ; X + 1 | |
lua_pushlightuserdata(L, const_cast<void*>(object)); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
if (lua_isnil(L, -1)) { | |
lua_pop(L, 1); | |
return false; | |
} | |
// Check if there's a field called like that. | |
// 0, +1 ; X + 2 | |
lua_pushstring(L, functionName); | |
lua_rawget(L, -2); | |
if (!lua_isnil(L, -1)) { | |
// Get LuaObjects. X + 3 | |
lua_pushliteral(L, "LuaObjects"); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "LuaObjects registry does not exist - did you forget to call LUA_OBJECT_OPEN?"); | |
// Get the Wrapper. X + 4 | |
lua_pushlightuserdata(L, const_cast<void*>(object)); | |
lua_rawget(L, -2); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "objectCall failed - object does not exist anymore"); | |
// Function? -1 = wrapper, -2 = LuaObjects, -3 = function | |
if (lua_isfunction(L, -3)) { | |
lua_remove(L, -2); | |
// Now that we have the function, push the object. | |
return true; | |
} | |
luaL_error(L, "objectCall in " LUA_QS " failed: lua defined " LUA_QS " is not a function", objectName(L, -1).c_str(), functionName); | |
} | |
// It's nil, drop it. | |
lua_pop(L, 1); | |
// X + 1; the registry table. | |
// Get the wrapper. | |
// -1, +0 ; X | |
lua_pop(L, 1); | |
// Get the wrapper from LuaObjects. | |
// -0, +2 ; X + 2 | |
lua_pushliteral(L, "LuaObjects"); | |
lua_rawget(L, LUA_REGISTRYINDEX); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "LuaObjects registry does not exist - did you forget to call LUA_OBJECT_OPEN?"); | |
lua_pushlightuserdata(L, const_cast<void*>(object)); | |
lua_rawget(L, -2); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "objectCall failed - object does not exist anymore"); | |
// X + 2; the __wrapper. | |
// Get the metatable. | |
if (!lua_getmetatable(L, -1)) | |
luaL_error(L, "objectCall failed - object does not have a metatable anymore!"); | |
// X + 3; the metatable of -wrapper. | |
// Get __cdef | |
lua_pushliteral(L, "__cdef"); | |
lua_rawget(L, -2); | |
if (lua_isnil(L, -1)) | |
luaL_error(L, "objectCall failed - " LUA_QS " has no cdefs anymore", objectName(L, -3)); | |
// X + 4; __cdef. | |
lua_pushstring(L, functionName); | |
lua_rawget(L, -2); | |
// X + 5; the function. | |
if (!lua_isnil(L, -1)) { | |
if (lua_isfunction(L, -1)) { | |
// Move X + 5 to X + 1 | |
lua_replace(L, -5); | |
// X+4, X+3, X+2, X+1 exist. X+1 is the function, X+2 the wrapper; therefore, delete X+4 and X+3 (metatable of wrapper and cdef) | |
lua_pop(L, 2); | |
return true; | |
} | |
// Get the name as X+6 | |
lua_getfield(L, -3, "__name"); | |
luaL_error(L, "objectCall in " LUA_QS " failed: C defined " LUA_QS " is not a function!", lua_tostring(L, -1), functionName); | |
} | |
// Clean up. | |
lua_pop(L, 5); | |
return false; | |
} | |
//! Registers a name for LuaObject for that class. | |
# define LUA_OBJECT_REGISTER(_class, _name) const char* gle::LuaObject< _class >::NAME = _name ; | |
//! Returns the name of a LuaObject for that class. | |
//! For objects, use the objectName() function. | |
# define LUA_OBJECT_NAME(_class) gle::LuaObject < _class >::NAME | |
//! Opens LuaObject (like "normal" libraries). Needs to be called before anything with objects is done. | |
# define LUA_OBJECT_OPEN(L) gle::_LUA_OBJECT_OPEN(L); | |
void _LUA_OBJECT_OPEN(lua_State* L) { | |
lua_pushliteral(L, "LuaObjects"); | |
// The table that will contain the wrappers. | |
// -0, +1 ; 2 | |
lua_newtable(L); | |
// The metatable. | |
// -0, +1 ; 3 | |
lua_newtable(L); | |
// __mode | |
// -0, +1 ; 4 | |
lua_pushliteral(L, "__mode"); | |
// kv | |
// -0, +1 ; 5 | |
lua_pushliteral(L, "kv"); | |
// set the metatable's __mode to kv. -- in theory, just having v would be enough, as it's lightuserdata => userdata. | |
// -2, +0 ; 3 | |
lua_rawset(L, -3); | |
// 3; the new metatable. set it. (3 metatable, 2 the table we're using for wrappers, 1 the key) | |
// -1, +0 ; 2 | |
lua_setmetatable(L, -2); | |
// 2 the table we're using, 1 the key LuaObjects | |
// -2, +0 ; 0 | |
lua_rawset(L, LUA_REGISTRYINDEX); | |
} | |
//! Registers a new metatable for this class. This is requiring that you LUA_OBJECT_REGISTERed that class before. | |
//! It will also fill all cfunctions you pass in cdefReg to be used, along with IsValid. | |
//! This function leaves the metatable on the stack - for you to use! For free! | |
// [ -0, +1, - ] | |
template<typename T> void registerObject(lua_State* L, const luaL_Reg *cdefReg) { | |
// Create the metatable. | |
// -0, +1 ; X + 1 | |
luaL_newmetatable(L, LUA_OBJECT_NAME(T)); | |
// Fill the metatable. | |
// __index | |
// -0, +0 ; X + 1 | |
lua_pushliteral(L, "__index"); | |
lua_pushcfunction(L, LOM__index<T>); | |
lua_rawset(L, -3); // set __index | |
// __newindex | |
// -0, +0 ; X + 1 | |
lua_pushliteral(L, "__newindex"); | |
lua_pushcfunction(L, LOM__newindex<T>); | |
lua_rawset(L, -3); // set __newindex | |
// __gc | |
// -0, +0 ; X + 1 | |
lua_pushliteral(L, "__gc"); | |
lua_pushcfunction(L, LOM__gc<T>); | |
lua_rawset(L, -3); // set __gc | |
// __name | |
// -0, +0 ; X + 1 | |
lua_pushliteral(L, "__name"); | |
lua_pushstring(L, LUA_OBJECT_NAME(T)); | |
lua_rawset(L, -3); // set __name | |
// Create the name already | |
// -0, +1 ; X + 2 | |
lua_pushliteral(L, "__cdef"); | |
// -0, +1 ; X + 3 | |
// Import the lib. | |
luaL_newlib(L, cdefReg); | |
// Import IsValid | |
// -0, +0 ; X + 3 | |
lua_pushliteral(L, "IsValid"); | |
lua_pushcfunction(L, LOC_IsValid<T>); | |
lua_rawset(L, -3); // set IsValid | |
// Push the literal "BaseClass" | |
// -0, +1 ; X + 4 | |
lua_pushliteral(L, "BaseClass"); | |
// -0, +1 ; X + 5 | |
lua_pushvalue(L, -2); // push the metatable, kinda hacky but it works | |
// -2, +0 ; X + 3 | |
lua_rawset(L, -3); // set BaseClass | |
// -2, +0 ; X + 1 | |
lua_rawset(L, -3); // set __cdef | |
// Leave the metatable on the stack. | |
} | |
//! Creates a new function to be used as method for objects of class `_class' with name `name'. | |
//! In usual lua manner, the lua_State* is called L, the wrapper self. | |
//! For example: LUA_OBJECT_FUNCTION( | |
# define LUA_OBJECT_FUNCTION(_class, name) int name (lua_State* L) { gle::LuaObject< _class >& self = gle::getObject< _class >(L, 1); /##/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment