Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9850 was 9727, checked in by bensch, 18 years ago

orxonox/new_class_id: new Executor construct, that is much more typesafe, faster, and easier to extend…

Also changed the LoadParam process, and adapted ScriptEngine calls

Then at the end, some missing headers appeared, and appended them to all the cc-files again.

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