#include "lua_class_interface.h" #include #define ARRAY_INDEX " idx" // The space is intentional to make this an out-of-band field luaL_Reg LuaInterface::s_ClassList[] = { { "__index", LuaInterface::luaGetObject, }, { "__newindex", LuaInterface::luaSetObject, }, { NULL, }, }; const char* LuaInterface::luaClassName = "ja2_LuaInterface"; LuaInterface::LuaInterface() : luaObject(NULL) { } LuaInterface::~LuaInterface() { } LuaInterface::SInterfaceData* LuaInterface::luaGetInterface() { return NULL; } void* LuaInterface::luaIsOfType(LuaState state, int index, const char* sClassName) { lua_State* L = state(); void *p = lua_touserdata(L, index); LuaInterface::SInterfaceData* iface = NULL; if( lua_getmetatable(L, index) ) /* does it have a metatable? */ { lua_getfield(L, -1, "__ClassInterface"); iface = (LuaInterface::SInterfaceData*) lua_touserdata(L, -1); if( !iface ) { return NULL; } lua_pop(L,2); } else { return NULL; } LuaInterface::SInterfaceData::tClassInterface::iterator it = iface->ClassHierarchy.begin(); for(; it != iface->ClassHierarchy.end(); ++it) { if( *it == sClassName ) { return p; } } return NULL; } LuaInterface::SInterfaceData* LuaInterface::luaGetExportedInterface( SInterfaceData* iface ) { //iface.Attribs.push_back(s_attrClassList); //iface.ClassHierarchy.push_back(LuaInterface::luaClassName); return iface; } void LuaInterface::luaExportInterface(LuaState state, LuaInterface::SInterfaceData& iface ) { luaL_Reg *i; LuaAttrib *idx; lua_State* L = state(); LuaInterface::SInterfaceData::tClassInterface::iterator it_class = iface.ClassHierarchy.begin(); luaL_newmetatable( L, (*it_class).c_str() ); for (i = s_ClassList; i->name; i++) { lua_pushstring(L, i->name); lua_pushlightuserdata(L, &iface); lua_pushcclosure(L, i->func, 1); lua_rawset(L, -3); } lua_pushlightuserdata(L, &iface); lua_setfield(L, -2, "__ClassInterface"); LuaInterface::SInterfaceData::tAttribs::iterator it_attrib = iface.Attribs.begin(); for(;it_attrib != iface.Attribs.end(); ++it_attrib) { for (idx=*it_attrib; idx->name; idx++) { if (idx->staticcall) { lua_pushstring(L, idx->name); lua_pushcfunction(L, idx->staticcall); lua_rawset(L, -3 ); } } } } LuaAttrib* LuaInterface::luaCommonGetSet(LuaState state) { const char *AttrToFind; typedef std::list tAttributes; lua_State* L = state(); LuaInterface::SInterfaceData* iface = (LuaInterface::SInterfaceData*) lua_touserdata(L, lua_upvalueindex( 1)); if(!iface) { return NULL; } tAttributes* Attributes = &iface->Attribs; if (lua_isnumber(L, 2) ) { AttrToFind = ARRAY_INDEX; } else if (lua_isstring(L, 2) ) { AttrToFind = lua_tostring(L, 2); } else { luaL_argcheck(L, 0, 2, "Invalid index to the table" ); // The last function doesn't return, but gotta keep the compiler happy return NULL; } tAttributes::iterator it = Attributes->begin(); for(;it != Attributes->end(); ++it) { LuaAttrib* attrib = (*it); for ( ; attrib->name; attrib++ ) { if ( strcmp( attrib->name, AttrToFind) == 0 ) { return attrib; } } } std::string err = "No such field : " + std::string(AttrToFind); luaL_error(L, err.c_str()); return NULL; } //int LuaInterface::luaGetObject(lua_State* L) DEFINE_LUA_CFUNCTION(LuaInterface, luaGetObject) { LuaAttrib *Attributes; Attributes = LuaInterface::luaCommonGetSet(L); if (!Attributes) { lua_pushnil( L ); return 1; } if (!Attributes->get) { if (!Attributes->call) { lua_pushnil( L ); } else { lua_pushcfunction(L, Attributes->call); } return 1; } return Attributes->get( L ); } //int LuaInterface::luaSetObject(lua_State* L) DEFINE_LUA_CFUNCTION(LuaInterface, luaSetObject) { LuaAttrib *Attributes; Attributes = LuaInterface::luaCommonGetSet(L); if (!Attributes) { lua_rawset( L, 1 ); return 0; } if (!Attributes->set) { luaL_error( L, "The attribute is not writable" ); } return Attributes->set(L); } void LuaInterface::luaCreateObject( LuaState state, void *Ptr ) { lua_State* L = state(); // Create the object and initialize its pointer void **ud; ud = (void**)lua_newuserdata( L, sizeof( void*) ); *ud = Ptr; // save user data state.registry().GetUserDataTable(); lua_pushlightuserdata(L, this); lua_pushvalue(L, -3); lua_rawset(L, -3); lua_pop(L, 1); // Swap the table and metatable for stack arg purposes lua_insert( L, -2 ); lua_setmetatable( L, -2 ); } void LuaInterface::luaPushObject( LuaState state, const char* sClassName, void *Ptr ) { lua_State* L = state(); state.registry().GetUserDataTable(); lua_pushlightuserdata(L, Ptr); lua_rawget(L,-2); if(lua_isnil(L,-1)) { lua_pop(L, 1); luaL_getmetatable( L, sClassName ); if (lua_istable( L, -1 ) ) { this->luaCreateObject( state, Ptr ); } } if(!lua_isuserdata(L,-1)) { SGP_THROW(L"Could not create User Data"); } lua_insert(L, -2); lua_pop(L, 1); } void LuaInterface::luaPushObject( LuaState state, const char* luaName ) { LuaInterface::SInterfaceData* iface = this->luaGetInterface(); this->luaPushObject(state, iface->ClassHierarchy.front().c_str(), this); if(luaName != NULL) { lua_setglobal( state(), luaName ); } }