/* Based on Lua Wiki example: http://lua-users.org/wiki/SimplerCppBinding * Modified by Chris. */ #ifndef LuaBinding_H #define LuaBinding_H extern "C" { #include #include } #include "LuaManager.h" #include inline bool MyLua_checkboolean (lua_State *L, int numArg) { luaL_checktype(L,numArg,LUA_TBOOLEAN); return !!lua_toboolean(L,numArg); } template struct RegType { const char *name; int (*mfunc)(T *p, lua_State *L); }; template class Luna { typedef struct { T *pT; } userdataType; public: static void Register(lua_State *L) { lua_newtable(L); int methods = lua_gettop(L); luaL_newmetatable(L, m_sClassName); int metatable = lua_gettop(L); // store method table in globals so that // scripts can add functions written in Lua. lua_pushstring(L, m_sClassName); lua_pushvalue(L, methods); lua_settable(L, LUA_GLOBALSINDEX); lua_pushliteral(L, "__metatable"); lua_pushvalue(L, methods); lua_settable(L, metatable); // hide metatable from Lua getmetatable() lua_pushliteral(L, "__index"); lua_pushvalue(L, methods); lua_settable(L, metatable); lua_pushliteral(L, "__tostring"); lua_pushcfunction(L, tostring_T); lua_settable(L, metatable); lua_pushliteral(L, "__eq"); lua_pushcfunction(L, equal); lua_settable(L, metatable); // fill method table with methods from class T for (unsigned i=0; s_pvMethods && isize(); i++ ) { const MyRegType *l = &(*s_pvMethods)[i]; lua_pushstring(L, l->name); lua_pushlightuserdata(L, (void*)l); lua_pushcclosure(L, thunk, 1); lua_settable(L, methods); } lua_pop(L, 2); // drop metatable and method table } // get userdata from Lua stack and return pointer to T object static T *check( lua_State *L, int narg, bool bIsSelf = false ) { userdataType *pUserdata = static_cast( luaL_checkudata(L, narg, m_sClassName) ); if( pUserdata == NULL ) { if( bIsSelf ) luaL_typerror( L, narg, m_sClassName ); else LuaHelpers::TypeError( L, narg, m_sClassName ); } return pUserdata->pT; // pointer to T object } private: // member function dispatcher static int thunk(lua_State *L) { // stack has userdata, followed by method args T *obj = check( L, 1, true ); // get self lua_remove(L, 1); // remove self so member function args start at index 1 // get member function from upvalue MyRegType *l = static_cast(lua_touserdata(L, lua_upvalueindex(1))); return (*(l->mfunc))(obj,L); // call member function } /* Two objects are equal if the underlying object is the same. */ static int equal( lua_State *L ) { userdataType *obj1 = static_cast(lua_touserdata(L, 1)); userdataType *obj2 = static_cast(lua_touserdata(L, 2)); lua_pushboolean( L, obj1->pT == obj2->pT ); return 1; } public: // create a new T object and // push onto the Lua stack a userdata containing a pointer to T object static int Push(lua_State *L, T* p ) { userdataType *ud = static_cast(lua_newuserdata(L, sizeof(userdataType))); ud->pT = p; // store pointer to object in userdata luaL_getmetatable(L, m_sClassName); // lookup metatable in Lua registry lua_setmetatable(L, -2); return 1; // userdata containing pointer to T object } typedef RegType MyRegType; typedef vector RegTypeVector; static RegTypeVector *s_pvMethods; static void CreateMethodsVector() { if(s_pvMethods==NULL) s_pvMethods = new RegTypeVector; } private: static const char m_sClassName[]; static int tostring_T (lua_State *L) { char buff[32]; userdataType *ud = static_cast(lua_touserdata(L, 1)); T *obj = ud->pT; sprintf(buff, "%p", obj); lua_pushfstring(L, "%s (%s)", m_sClassName, buff); return 1; } }; #define LUA_REGISTER_CLASS( T ) \ template<> const char Luna::m_sClassName[] = #T; \ template<> Luna::RegTypeVector* Luna::s_pvMethods = NULL; \ static Luna##T registera; \ void T::PushSelf( lua_State *L ) { Luna##T::Push( L, this ); } \ /* Call PushSelf, so we always call the derived Luna::Push. */ \ namespace LuaHelpers { template<> void Push( T *pObject, lua_State *L ) { pObject->PushSelf( L ); } } #define ADD_METHOD( method_name ) \ { Luna::CreateMethodsVector(); RegType r = {#method_name,method_name}; Luna::s_pvMethods->push_back(r); } #endif /* * (c) 2001-2005 lua-users.org, Chris Danford * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */