LuaWrappers.hpp

Go to the documentation of this file.
00001 /******************************************************************************\
00002 * LuaWrappers.hpp                                                              *
00003 * Making C++ stuff accessible from Lua.                                        *
00004 *                                                                              *
00005 *                                                                              *
00006 * Copyright (C) 2005-2007 by Leandro Motta Barros.                             *
00007 *                                                                              *
00008 * Permission is hereby granted, free of charge, to any person obtaining a copy *
00009 * of this software and associated documentation files (the "Software"), to     *
00010 * deal in the Software without restriction, including without limitation the   *
00011 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  *
00012 * sell copies of the Software, and to permit persons to whom the Software is   *
00013 * furnished to do so, subject to the following conditions:                     *
00014 *                                                                              *
00015 * The above copyright notice and this permission notice shall be included in   *
00016 * all copies or substantial portions of the Software.                          *
00017 *                                                                              *
00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   *
00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     *
00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE *
00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       *
00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      *
00023 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS *
00024 * IN THE SOFTWARE.                                                             *
00025 \******************************************************************************/
00026 
00027 #ifndef _DILUCULUM_LUA_WRAPPERS_HPP_
00028 #define _DILUCULUM_LUA_WRAPPERS_HPP_
00029 
00030 #include <algorithm>
00031 #include <string>
00032 #include <boost/bind.hpp>
00033 #include <Diluculum/LuaExceptions.hpp>
00034 #include <Diluculum/LuaState.hpp>
00035 #include <Diluculum/LuaUtils.hpp>
00036 
00037 
00038 namespace Diluculum
00039 {
00040    namespace Impl
00041    {
00050       void ReportErrorFromCFunction (lua_State* ls, const::std::string& what);
00051 
00052 
00053 
00057       struct CppObject
00058       {
00059          public:
00061             void* ptr;
00062 
00068             bool deleteMe;
00069       };
00070 
00071 
00072 
00079       class ClassTableFiller
00080       {
00081          public:
00090             ClassTableFiller (Diluculum::LuaValueMap& classTable,
00091                               const std::string& name,
00092                               lua_CFunction func)
00093             {
00094                classTable[name] = func;
00095             }
00096       };
00097    }
00098 }
00099 
00100 
00101 
00106 #define DILUCULUM_WRAPPER_FUNCTION(FUNC)        \
00107    Diluculum__ ## FUNC ## __Wrapper_Function
00108 
00109 
00110 
00130 #define DILUCULUM_WRAP_FUNCTION(FUNC)                                         \
00131 int DILUCULUM_WRAPPER_FUNCTION(FUNC) (lua_State* ls)                          \
00132 {                                                                             \
00133    using std::for_each;                                                       \
00134    using boost::bind;                                                         \
00135    using Diluculum::PushLuaValue;                                             \
00136    using Diluculum::Impl::ReportErrorFromCFunction;                           \
00137                                                                               \
00138    try                                                                        \
00139    {                                                                          \
00140       /* Read parameters and empty the stack */                               \
00141       const int numParams = lua_gettop (ls);                                  \
00142       Diluculum::LuaValueList params;                                         \
00143       for (int i = 1; i <= numParams; ++i)                                    \
00144          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
00145       lua_pop (ls, numParams);                                                \
00146                                                                               \
00147       /* Call the wrapped function */                                         \
00148       Diluculum::LuaValueList ret = FUNC (params);                            \
00149                                                                               \
00150       /* Push the return values and return */                                 \
00151       for_each (ret.begin(), ret.end(), bind (PushLuaValue, ls, _1));         \
00152                                                                               \
00153       return ret.size();                                                      \
00154    }                                                                          \
00155    catch (Diluculum::LuaError& e)                                             \
00156    {                                                                          \
00157       ReportErrorFromCFunction (ls, e.what());                                \
00158       return 0;                                                               \
00159    }                                                                          \
00160    catch(...)                                                                 \
00161    {                                                                          \
00162       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
00163       return 0;                                                               \
00164    }                                                                          \
00165 }
00166 
00167 
00168 
00172 #define DILUCULUM_CLASS_TABLE(CLASS) \
00173 Diluculum__Class_Table__ ## CLASS
00174 
00175 
00176 
00182 #define DILUCULUM_BEGIN_CLASS(CLASS)                                          \
00183 namespace                                                                     \
00184 {                                                                             \
00185    /* the table representing the class */                                     \
00186    Diluculum::LuaValueMap DILUCULUM_CLASS_TABLE(CLASS);                       \
00187 }                                                                             \
00188                                                                               \
00189 /* The Constructor */                                                         \
00190 int Diluculum__ ## CLASS ## __Constructor_Wrapper_Function (lua_State* ls)    \
00191 {                                                                             \
00192    using Diluculum::PushLuaValue;                                             \
00193    using Diluculum::Impl::CppObject;                                          \
00194    using Diluculum::Impl::ReportErrorFromCFunction;                           \
00195                                                                               \
00196    try                                                                        \
00197    {                                                                          \
00198       /* Read parameters and empty the stack */                               \
00199       const int numParams = lua_gettop (ls);                                  \
00200       Diluculum::LuaValueList params;                                         \
00201       for (int i = 1; i <= numParams; ++i)                                    \
00202          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
00203       lua_pop (ls, numParams);                                                \
00204                                                                               \
00205       /* Construct the object, wrap it in a userdata, and return */           \
00206       void* ud = lua_newuserdata (ls, sizeof(CppObject));                     \
00207       CppObject* cppObj = reinterpret_cast<CppObject*>(ud);                   \
00208       cppObj->ptr = new CLASS (params);                                       \
00209       cppObj->deleteMe = true;                                                \
00210                                                                               \
00211       lua_getglobal (ls, "__Diluculum__Class_Metatables");                    \
00212       lua_getfield (ls, -1, #CLASS);                                          \
00213       lua_setmetatable (ls, -3);                                              \
00214       lua_pop (ls, 1); /* pop the table of metatables */                      \
00215                                                                               \
00216       return 1;                                                               \
00217    }                                                                          \
00218    catch (Diluculum::LuaError& e)                                             \
00219    {                                                                          \
00220       ReportErrorFromCFunction (ls, e.what());                                \
00221       return 0;                                                               \
00222    }                                                                          \
00223    catch(...)                                                                 \
00224    {                                                                          \
00225       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
00226       return 0;                                                               \
00227    }                                                                          \
00228 }                                                                             \
00229                                                                               \
00230 /* Destructor */                                                              \
00231 int Diluculum__ ## CLASS ## __Destructor_Wrapper_Function (lua_State* ls)     \
00232 {                                                                             \
00233    using Diluculum::Impl::CppObject;                                          \
00234                                                                               \
00235    CppObject* cppObj =                                                        \
00236       reinterpret_cast<CppObject*>(lua_touserdata (ls, -1));                  \
00237                                                                               \
00238    if (cppObj->deleteMe)                                                      \
00239    {                                                                          \
00240       cppObj->deleteMe = false; /* don't delete again when gc'ed! */          \
00241       CLASS* pObj = reinterpret_cast<CLASS*>(cppObj->ptr);                    \
00242       delete pObj;                                                            \
00243    }                                                                          \
00244                                                                               \
00245    return 0;                                                                  \
00246 }
00247 
00248 
00249 
00254 #define DILUCULUM_METHOD_WRAPPER(CLASS, METHOD)                      \
00255    Diluculum__ ## CLASS ## __ ## METHOD ## __Method_Wrapper_Function
00256 
00257 
00258 
00264 #define DILUCULUM_CLASS_METHOD(CLASS, METHOD)                                 \
00265 int DILUCULUM_METHOD_WRAPPER(CLASS, METHOD) (lua_State* ls)                   \
00266 {                                                                             \
00267    using std::for_each;                                                       \
00268    using boost::bind;                                                         \
00269    using Diluculum::PushLuaValue;                                             \
00270    using Diluculum::Impl::CppObject;                                          \
00271    using Diluculum::Impl::ReportErrorFromCFunction;                           \
00272                                                                               \
00273    try                                                                        \
00274    {                                                                          \
00275       /* Read parameters and empty the stack */                               \
00276       const int numParams = lua_gettop (ls);                                  \
00277       Diluculum::LuaValue ud = Diluculum::ToLuaValue (ls, 1);                 \
00278       Diluculum::LuaValueList params;                                         \
00279       for (int i = 2; i <= numParams; ++i)                                    \
00280          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
00281       lua_pop (ls, numParams);                                                \
00282                                                                               \
00283       /* Get the object pointer and call the method */                        \
00284       CppObject* cppObj =                                                     \
00285          reinterpret_cast<CppObject*>(ud.asUserData().getData());             \
00286       CLASS* pObj = reinterpret_cast<CLASS*>(cppObj->ptr);                    \
00287                                                                               \
00288       Diluculum::LuaValueList ret = pObj->METHOD (params);                    \
00289                                                                               \
00290       /* Push the return values and return */                                 \
00291       for_each (ret.begin(), ret.end(), bind (PushLuaValue, ls, _1));         \
00292                                                                               \
00293       return ret.size();                                                      \
00294    }                                                                          \
00295    catch (Diluculum::LuaError& e)                                             \
00296    {                                                                          \
00297       ReportErrorFromCFunction (ls, e.what());                                \
00298       return 0;                                                               \
00299    }                                                                          \
00300    catch(...)                                                                 \
00301    {                                                                          \
00302       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
00303       return 0;                                                               \
00304    }                                                                          \
00305 }                                                                             \
00306                                                                               \
00307 namespace                                                                     \
00308 {                                                                             \
00309    Diluculum::Impl::ClassTableFiller                                          \
00310       Diluculum__ ## CLASS ## _ ## METHOD ## __ ## Filler(                    \
00311          DILUCULUM_CLASS_TABLE(CLASS),                                        \
00312          #METHOD,                                                             \
00313          DILUCULUM_METHOD_WRAPPER(CLASS, METHOD));                            \
00314 }
00315 
00316 
00317 
00322 #define DILUCULUM_END_CLASS(CLASS)                                            \
00323                                                                               \
00324 /* The function used to register the class in a 'LuaState' */                 \
00325 void Diluculum_Register_Class__ ## CLASS (Diluculum::LuaVariable className)   \
00326 {                                                                             \
00327    Diluculum::LuaState ls (className.getState());                             \
00328                                                                               \
00329    if (ls["__Diluculum__Class_Metatables"].value().type() == LUA_TNIL)        \
00330      ls["__Diluculum__Class_Metatables"] = Diluculum::EmptyLuaValueMap;       \
00331                                                                               \
00332    DILUCULUM_CLASS_TABLE(CLASS)["classname"] = #CLASS;                        \
00333                                                                               \
00334    DILUCULUM_CLASS_TABLE(CLASS)["new"] =                                      \
00335       Diluculum__ ## CLASS ## __Constructor_Wrapper_Function;                 \
00336                                                                               \
00337    DILUCULUM_CLASS_TABLE(CLASS)["delete"] =                                   \
00338       Diluculum__ ## CLASS ## __Destructor_Wrapper_Function;                  \
00339                                                                               \
00340    DILUCULUM_CLASS_TABLE(CLASS)["__gc"] =                                     \
00341       Diluculum__ ## CLASS ## __Destructor_Wrapper_Function;                  \
00342                                                                               \
00343    DILUCULUM_CLASS_TABLE(CLASS)["__index"] = DILUCULUM_CLASS_TABLE(CLASS);    \
00344                                                                               \
00345    className = DILUCULUM_CLASS_TABLE(CLASS);                                  \
00346                                                                               \
00347    ls["__Diluculum__Class_Metatables"][#CLASS] =                              \
00348       DILUCULUM_CLASS_TABLE(CLASS);                                           \
00349 } /* end of Diluculum_Register_Class__CLASS */
00350 
00351 
00352 
00360 #define DILUCULUM_REGISTER_CLASS(LUA_VARIABLE, CLASS)  \
00361    Diluculum_Register_Class__ ## CLASS (LUA_VARIABLE);
00362 
00363 
00364 
00378 #define DILUCULUM_REGISTER_OBJECT(LUA_VARIABLE, CLASS, OBJECT)                \
00379 {                                                                             \
00380    /* leave the table where 'OBJECT' is to be stored at the stack top */      \
00381    LUA_VARIABLE.pushLastTable();                                              \
00382                                                                               \
00383    /* push the field where the object will be stored */                       \
00384    Diluculum::PushLuaValue (LUA_VARIABLE.getState(),                          \
00385                             LUA_VARIABLE.getKeys().back());                   \
00386                                                                               \
00387    /* create the userdata, set its metatable */                               \
00388    void* ud = lua_newuserdata (LUA_VARIABLE.getState(),                       \
00389                                sizeof(Diluculum::Impl::CppObject));           \
00390                                                                               \
00391    Diluculum::Impl::CppObject* cppObj =                                       \
00392       reinterpret_cast<Diluculum::Impl::CppObject*>(ud);                      \
00393                                                                               \
00394    cppObj->ptr = &OBJECT;                                                     \
00395    cppObj->deleteMe = false;                                                  \
00396                                                                               \
00397    lua_getglobal (LUA_VARIABLE.getState(), "__Diluculum__Class_Metatables");  \
00398    lua_getfield (LUA_VARIABLE.getState(), -1, #CLASS);                        \
00399    lua_setmetatable (LUA_VARIABLE.getState(), -3);                            \
00400                                                                               \
00401    lua_pop (LUA_VARIABLE.getState(), 1); /* pop the table of metatables */    \
00402                                                                               \
00403    /* store the userdata */                                                   \
00404    lua_settable (LUA_VARIABLE.getState(), -3);                                \
00405 }
00406 
00407 
00408 
00424 #define DILUCULUM_BEGIN_MODULE(MODNAME)                  \
00425 extern "C" int luaopen_ ## MODNAME (lua_State *luaState) \
00426 {                                                        \
00427    using Diluculum::LuaState;                            \
00428    using Diluculum::LuaVariable;                         \
00429    using Diluculum::EmptyLuaValueMap;                    \
00430    LuaState ls (luaState);                               \
00431                                                          \
00432    ls[#MODNAME] = EmptyLuaValueMap;                      \
00433    LuaVariable theModule = ls[#MODNAME];
00434 
00435 
00436 
00443 #define DILUCULUM_MODULE_ADD_CLASS(CLASS, LUACLASS)      \
00444    DILUCULUM_REGISTER_CLASS(theModule[LUACLASS], CLASS);
00445 
00446 
00447 
00454 #define DILUCULUM_MODULE_ADD_FUNCTION(CFUNC, LUAFUNC) \
00455    theModule[LUAFUNC] = CFUNC;
00456 
00457 
00458 
00462 #define DILUCULUM_END_MODULE() \
00463    return 1;                   \
00464 }
00465 
00466 #endif // _DILUCULUM_LUA_WRAPPERS_HPP_

Generated on Tue Feb 6 09:30:26 2007 for Diluculum by  doxygen 1.4.6