00001 #ifndef LUNA_H_ 00002 #define LUNA_H_ 00003 00004 /***************************************************************************** 00005 * .:: Luna ::. * 00006 * * , * * 00007 * C++ library for binding classes into Lua. By nornagon. (( * * 00008 * * ` * 00009 * Example: * 00010 ***************************************************************************** 00011 00012 class Foo { 00013 public: 00014 Foo(lua_State *L) { 00015 printf("in constructor\n"); 00016 } 00017 00018 int foo(lua_State *L) { 00019 printf("in foo\n"); 00020 } 00021 00022 ~Foo() { 00023 printf("in destructor\n"); 00024 } 00025 00026 static const char className[]; 00027 static const Luna<Foo>::RegType Register[]; 00028 }; 00029 00030 const char Foo::className[] = "Foo"; 00031 const Luna<Foo>::RegType Foo::Register[] = { 00032 { "foo", &Foo::foo }, 00033 { 0 } 00034 }; 00035 00036 ***************************************************************************** 00037 * Then: * 00038 ***************************************************************************** 00039 00040 Luna<Foo>::Register(L); 00041 00042 ***************************************************************************** 00043 * From Lua: * 00044 ***************************************************************************** 00045 00046 local foo = Foo() 00047 foo:foo() 00048 00049 ***************************************************************************** 00050 * Clean up: * 00051 ***************************************************************************** 00052 00053 lua_close(L); 00054 00055 ***************************************************************************** 00056 * Output: * 00057 ***************************************************************************** 00058 00059 in constructor 00060 in foo 00061 in destructor 00062 00063 ***************************************************************************** 00064 * This program is free software. It comes without any warranty, to * 00065 * the extent permitted by applicable law. You can redistribute it * 00066 * and/or modify it under the terms of the Do What The Fuck You Want * 00067 * To Public License, Version 2, as published by Sam Hocevar. See * 00068 * http://sam.zoy.org/wtfpl/COPYING for more details. * 00069 ****************************************************************************/ 00070 00071 #ifdef HAVE_LIBLUA5_1 00072 00073 // convenience macros 00074 #define luna_register(L, klass) (Luna<klass>::Register((L))) 00075 #define luna_registermetatable(L, klass) (Luna<klass>::RegisterMetatable((L))) 00076 #define luna_inject(L, klass, t) (Luna<klass>::inject((L), (t))) 00077 00078 extern "C" { 00079 #include "lua5.1/lua.h" 00080 #include "lua5.1/lualib.h" 00081 #include "lua5.1/lauxlib.h" 00082 } 00083 00084 template<class T> class Luna { 00085 public: 00086 static void Register(lua_State *L) { 00087 lua_pushcfunction(L, &Luna<T>::constructor); 00088 lua_setglobal(L, T::className); // T() in lua will make a new instance. 00089 00090 RegisterMetatable(L); 00091 } 00092 00093 // register the metatable without registering the class constructor 00094 static void RegisterMetatable(lua_State *L) { 00095 luaL_newmetatable(L, T::className); // create a metatable in the registry 00096 lua_pushstring(L, "__gc"); 00097 lua_pushcfunction(L, &Luna<T>::gc_obj); 00098 lua_settable(L, -3); // metatable["__gc"] = Luna<T>::gc_obj 00099 lua_pop(L, 1); 00100 } 00101 00102 static int constructor(lua_State *L) { 00103 return inject(L, new T(L)); 00104 } 00105 00106 static int inject(lua_State *L, T* obj) { 00107 lua_newtable(L); // create a new table for the class object ('self') 00108 00109 lua_pushnumber(L, 0); 00110 00111 T** a = static_cast<T**>(lua_newuserdata(L, sizeof(T*))); // store a ptr to the ptr 00112 *a = obj; // set the ptr to the ptr to point to the ptr... >.> 00113 luaL_newmetatable(L, T::className); // get (or create) the unique metatable 00114 lua_setmetatable(L, -2); // self.metatable = uniqe_metatable 00115 00116 lua_settable(L, -3); // self[0] = obj; 00117 00118 for (int i = 0; T::Register[i].name; i++) { // register the functions 00119 lua_pushstring(L, T::Register[i].name); 00120 lua_pushnumber(L, i); // let the thunk know which method we mean 00121 lua_pushcclosure(L, &Luna<T>::thunk, 1); 00122 lua_settable(L, -3); // self["function"] = thunk("function") 00123 } 00124 return 1; 00125 } 00126 00127 static int thunk(lua_State *L) { 00128 // redirect method call to the real thing 00129 int i = (int)lua_tonumber(L, lua_upvalueindex(1)); // which function? 00130 lua_pushnumber(L, 0); 00131 lua_gettable(L, 1); // get the class table (i.e, self) 00132 00133 T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className)); 00134 lua_remove(L, -1); // remove the userdata from the stack 00135 00136 return ((*obj)->*(T::Register[i].mfunc))(L); // execute the thunk 00137 } 00138 00139 static int gc_obj(lua_State *L) { 00140 // clean up 00141 //printf("GC called: %s\n", T::className); 00142 T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className)); 00143 delete (*obj); 00144 return 0; 00145 } 00146 00147 struct RegType { 00148 const char *name; 00149 int(T::*mfunc)(lua_State*); 00150 }; 00151 }; 00152 00153 #endif 00154 #endif /* LUNA_H_ */
1.5.6