Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/script_engine/src/lib/script_engine/lunar.h @ 8202

Last change on this file since 8202 was 8193, checked in by snellen, 18 years ago

script_engine: swapping to integrate into the ORXONOX framework

File size: 8.3 KB
Line 
1#ifndef _LUNAR_H
2#define _LUNAR_H
3
4#include <string>
5#include <cassert>
6#include "script.h"
7
8#include "luaincl.h"
9#include "executor/executor_lua.h"
10
11
12
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)
21      {
22        if(script != NULL)
23          Register(script->getLuaState());
24      }
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(L);  // 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    };
244
245#endif /* _LUNAR_H */
246
Note: See TracBrowser for help on using the repository browser.