Changeset 8394 in orxonox.OLD for branches/script_engine
- Timestamp:
- Jun 14, 2006, 3:50:07 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/script_engine/src/lib/script_engine/lunar.h
r8385 r8394 11 11 12 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) 13 template <typename T> class Lunar 14 { 15 typedef struct { T *pT; } 16 userdataType; 17 public: 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) 21 125 { 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); 24 132 } 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 167 private: 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 }; 244 267 245 268 #endif /* _LUNAR_H */
Note: See TracChangeset
for help on using the changeset viewer.