Simple Cpp Binding |
|
Here is an example of a Lua binding for a simple C++ class. If you prefer, you can factor out all the nasty bits and put them in a template. SimplerCppBinding shows how to do this using Luna for Lua 5.0
extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } class Account { public: Account(double balance) { m_balance = balance; } void deposit(double amount) { m_balance += amount; } void withdraw(double amount) { m_balance -= amount; } double balance(void) { return m_balance; } private: double m_balance; }; class LuaAccount { static const char className[]; static const luaL_reg methods[]; static Account *checkaccount(lua_State *L, int narg) { luaL_checktype(L, narg, LUA_TUSERDATA); void *ud = luaL_checkudata(L, narg, className); if(!ud) luaL_typerror(L, narg, className); return *(Account**)ud; // unbox pointer } static int create_account(lua_State *L) { double balance = luaL_checknumber(L, 1); Account *a = new Account(balance); lua_boxpointer(L, a); luaL_getmetatable(L, className); lua_setmetatable(L, -2); return 1; } static int deposit(lua_State *L) { Account *a = checkaccount(L, 1); double amount = luaL_checknumber(L, 2); a->deposit(amount); return 0; } static int withdraw(lua_State *L) { Account *a = checkaccount(L, 1); double amount = luaL_checknumber(L, 2); a->withdraw(amount); return 0; } static int balance(lua_State *L) { Account *a = checkaccount(L, 1); double balance = a->balance(); lua_pushnumber(L, balance); return 1; } static int gc_account(lua_State *L) { Account *a = (Account*)lua_unboxpointer(L, 1); delete a; return 0; } public: static void Register(lua_State* L) { lua_newtable(L); int methodtable = lua_gettop(L); luaL_newmetatable(L, className); int metatable = lua_gettop(L); lua_pushliteral(L, "__metatable"); lua_pushvalue(L, methodtable); lua_settable(L, metatable); // hide metatable from Lua getmetatable() lua_pushliteral(L, "__index"); lua_pushvalue(L, methodtable); lua_settable(L, metatable); lua_pushliteral(L, "__gc"); lua_pushcfunction(L, gc_account); lua_settable(L, metatable); lua_pop(L, 1); // drop metatable luaL_openlib(L, 0, methods, 0); // fill methodtable lua_pop(L, 1); // drop methodtable lua_register(L, className, create_account); } }; const char LuaAccount::className[] = "Account"; #define method(class, name) {#name, class::name} const luaL_reg LuaAccount::methods[] = { method(LuaAccount, deposit), method(LuaAccount, withdraw), method(LuaAccount, balance), {0,0} }; int main(int argc, char* argv[]) { lua_State *L = lua_open(); luaopen_base(L); luaopen_table(L); luaopen_io(L); luaopen_string(L); luaopen_math(L); luaopen_debug(L); LuaAccount::Register(L); if(argc>1) lua_dofile(L, argv[1]); lua_close(L); return 0; }
This code can be compiled for Lua 5.0 as follows:
g++ -o test account.cc -L/usr/local/lib -llua -llualib
function printf(...) io.write(string.format(unpack(arg))) end local a = Account(100) printf("Account balance = $%0.02f\n", a:balance() ) a:deposit(50.30) printf("Account balance = $%0.02f\n", a:balance() ) a:withdraw(25.10) printf("Account balance = $%0.02f\n", a:balance() )
$ ./test account.lua Account balance = $100.00 Account balance = $150.30 Account balance = $125.20