"Fossies" - the Fresh Open Source Software Archive

Member "highlight-3.57-x64/src/include/Diluculum/LuaWrappers.hpp" (12 May 2020, 27648 Bytes) of package /windows/www/highlight-3.57-x64.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /******************************************************************************\
    2 * LuaWrappers.hpp                                                              *
    3 * Making C++ stuff accessible from Lua.                                        *
    4 *                                                                              *
    5 *                                                                              *
    6 * Copyright (C) 2005-2013 by Leandro Motta Barros.                             *
    7 *                                                                              *
    8 * Permission is hereby granted, free of charge, to any person obtaining a copy *
    9 * of this software and associated documentation files (the "Software"), to     *
   10 * deal in the Software without restriction, including without limitation the   *
   11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  *
   12 * sell copies of the Software, and to permit persons to whom the Software is   *
   13 * furnished to do so, subject to the following conditions:                     *
   14 *                                                                              *
   15 * The above copyright notice and this permission notice shall be included in   *
   16 * all copies or substantial portions of the Software.                          *
   17 *                                                                              *
   18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   *
   19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     *
   20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE *
   21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       *
   22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      *
   23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS *
   24 * IN THE SOFTWARE.                                                             *
   25 \******************************************************************************/
   26 
   27 #ifndef _DILUCULUM_LUA_WRAPPERS_HPP_
   28 #define _DILUCULUM_LUA_WRAPPERS_HPP_
   29 
   30 #include <algorithm>
   31 #include <string>
   32 #include <boost/bind.hpp>
   33 #include <Diluculum/CppObject.hpp>
   34 #include <Diluculum/LuaExceptions.hpp>
   35 #include <Diluculum/LuaState.hpp>
   36 #include <Diluculum/LuaUtils.hpp>
   37 
   38 
   39 namespace Diluculum
   40 {
   41    namespace Impl
   42    {
   43       /** Calls \c lua_error() with a proper error message. The error message is
   44        *  composed of things that may help to find out what's the error, like
   45        *  the function name.
   46        *  @param ls The <tt>lua_State*</tt> on which the function will operate.
   47        *  @param what A message to be included in the error message created by
   48        *         this function.
   49        *  @note This is not intended to be called by Diluculum users.
   50        */
   51       void ReportErrorFromCFunction (lua_State* ls, const::std::string& what);
   52 
   53 
   54 
   55       /** Helper class, used by the \c DILUCULUM_CLASS_METHOD() macro, as a
   56        *  means register a method in the table that represents a class being
   57        *  exported to Lua. Everything is done in the constructor. This is just
   58        *  a way to get some code executed in a macro call that happens at the
   59        *  global scope, outside of a function definition.
   60        */
   61       class ClassTableFiller
   62       {
   63          public:
   64             /** Adds the function \c func to the table \c classTable, with a key
   65              *  \c name.
   66              *  @param classTable The table representing the class being
   67              *         exported to Lua.
   68              *  @param name The name by which the method will be known in the
   69              *         Lua side.
   70              *  @param func The C function wrapping the method.
   71              */
   72             ClassTableFiller (Diluculum::LuaValueMap& classTable,
   73                               const std::string& name,
   74                               lua_CFunction func)
   75             {
   76                classTable[name] = func;
   77             }
   78       };
   79    }
   80 }
   81 
   82 
   83 
   84 /** Returns the name of the wrapper function that is created by
   85  *  \c DILUCULUM_WRAP_FUNCTION() for a given function name.
   86  *  @param FUNC The function whose wrapper name is desired.
   87  */
   88 #define DILUCULUM_WRAPPER_FUNCTION(FUNC)        \
   89    Diluculum__ ## FUNC ## __Wrapper_Function
   90 
   91 
   92 
   93 /** Creates a \c lua_CFunction that wraps a function with the signature like the
   94  *  following one:
   95  *  <p><tt>Diluculum::LuaValueList Func (const Diluculum::LuaValueList& params)</tt>
   96  *  <p>Notice that, thanks to the use of <tt>Diluculum::LuaValueList</tt>s, the
   97  *  wrapped function can effectively take and return an arbitrary number of
   98  *  values.
   99  *  @note The name of the created wrapper function is a decorated version of the
  100  *        \c FUNC parameter. The decoration scheme can be quite complicated and
  101  *        is subject to change in future releases of Diluculum, so don't try to
  102  *        use it directly. Use the \c DILUCULUM_WRAPPER_FUNCTION() macro to
  103  *        obtain it instead.
  104  *  @note The proper way to report errors from the function being wrapped is by
  105  *        <tt>throw</tt>ing a \c Diluculum::LuaError. The created wrapper
  106  *        function will handle these exceptions and "translate" them to a call
  107  *        to \c lua_error().
  108  *  @see DILUCULUM_WRAPPER_FUNCTION() To find out the name of the created
  109  *       wrapper function.
  110  *  @param FUNC The function to be wrapped.
  111  */
  112 #define DILUCULUM_WRAP_FUNCTION(FUNC)                                         \
  113 int DILUCULUM_WRAPPER_FUNCTION(FUNC) (lua_State* ls)                          \
  114 {                                                                             \
  115    using std::for_each;                                                       \
  116    using boost::bind;                                                         \
  117    using Diluculum::PushLuaValue;                                             \
  118    using Diluculum::Impl::ReportErrorFromCFunction;                           \
  119                                                                               \
  120    try                                                                        \
  121    {                                                                          \
  122       /* Read parameters and empty the stack */                               \
  123       const int numParams = lua_gettop (ls);                                  \
  124       Diluculum::LuaValueList params;                                         \
  125       for (int i = 1; i <= numParams; ++i)                                    \
  126          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
  127       lua_pop (ls, numParams);                                                \
  128                                                                               \
  129       /* Call the wrapped function */                                         \
  130       Diluculum::LuaValueList ret = FUNC (params);                            \
  131                                                                               \
  132       /* Push the return values and return */                                 \
  133       for_each (ret.begin(), ret.end(), bind (PushLuaValue, ls, _1));         \
  134                                                                               \
  135       return ret.size();                                                      \
  136    }                                                                          \
  137    catch (Diluculum::LuaError& e)                                             \
  138    {                                                                          \
  139       ReportErrorFromCFunction (ls, e.what());                                \
  140       return 0;                                                               \
  141    }                                                                          \
  142    catch(...)                                                                 \
  143    {                                                                          \
  144       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
  145       return 0;                                                               \
  146    }                                                                          \
  147 }
  148 
  149 
  150 
  151 /** Returns the name of the table that represent the class \c CLASS.
  152  *  @note This is used internally. Users can ignore this macro.
  153  */
  154 #define DILUCULUM_CLASS_TABLE(CLASS) \
  155 Diluculum__Class_Table__ ## CLASS
  156 
  157 
  158 
  159 /** Starts a block of class wrapping macro calls. This must be followed by calls
  160  *  to \c DILUCULUM_CLASS_METHOD() for each method to be exported to Lua and a
  161  *  final call to \c DILUCULUM_END_CLASS().
  162  *  @param CLASS The class being exported.
  163  */
  164 #define DILUCULUM_BEGIN_CLASS(CLASS)                                          \
  165 namespace                                                                     \
  166 {                                                                             \
  167    /* the table representing the class */                                     \
  168    Diluculum::LuaValueMap DILUCULUM_CLASS_TABLE(CLASS);                       \
  169 }                                                                             \
  170                                                                               \
  171 /* The Constructor */                                                         \
  172 int Diluculum__ ## CLASS ## __Constructor_Wrapper_Function (lua_State* ls)    \
  173 {                                                                             \
  174    using Diluculum::PushLuaValue;                                             \
  175    using Diluculum::Impl::CppObject;                                          \
  176    using Diluculum::Impl::ReportErrorFromCFunction;                           \
  177                                                                               \
  178    try                                                                        \
  179    {                                                                          \
  180       /* Read parameters and empty the stack */                               \
  181       const int numParams = lua_gettop (ls);                                  \
  182       Diluculum::LuaValueList params;                                         \
  183       for (int i = 1; i <= numParams; ++i)                                    \
  184          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
  185       lua_pop (ls, numParams);                                                \
  186                                                                               \
  187       /* Construct the object, wrap it in a userdata, and return */           \
  188       void* ud = lua_newuserdata (ls, sizeof(CppObject));                     \
  189       CppObject* cppObj = reinterpret_cast<CppObject*>(ud);                   \
  190       cppObj->ptr = new CLASS (params);                                       \
  191       cppObj->deleteMe = true;                                                \
  192                                                                               \
  193       lua_getglobal (ls, "__Diluculum__Class_Metatables");                    \
  194       lua_getfield (ls, -1, #CLASS);                                          \
  195       lua_setmetatable (ls, -3);                                              \
  196       lua_pop (ls, 1); /* pop the table of metatables */                      \
  197                                                                               \
  198       return 1;                                                               \
  199    }                                                                          \
  200    catch (Diluculum::LuaError& e)                                             \
  201    {                                                                          \
  202       ReportErrorFromCFunction (ls, e.what());                                \
  203       return 0;                                                               \
  204    }                                                                          \
  205    catch(...)                                                                 \
  206    {                                                                          \
  207       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
  208       return 0;                                                               \
  209    }                                                                          \
  210 }                                                                             \
  211                                                                               \
  212 /* Destructor */                                                              \
  213 int Diluculum__ ## CLASS ## __Destructor_Wrapper_Function (lua_State* ls)     \
  214 {                                                                             \
  215    using Diluculum::Impl::CppObject;                                          \
  216                                                                               \
  217    CppObject* cppObj =                                                        \
  218       reinterpret_cast<CppObject*>(lua_touserdata (ls, -1));                  \
  219                                                                               \
  220    if (cppObj->deleteMe)                                                      \
  221    {                                                                          \
  222       cppObj->deleteMe = false; /* don't delete again when gc'ed! */          \
  223       CLASS* pObj = reinterpret_cast<CLASS*>(cppObj->ptr);                    \
  224       delete pObj;                                                            \
  225    }                                                                          \
  226                                                                               \
  227    return 0;                                                                  \
  228 }
  229 
  230 
  231 
  232 /** Returns the name of the function used to wrap a method \c METHOD of the
  233  *  class \c CLASS.
  234  *  @note This is used internally. Users can ignore this macro.
  235  */
  236 #define DILUCULUM_METHOD_WRAPPER(CLASS, METHOD)                      \
  237    Diluculum__ ## CLASS ## __ ## METHOD ## __Method_Wrapper_Function
  238 
  239 
  240 
  241 /** Exports a given class' method. This macro must be called between calls to
  242  *  \c DILUCULUM_BEGIN_CLASS() and \c DILUCULUM_END_CLASS().
  243  *  @param CLASS The class whose method is being exported.
  244  *  @param METHOD The method being exported.
  245  */
  246 #define DILUCULUM_CLASS_METHOD(CLASS, METHOD)                                 \
  247 int DILUCULUM_METHOD_WRAPPER(CLASS, METHOD) (lua_State* ls)                   \
  248 {                                                                             \
  249    using std::for_each;                                                       \
  250    using boost::bind;                                                         \
  251    using Diluculum::PushLuaValue;                                             \
  252    using Diluculum::Impl::CppObject;                                          \
  253    using Diluculum::Impl::ReportErrorFromCFunction;                           \
  254                                                                               \
  255    try                                                                        \
  256    {                                                                          \
  257       /* Read parameters and empty the stack */                               \
  258       const int numParams = lua_gettop (ls);                                  \
  259       Diluculum::LuaValue ud = Diluculum::ToLuaValue (ls, 1);                 \
  260       Diluculum::LuaValueList params;                                         \
  261       for (int i = 2; i <= numParams; ++i)                                    \
  262          params.push_back (Diluculum::ToLuaValue (ls, i));                    \
  263       lua_pop (ls, numParams);                                                \
  264                                                                               \
  265       /* Get the object pointer and call the method */                        \
  266       CppObject* cppObj =                                                     \
  267          reinterpret_cast<CppObject*>(ud.asUserData().getData());             \
  268       CLASS* pObj = reinterpret_cast<CLASS*>(cppObj->ptr);                    \
  269                                                                               \
  270       Diluculum::LuaValueList ret = pObj->METHOD (params);                    \
  271                                                                               \
  272       /* Push the return values and return */                                 \
  273       for_each (ret.begin(), ret.end(), bind (PushLuaValue, ls, _1));         \
  274                                                                               \
  275       return ret.size();                                                      \
  276    }                                                                          \
  277    catch (Diluculum::LuaError& e)                                             \
  278    {                                                                          \
  279       ReportErrorFromCFunction (ls, e.what());                                \
  280       return 0;                                                               \
  281    }                                                                          \
  282    catch(...)                                                                 \
  283    {                                                                          \
  284       ReportErrorFromCFunction (ls, "Unknown exception caught by wrapper.");  \
  285       return 0;                                                               \
  286    }                                                                          \
  287 }                                                                             \
  288                                                                               \
  289 namespace                                                                     \
  290 {                                                                             \
  291    Diluculum::Impl::ClassTableFiller                                          \
  292       Diluculum__ ## CLASS ## _ ## METHOD ## __ ## Filler(                    \
  293          DILUCULUM_CLASS_TABLE(CLASS),                                        \
  294          #METHOD,                                                             \
  295          DILUCULUM_METHOD_WRAPPER(CLASS, METHOD));                            \
  296 }
  297 
  298 
  299 
  300 /** Ends a block of class wrapping macro calls (which was opened by a call to
  301  *  \c DILUCULUM_BEGIN_CLASS()).
  302  *  @param CLASS The class being exported.
  303  */
  304 #define DILUCULUM_END_CLASS(CLASS)                                            \
  305                                                                               \
  306 /* The function used to register the class in a 'LuaState' */                 \
  307 void Diluculum_Register_Class__ ## CLASS (Diluculum::LuaVariable className)   \
  308 {                                                                             \
  309    Diluculum::LuaState ls (className.getState());                             \
  310                                                                               \
  311    if (ls["__Diluculum__Class_Metatables"].value().type() == LUA_TNIL)        \
  312      ls["__Diluculum__Class_Metatables"] = Diluculum::EmptyLuaValueMap;       \
  313                                                                               \
  314    static bool isInited = false;                                              \
  315    if (!isInited)                                                             \
  316    {                                                                          \
  317       isInited = true;                                                        \
  318                                                                               \
  319       DILUCULUM_CLASS_TABLE(CLASS)["classname"] = #CLASS;                     \
  320                                                                               \
  321       DILUCULUM_CLASS_TABLE(CLASS)["new"] =                                   \
  322          Diluculum__ ## CLASS ## __Constructor_Wrapper_Function;              \
  323                                                                               \
  324       DILUCULUM_CLASS_TABLE(CLASS)["delete"] =                                \
  325          Diluculum__ ## CLASS ## __Destructor_Wrapper_Function;               \
  326                                                                               \
  327       DILUCULUM_CLASS_TABLE(CLASS)["__gc"] =                                  \
  328          Diluculum__ ## CLASS ## __Destructor_Wrapper_Function;               \
  329                                                                               \
  330       DILUCULUM_CLASS_TABLE(CLASS)["__index"] = DILUCULUM_CLASS_TABLE(CLASS); \
  331    }                                                                          \
  332                                                                               \
  333    className = DILUCULUM_CLASS_TABLE(CLASS);                                  \
  334                                                                               \
  335    ls["__Diluculum__Class_Metatables"][#CLASS] =                              \
  336       DILUCULUM_CLASS_TABLE(CLASS);                                           \
  337 } /* end of Diluculum_Register_Class__CLASS */
  338 
  339 
  340 
  341 /** Registers a class in a given \c Diluculum::LuaState. The class must have
  342  *  been previously exported by calls to \c DILUCULUM_BEGIN_CLASS(),
  343  *  \c DILUCULUM_END_CLASS() and probably \c DILUCULUM_CLASS_METHOD().
  344  *  @param LUA_VARIABLE The \c Diluculum::LuaVariable that will store the class
  345  *         after this call.
  346  *  @param CLASS The class being registered.
  347  */
  348 #define DILUCULUM_REGISTER_CLASS(LUA_VARIABLE, CLASS)  \
  349    Diluculum_Register_Class__ ## CLASS (LUA_VARIABLE);
  350 
  351 
  352 
  353 /** Registers an object instantiated in C++ into a Lua state. This way, this
  354  *  object's methods can be called from Lua. The registered C++ object will
  355  *  \e not be destroyed when the corresponding Lua object is garbage-collected.
  356  *  Destroying it is responsibility of the programmer on the C++ side.
  357  *  @param LUA_VARIABLE The \c Diluculum::LuaVariable where the object will be
  358  *         stored. Notice that a \c Diluculum::LuaVariable contains a reference
  359  *         to a <tt>lua_State*</tt>, so the Lua state in which the object will
  360  *         be stored is passed here, too, albeit indirectly.
  361  *  @param CLASS The class of the object being registered. This class must have
  362  *         been previously registered in the target Lua state with a call to the
  363  *         \c DILUCULUM_REGISTER_CLASS() macro.
  364  *  @param OBJECT The object to be registered to the Lua state.
  365  */
  366 #define DILUCULUM_REGISTER_OBJECT(LUA_VARIABLE, CLASS, OBJECT)                \
  367 {                                                                             \
  368    /* leave the table where 'OBJECT' is to be stored at the stack top */      \
  369    LUA_VARIABLE.pushLastTable();                                              \
  370                                                                               \
  371    /* push the field where the object will be stored */                       \
  372    Diluculum::PushLuaValue (LUA_VARIABLE.getState(),                          \
  373                             LUA_VARIABLE.getKeys().back());                   \
  374                                                                               \
  375    /* create the userdata, set its metatable */                               \
  376    void* ud = lua_newuserdata (LUA_VARIABLE.getState(),                       \
  377                                sizeof(Diluculum::Impl::CppObject));           \
  378                                                                               \
  379    Diluculum::Impl::CppObject* cppObj =                                       \
  380       reinterpret_cast<Diluculum::Impl::CppObject*>(ud);                      \
  381                                                                               \
  382    cppObj->ptr = &OBJECT;                                                     \
  383    cppObj->deleteMe = false;                                                  \
  384                                                                               \
  385    lua_getglobal (LUA_VARIABLE.getState(), "__Diluculum__Class_Metatables");  \
  386    lua_getfield (LUA_VARIABLE.getState(), -1, #CLASS);                        \
  387    lua_setmetatable (LUA_VARIABLE.getState(), -3);                            \
  388                                                                               \
  389    lua_pop (LUA_VARIABLE.getState(), 1); /* pop the table of metatables */    \
  390                                                                               \
  391    /* store the userdata */                                                   \
  392    lua_settable (LUA_VARIABLE.getState(), -3);                                \
  393 }
  394 
  395 
  396 
  397 /** Starts a block declaring a dynamically loadable module, that is, a module
  398  *  that is expected to be compiled as a shared library. The block must be
  399  *  closed by a call to \c DILUCULUM_END_MODULE() and contain some calls to
  400  *  macros like \c DILUCULUM_MODULE_ADD_CLASS() and
  401  *  \c DILUCULUM_MODULE_ADD_FUNCTION() in its body.
  402  *  <p>For those who know the way things happen in Lua, this block will provide
  403  *  a \c luaopen_MyModule() function, which initializes the module when loaded.
  404  *  @param MODNAME The module name. This is how the module will be called in
  405  *         Lua. Also, the dynamic library to which the model will be compiled
  406  *         should be named like this (plus an extension like <tt>.so</tt> or
  407  *         <tt>.dll</tt>). Well, actually the rules for naming the module file
  408  *         are more complex than this. Check the
  409  *         <a href="http://www.lua.org/docs.html">Lua manual</a> for the dirty
  410  *         details.
  411  */
  412 #define DILUCULUM_BEGIN_MODULE(MODNAME)                  \
  413 extern "C" int luaopen_ ## MODNAME (lua_State *luaState) \
  414 {                                                        \
  415    using Diluculum::LuaState;                            \
  416    using Diluculum::LuaVariable;                         \
  417    using Diluculum::EmptyLuaValueMap;                    \
  418    LuaState ls (luaState);                               \
  419                                                          \
  420    ls[#MODNAME] = EmptyLuaValueMap;                      \
  421    LuaVariable theModule = ls[#MODNAME];
  422 
  423 
  424 
  425 /** Adds a class to the module. Must be called between calls to
  426  *  \c DILUCULUM_BEGIN_MODULE() and \c DILUCULUM_END_MODULE().
  427  *  @param CLASS The name of the class being added, as it is known in the
  428  *         C++ side.
  429  *  @param LUACLASS The name by which the class will be known in the Lua side.
  430  */
  431 #define DILUCULUM_MODULE_ADD_CLASS(CLASS, LUACLASS)      \
  432    DILUCULUM_REGISTER_CLASS(theModule[LUACLASS], CLASS);
  433 
  434 
  435 
  436 /** Adds a function to the module. Must be called between calls to
  437  *  \c DILUCULUM_BEGIN_MODULE() and \c DILUCULUM_END_MODULE().
  438  *  @param CFUNC The name of the function being added, as it is known in the
  439  *         C++ side.
  440  *  @param LUAFUNC The name by which the function will be known in the Lua side.
  441  */
  442 #define DILUCULUM_MODULE_ADD_FUNCTION(CFUNC, LUAFUNC) \
  443    theModule[LUAFUNC] = CFUNC;
  444 
  445 
  446 
  447 /** Closes a block (started by \c DILUCULUM_BEGIN_MODULE()) that defines a
  448  *  dynamically loadable Lua module.
  449  *  @bug In principle, this function should return one parameter: the table
  450  *       containing the module (this is more or less a convention). The current
  451  *       implementation not only ignores the convention: it also seems to return
  452  *       something invalid (function looks to be returning 1 without anything on
  453  *       the stack).
  454  */
  455 #define DILUCULUM_END_MODULE() \
  456    return 1;                   \
  457 }
  458 
  459 #endif // _DILUCULUM_LUA_WRAPPERS_HPP_