Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Changeset 8394 in orxonox.OLD for branches/script_engine/src


Ignore:
Timestamp:
Jun 14, 2006, 3:50:07 PM (18 years ago)
Author:
bensch
Message:

restructure step 1.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/script_engine/src/lib/script_engine/lunar.h

    r8385 r8394  
    1111
    1212
    13     template <typename T> class Lunar {
    14       typedef struct { T *pT; } userdataType;
    15     public:
    16       typedef Executor* mfp;
    17       typedef struct { const char *name; mfp mfunc; } RegType;
    18 
    19 
    20       static void Register(Script* script)
     13template <typename T> class Lunar
     14{
     15  typedef struct { T *pT; }
     16  userdataType;
     17public:
     18  typedef Executor* mfp;
     19  typedef struct { const char *name; mfp mfunc; }
     20  RegType;
     21
     22
     23  static void Register(Script* script)
     24  {
     25    if(script != NULL)
     26      Register(script->getLuaState());
     27  }
     28
     29  static void Register(lua_State *L)
     30  {
     31    lua_newtable(L);
     32    int methods = lua_gettop(L);
     33
     34    luaL_newmetatable(L, T::className);
     35    int metatable = lua_gettop(L);
     36
     37    // store method table in globals so that
     38    // scripts can add functions written in Lua.
     39    lua_pushvalue(L, methods);
     40    set(L, LUA_GLOBALSINDEX, T::className);
     41
     42    // hide metatable from Lua getmetatable()
     43    lua_pushvalue(L, methods);
     44    set(L, metatable, "__metatable");
     45
     46    lua_pushvalue(L, methods);
     47    set(L, metatable, "__index");
     48
     49    lua_pushcfunction(L, tostring_T);
     50    set(L, metatable, "__tostring");
     51
     52    lua_pushcfunction(L, gc_T);
     53    set(L, metatable, "__gc");
     54
     55    lua_newtable(L);                // mt for method table
     56    lua_pushcfunction(L, new_T);
     57    lua_pushvalue(L, -1);           // dup new_T function
     58    set(L, methods, "new");         // add new_T to method table
     59    set(L, -3, "__call");           // mt.__call = new_T
     60    lua_setmetatable(L, methods);
     61
     62    // fill method table with methods from class T
     63    for (RegType *l = T::methods; l->name; l++)
     64    {
     65      lua_pushstring(L, l->name);
     66      lua_pushlightuserdata(L, (void*)l);
     67      lua_pushcclosure(L, thunk, 1);
     68      lua_settable(L, methods);
     69    }
     70
     71    lua_pop(L, 2);  // drop metatable and method table
     72  }
     73
     74  // call named lua method from userdata method table
     75  static int call(lua_State *L, const char *method,
     76                  int nargs=0, int nresults=LUA_MULTRET, int errfunc=0)
     77  {
     78    int base = lua_gettop(L) - nargs;  // userdata index
     79    if (!luaL_checkudata(L, base, T::className))
     80    {
     81      lua_settop(L, base-1);           // drop userdata and args
     82      lua_pushfstring(L, "not a valid %s userdata", T::className);
     83      return -1;
     84    }
     85
     86    lua_pushstring(L, method);         // method name
     87    lua_gettable(L, base);             // get method from userdata
     88    if (lua_isnil(L, -1))
     89    {            // no method?
     90      lua_settop(L, base-1);           // drop userdata and args
     91      lua_pushfstring(L, "%s missing method '%s'", T::className, method);
     92      return -1;
     93    }
     94    lua_insert(L, base);               // put method under userdata, args
     95
     96    int status = lua_pcall(L, 1+nargs, nresults, errfunc);  // call method
     97    if (status)
     98    {
     99      const char *msg = lua_tostring(L, -1);
     100      if (msg == NULL) msg = "(error with no message)";
     101      lua_pushfstring(L, "%s:%s status = %d\n%s",
     102                      T::className, method, status, msg);
     103      lua_remove(L, base);             // remove old message
     104      return -1;
     105    }
     106    return lua_gettop(L) - base + 1;   // number of results
     107  }
     108
     109  // push onto the Lua stack a userdata containing a pointer to T object
     110  static int push(lua_State *L, T *obj, bool gc=false)
     111  {
     112    if (!obj) { lua_pushnil(L); return 0; }
     113    luaL_getmetatable(L, T::className);  // lookup metatable in Lua registry
     114    if (lua_isnil(L, -1)) luaL_error(L, "%s missing metatable", T::className);
     115    int mt = lua_gettop(L);
     116    subtable(L, mt, "userdata", "v");
     117    userdataType *ud =
     118      static_cast<userdataType*>(pushuserdata(L, obj, sizeof(userdataType)));
     119    if (ud)
     120    {
     121      ud->pT = obj;  // store pointer to object in userdata
     122      lua_pushvalue(L, mt);
     123      lua_setmetatable(L, -2);
     124      if (gc == false)
    21125      {
    22         if(script != NULL)
    23           Register(script->getLuaState());
     126        lua_checkstack(L, 3);
     127        subtable(L, mt, "do not trash", "k");
     128        lua_pushvalue(L, -2);
     129        lua_pushboolean(L, 1);
     130        lua_settable(L, -3);
     131        lua_pop(L, 1);
    24132      }
    25 
    26       static void Register(lua_State *L) {
    27         lua_newtable(L);
    28         int methods = lua_gettop(L);
    29 
    30         luaL_newmetatable(L, T::className);
    31         int metatable = lua_gettop(L);
    32 
    33         // store method table in globals so that
    34         // scripts can add functions written in Lua.
    35         lua_pushvalue(L, methods);
    36         set(L, LUA_GLOBALSINDEX, T::className);
    37 
    38         // hide metatable from Lua getmetatable()
    39         lua_pushvalue(L, methods);
    40         set(L, metatable, "__metatable");
    41 
    42         lua_pushvalue(L, methods);
    43         set(L, metatable, "__index");
    44 
    45         lua_pushcfunction(L, tostring_T);
    46         set(L, metatable, "__tostring");
    47 
    48         lua_pushcfunction(L, gc_T);
    49         set(L, metatable, "__gc");
    50 
    51         lua_newtable(L);                // mt for method table
    52         lua_pushcfunction(L, new_T);
    53         lua_pushvalue(L, -1);           // dup new_T function
    54         set(L, methods, "new");         // add new_T to method table
    55         set(L, -3, "__call");           // mt.__call = new_T
    56         lua_setmetatable(L, methods);
    57 
    58         // fill method table with methods from class T
    59         for (RegType *l = T::methods; l->name; l++) {
    60           lua_pushstring(L, l->name);
    61           lua_pushlightuserdata(L, (void*)l);
    62           lua_pushcclosure(L, thunk, 1);
    63           lua_settable(L, methods);
    64         }
    65 
    66         lua_pop(L, 2);  // drop metatable and method table
    67       }
    68 
    69       // call named lua method from userdata method table
    70       static int call(lua_State *L, const char *method,
    71                       int nargs=0, int nresults=LUA_MULTRET, int errfunc=0)
    72       {
    73         int base = lua_gettop(L) - nargs;  // userdata index
    74         if (!luaL_checkudata(L, base, T::className)) {
    75           lua_settop(L, base-1);           // drop userdata and args
    76           lua_pushfstring(L, "not a valid %s userdata", T::className);
    77           return -1;
    78         }
    79 
    80         lua_pushstring(L, method);         // method name
    81         lua_gettable(L, base);             // get method from userdata
    82         if (lua_isnil(L, -1)) {            // no method?
    83           lua_settop(L, base-1);           // drop userdata and args
    84           lua_pushfstring(L, "%s missing method '%s'", T::className, method);
    85           return -1;
    86         }
    87         lua_insert(L, base);               // put method under userdata, args
    88 
    89         int status = lua_pcall(L, 1+nargs, nresults, errfunc);  // call method
    90         if (status) {
    91           const char *msg = lua_tostring(L, -1);
    92           if (msg == NULL) msg = "(error with no message)";
    93           lua_pushfstring(L, "%s:%s status = %d\n%s",
    94                           T::className, method, status, msg);
    95           lua_remove(L, base);             // remove old message
    96           return -1;
    97         }
    98         return lua_gettop(L) - base + 1;   // number of results
    99       }
    100 
    101       // push onto the Lua stack a userdata containing a pointer to T object
    102       static int push(lua_State *L, T *obj, bool gc=false) {
    103         if (!obj) { lua_pushnil(L); return 0; }
    104         luaL_getmetatable(L, T::className);  // lookup metatable in Lua registry
    105         if (lua_isnil(L, -1)) luaL_error(L, "%s missing metatable", T::className);
    106         int mt = lua_gettop(L);
    107         subtable(L, mt, "userdata", "v");
    108         userdataType *ud =
    109           static_cast<userdataType*>(pushuserdata(L, obj, sizeof(userdataType)));
    110         if (ud) {
    111           ud->pT = obj;  // store pointer to object in userdata
    112           lua_pushvalue(L, mt);
    113           lua_setmetatable(L, -2);
    114           if (gc == false) {
    115             lua_checkstack(L, 3);
    116             subtable(L, mt, "do not trash", "k");
    117             lua_pushvalue(L, -2);
    118             lua_pushboolean(L, 1);
    119             lua_settable(L, -3);
    120             lua_pop(L, 1);
    121           }
    122         }
    123         lua_replace(L, mt);
    124         lua_settop(L, mt);
    125         return mt;  // index of userdata containing pointer to T object
    126       }
    127 
    128 
    129       static int insertObject(lua_State* L, T* obj, const std::string& name, bool gc=false)
    130       {
    131         int objectRef = push(L, obj, gc);
    132 
    133         lua_pushlstring(L, name.c_str(), name.size());
    134         lua_pushvalue(L, objectRef );
    135         lua_settable(L, LUA_GLOBALSINDEX );
    136 
    137         return objectRef;
    138       }
    139 
    140 
    141       static int insertObject(Script* script, T* obj, const std::string& name, bool gc=false)
    142       {
    143         assert (script != NULL);
    144         return insertObject(script->getLuaState(), obj, name, gc);
    145       }
    146 
    147       // get userdata from Lua stack and return pointer to T object
    148       static T *check(lua_State *L, int narg) {
    149         userdataType *ud =
    150           static_cast<userdataType*>(luaL_checkudata(L, narg, T::className));
    151         if(!ud) luaL_typerror(L, narg, T::className);
    152         return ud->pT;  // pointer to T object
    153       }
    154 
    155     private:
    156       Lunar();  // hide default constructor
    157 
    158       // member function dispatcher
    159       static int thunk(lua_State *L) {
    160         // stack has userdata, followed by method args
    161         T *obj = check(L, 1);  // get 'self', or if you prefer, 'this'
    162         lua_remove(L, 1);  // remove self so member function args start at index 1
    163         // get member function from upvalue
    164         RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
    165         int value;
    166         (*l->mfunc)(obj, value, L);  // call member function
    167         return value;
    168       }
    169 
    170       // create a new T object and
    171       // push onto the Lua stack a userdata containing a pointer to T object
    172       static int new_T(lua_State *L) {
    173         lua_remove(L, 1);   // use classname:new(), instead of classname.new()
    174         T *obj = new T();  // call constructor for T objects
    175         push(L, obj, true); // gc_T will delete this object
    176         return 1;           // userdata containing pointer to T object
    177       }
    178 
    179       // garbage collection metamethod
    180       static int gc_T(lua_State *L) {
    181         if (luaL_getmetafield(L, 1, "do not trash")) {
    182           lua_pushvalue(L, 1);  // dup userdata
    183           lua_gettable(L, -2);
    184           if (!lua_isnil(L, -1)) return 0;  // do not delete object
    185         }
    186         userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
    187         T *obj = ud->pT;
    188         if (obj) delete obj;  // call destructor for T objects
    189         return 0;
    190       }
    191 
    192       static int tostring_T (lua_State *L) {
    193         char buff[32];
    194         userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
    195         T *obj = ud->pT;
    196         sprintf(buff, "%p", obj);
    197         lua_pushfstring(L, "%s (%s)", T::className, buff);
    198         return 1;
    199       }
    200 
    201       static void set(lua_State *L, int table_index, const char *key) {
    202         lua_pushstring(L, key);
    203         lua_insert(L, -2);  // swap value and key
    204         lua_settable(L, table_index);
    205       }
    206 
    207       static void weaktable(lua_State *L, const char *mode) {
    208         lua_newtable(L);
    209         lua_pushvalue(L, -1);  // table is its own metatable
    210         lua_setmetatable(L, -2);
    211         lua_pushliteral(L, "__mode");
    212         lua_pushstring(L, mode);
    213         lua_settable(L, -3);   // metatable.__mode = mode
    214       }
    215 
    216       static void subtable(lua_State *L, int tindex, const char *name, const char *mode) {
    217         lua_pushstring(L, name);
    218         lua_gettable(L, tindex);
    219         if (lua_isnil(L, -1)) {
    220           lua_pop(L, 1);
    221           lua_checkstack(L, 3);
    222           weaktable(L, mode);
    223           lua_pushstring(L, name);
    224           lua_pushvalue(L, -2);
    225           lua_settable(L, tindex);
    226         }
    227       }
    228 
    229       static void *pushuserdata(lua_State *L, void *key, size_t sz) {
    230         void *ud = 0;
    231         lua_pushlightuserdata(L, key);
    232         lua_gettable(L, -2);     // lookup[key]
    233         if (lua_isnil(L, -1)) {
    234           lua_pop(L, 1);         // drop nil
    235           lua_checkstack(L, 3);
    236           ud = lua_newuserdata(L, sz);  // create new userdata
    237           lua_pushlightuserdata(L, key);
    238           lua_pushvalue(L, -2);  // dup userdata
    239           lua_settable(L, -4);   // lookup[key] = userdata
    240         }
    241         return ud;
    242       }
    243     };
     133    }
     134    lua_replace(L, mt);
     135    lua_settop(L, mt);
     136    return mt;  // index of userdata containing pointer to T object
     137  }
     138
     139
     140  static int insertObject(lua_State* L, T* obj, const std::string& name, bool gc=false)
     141  {
     142    int objectRef = push(L, obj, gc);
     143
     144    lua_pushlstring(L, name.c_str(), name.size());
     145    lua_pushvalue(L, objectRef );
     146    lua_settable(L, LUA_GLOBALSINDEX );
     147
     148    return objectRef;
     149  }
     150
     151
     152  static int insertObject(Script* script, T* obj, const std::string& name, bool gc=false)
     153  {
     154    assert (script != NULL);
     155    return insertObject(script->getLuaState(), obj, name, gc);
     156  }
     157
     158  // get userdata from Lua stack and return pointer to T object
     159  static T *check(lua_State *L, int narg)
     160  {
     161    userdataType *ud =
     162      static_cast<userdataType*>(luaL_checkudata(L, narg, T::className));
     163    if(!ud) luaL_typerror(L, narg, T::className);
     164    return ud->pT;  // pointer to T object
     165  }
     166
     167private:
     168  Lunar();  // hide default constructor
     169
     170  // member function dispatcher
     171  static int thunk(lua_State *L)
     172  {
     173    // stack has userdata, followed by method args
     174    T *obj = check(L, 1);  // get 'self', or if you prefer, 'this'
     175    lua_remove(L, 1);  // remove self so member function args start at index 1
     176    // get member function from upvalue
     177    RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
     178    int value;
     179    (*l->mfunc)(obj, value, L);  // call member function
     180    return value;
     181  }
     182
     183  // create a new T object and
     184  // push onto the Lua stack a userdata containing a pointer to T object
     185  static int new_T(lua_State *L)
     186  {
     187    lua_remove(L, 1);   // use classname:new(), instead of classname.new()
     188    T *obj = new T();  // call constructor for T objects
     189    push(L, obj, true); // gc_T will delete this object
     190    return 1;           // userdata containing pointer to T object
     191  }
     192
     193  // garbage collection metamethod
     194  static int gc_T(lua_State *L)
     195  {
     196    if (luaL_getmetafield(L, 1, "do not trash"))
     197    {
     198      lua_pushvalue(L, 1);  // dup userdata
     199      lua_gettable(L, -2);
     200      if (!lua_isnil(L, -1)) return 0;  // do not delete object
     201    }
     202    userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
     203    T *obj = ud->pT;
     204    if (obj) delete obj;  // call destructor for T objects
     205    return 0;
     206  }
     207
     208  static int tostring_T (lua_State *L)
     209  {
     210    char buff[32];
     211    userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
     212    T *obj = ud->pT;
     213    sprintf(buff, "%p", obj);
     214    lua_pushfstring(L, "%s (%s)", T::className, buff);
     215    return 1;
     216  }
     217
     218  static void set(lua_State *L, int table_index, const char *key)
     219  {
     220    lua_pushstring(L, key);
     221    lua_insert(L, -2);  // swap value and key
     222    lua_settable(L, table_index);
     223  }
     224
     225  static void weaktable(lua_State *L, const char *mode)
     226  {
     227    lua_newtable(L);
     228    lua_pushvalue(L, -1);  // table is its own metatable
     229    lua_setmetatable(L, -2);
     230    lua_pushliteral(L, "__mode");
     231    lua_pushstring(L, mode);
     232    lua_settable(L, -3);   // metatable.__mode = mode
     233  }
     234
     235  static void subtable(lua_State *L, int tindex, const char *name, const char *mode)
     236  {
     237    lua_pushstring(L, name);
     238    lua_gettable(L, tindex);
     239    if (lua_isnil(L, -1))
     240    {
     241      lua_pop(L, 1);
     242      lua_checkstack(L, 3);
     243      weaktable(L, mode);
     244      lua_pushstring(L, name);
     245      lua_pushvalue(L, -2);
     246      lua_settable(L, tindex);
     247    }
     248  }
     249
     250  static void *pushuserdata(lua_State *L, void *key, size_t sz)
     251  {
     252    void *ud = 0;
     253    lua_pushlightuserdata(L, key);
     254    lua_gettable(L, -2);     // lookup[key]
     255    if (lua_isnil(L, -1))
     256    {
     257      lua_pop(L, 1);         // drop nil
     258      lua_checkstack(L, 3);
     259      ud = lua_newuserdata(L, sz);  // create new userdata
     260      lua_pushlightuserdata(L, key);
     261      lua_pushvalue(L, -2);  // dup userdata
     262      lua_settable(L, -4);   // lookup[key] = userdata
     263    }
     264    return ud;
     265  }
     266};
    244267
    245268#endif /* _LUNAR_H */
Note: See TracChangeset for help on using the changeset viewer.