00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef LUNA_HH_
00018 # define LUNA_HH_
00019
00020 # include "Lua.hh"
00021
00022 # include <cstring>
00023 # include <string>
00024
00032 template <typename T>
00033 class Luna
00034 {
00035 typedef struct { T *pT; } userdataType;
00036
00037 public:
00038 typedef int (T::*mfp)(lua_State *L);
00039
00040 struct RegType {
00041 const char *name;
00042 mfp mfunc;
00043 };
00044
00046 static void registerMethods(lua_State* l);
00047
00049 static T* check(lua_State* l, int narg);
00050
00052 static T* create(lua_State* l);
00053
00057 static int getMethod(lua_State *l, const std::string& funcname);
00058
00059
00060 private:
00061 Luna();
00062
00063
00064 static int thunk(lua_State *L);
00065
00066
00067
00068 static int new_T(lua_State *L);
00069
00070
00071 static int gc_T(lua_State *L);
00072
00073 static int tostring_T(lua_State *L);
00074
00075
00076 static int newindex(lua_State* l);
00077 };
00078
00079 # define luna_method(class, name) { #name, &class::name }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 template <typename T>
00090 inline void Luna<T>::registerMethods(lua_State *l)
00091 {
00092 std::string name(T::className);
00093 size_t idx = name.find_last_of(".");
00094 std::string superclass(name.substr(0, idx));
00095
00096 lua_newtable(l);
00097 int methods = lua_gettop(l);
00098
00099 luaL_newmetatable(l, T::className);
00100 int metatable = lua_gettop(l);
00101
00102
00103
00104 if (idx != std::string::npos)
00105 lua_pushstring(l, name.substr(idx + 1).c_str());
00106 else
00107 lua_pushstring(l, T::className);
00108 lua_pushvalue(l, methods);
00109 lua_settable(l, LUA_GLOBALSINDEX);
00110
00111 lua_pushliteral(l, "__metatable");
00112 lua_pushvalue(l, methods);
00113 lua_settable(l, metatable);
00114
00115 lua_pushcclosure(l, newindex, 0);
00116 lua_setfield(l, metatable, "__newindex");
00117
00118 lua_pushvalue(l, methods);
00119 lua_setfield(l, metatable, "__index");
00120
00121 lua_pushliteral(l, "__tostring");
00122 lua_pushcfunction(l, tostring_T);
00123 lua_settable(l, metatable);
00124
00125 lua_pushliteral(l, "__gc");
00126 lua_pushcfunction(l, gc_T);
00127 lua_settable(l, metatable);
00128
00129 lua_newtable(l);
00130 int mt = lua_gettop(l);
00131 lua_pushliteral(l, "__call");
00132 lua_pushcfunction(l, new_T);
00133 lua_pushliteral(l, "new");
00134 lua_pushvalue(l, -2);
00135 lua_settable(l, methods);
00136 lua_settable(l, mt);
00137 lua_setmetatable(l, methods);
00138
00139
00140 for (RegType *ll = T::methods; ll->name; ll++)
00141 {
00142 lua_pushstring(l, ll->name);
00143 lua_pushlightuserdata(l, (void*)ll);
00144 lua_pushcclosure(l, thunk, 1);
00145 lua_settable(l, methods);
00146 }
00147
00148
00149 if (idx != std::string::npos)
00150 {
00151 luaL_getmetatable(l, superclass.c_str());
00152 if (!lua_istable(l, -1))
00153 luaL_error(l, "superclass '%s' not found", superclass.c_str());
00154 lua_getfield(l, -1, "__index");
00155
00156 lua_pushnil(l);
00157 while (lua_next(l, -2))
00158 {
00159 if (strcmp(lua_tostring(l, -2), "new"))
00160 {
00161 lua_pushvalue(l, -2);
00162 lua_pushvalue(l, -2);
00163 lua_settable(l, methods);
00164 }
00165 lua_pop(l, 1);
00166 }
00167 lua_pop(l, 2);
00168 }
00169
00170 lua_pop(l, 2);
00171 }
00172
00173 template <typename T>
00174 inline T* Luna<T>::check(lua_State *L, int narg)
00175 {
00176 userdataType *ud;
00177
00178 ud = static_cast<userdataType*>(luaL_checkudata(L, narg, T::className));
00179 if (!ud)
00180 luaL_typerror(L, narg, T::className);
00181 return ud->pT;
00182 }
00183
00184 template <typename T>
00185 inline T* Luna<T>::create(lua_State *l)
00186 {
00187 lua_pushnil(l);
00188 lua_insert(l, 1);
00189 new_T(l);
00190 return check(l, -1);
00191 }
00192
00193 template <typename T>
00194 inline int Luna<T>::getMethod(lua_State *l, const std::string& funcname)
00195 {
00196 luaL_getmetatable(l, T::className);
00197 lua_getfield(l, -1, "__index");
00198 lua_remove(l, -2);
00199 lua_getfield(l, -1, funcname.c_str());
00200 lua_remove(l, -2);
00201
00202 if (!lua_isfunction(l, -1))
00203 {
00204
00205 lua_pop(l, 1);
00206 return luaL_error(l, "method not found in %s: %s",
00207 T::className, funcname.c_str());
00208 }
00209
00210
00211 return 1;
00212 }
00213
00214
00215
00216 template <typename T>
00217 inline int Luna<T>::thunk(lua_State *L)
00218 {
00219
00220 T *obj = check(L, 1);
00221 lua_remove(L, 1);
00222
00223 RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
00224 return (obj->*(l->mfunc))(L);
00225 }
00226
00227 template <typename T>
00228 inline int Luna<T>::new_T(lua_State *L)
00229 {
00230 lua_remove(L, 1);
00231 T *obj = new T(L);
00232 userdataType *ud =
00233 static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
00234 ud->pT = obj;
00235 luaL_getmetatable(L, T::className);
00236 lua_setmetatable(L, -2);
00237 return 1;
00238 }
00239
00240 template <typename T>
00241 inline int Luna<T>::gc_T(lua_State *L)
00242 {
00243 userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
00244 T *obj = ud->pT;
00245 delete obj;
00246 return 0;
00247 }
00248
00249 template <typename T>
00250 inline int Luna<T>::tostring_T (lua_State *L)
00251 {
00252 userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
00253 T *obj = ud->pT;
00254 lua_pushfstring(L, "%s (%p)", T::className, obj);
00255 return 1;
00256 }
00257
00258 template <typename T>
00259 inline int Luna<T>::newindex(lua_State* l)
00260 {
00261 if (!lua_isfunction(l, 3))
00262 return luaL_error(l, "attempt to set a value to class %s",
00263 T::className);
00264
00265
00266 std::string name(T::className);
00267 size_t idx = name.find_last_of(".");
00268 std::string superclass(name.substr(0, idx));
00269
00270
00271 luaL_getmetatable(l, superclass.c_str());
00272 lua_getfield(l, -1, "__index");
00273 if (!lua_istable(l, -1))
00274 return luaL_error(l, "newindex: bug");
00275
00276
00277 lua_pushvalue(l, 2);
00278 lua_pushvalue(l, 3);
00279 lua_settable(l, -3);
00280
00281 return 0;
00282 }
00283
00284
00285 #endif // LUNA_HH_