#ifndef LUASTACK_HPP #define LUASTACK_HPP extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include "luajit.h" } #include #include // LuaSlot // // An LuaSlot contains a lua stack index. It is initialized by the // LuaStack and contains the same index until the LuaStack // is destroyed. You can convert an LuaSlot into a lua stack index // by simply coercing it to 'int'. // // There are three variants of LuaSlot that you can use: LuaArg (function // argument), LuaRet (function return value), and LuaVar (function local // variable). // class LuaSlot { protected: int index_; private: inline operator int() const { return index_; } public: LuaSlot() { index_ = 0; } int index() const { return index_; } friend class LuaStack; }; class LuaArg : public LuaSlot {}; class LuaRet : public LuaSlot {}; class LuaVar : public LuaSlot {}; class LuaSpecial : public LuaSlot { public: LuaSpecial(int n) { index_ = n; } }; extern LuaSpecial LuaRegistry; extern LuaSpecial LuaGlobals; class LuaUpvalue : public LuaSlot { public: LuaUpvalue(int n) { index_ = lua_upvalueindex(n); } }; class LuaNilMarker {}; extern LuaNilMarker LuaNil; class LuaStack { private: int narg_; int ngap_; int nvar_; int nret_; int argpos_; int gappos_; int varpos_; int retpos_; int rettop_; int finaltop_; lua_State *L_; template void count_slots(LuaArg &v, SS & ... stackslots) { count_slots(stackslots...); } template void count_slots(LuaVar &v, SS & ... stackslots) { count_slots(stackslots...); } template void count_slots(LuaRet &v, SS & ... stackslots) { count_slots(stackslots...); } template void count_slots() { count_slots_finalize(NARG, NVAR, NRET); } void count_slots_finalize(int narg, int nvar, int nret); template void assign_slots(int argp, int varp, int retp, LuaArg &v, SS & ... stackslots) { v.index_ = argp; assign_slots(argp + 1, varp, retp, stackslots...); } template void assign_slots(int argp, int varp, int retp, LuaVar &v, SS & ... stackslots) { v.index_ = varp; assign_slots(argp, varp+1, retp, stackslots...); } template void assign_slots(int argp, int varp, int retp, LuaRet &v, SS & ... stackslots) { v.index_ = retp; assign_slots(argp, varp, retp+1, stackslots...); } void assign_slots(int argp, int varp, int retp) {} void clear_frame(); public: template LuaStack(lua_State *L, SS & ... stackslots) { L_ = L; count_slots<0, 0, 0>(stackslots...); if (lua_gettop(L) < narg_) { luaL_error(L, "not enough arguments on stack"); } assign_slots(argpos_, varpos_, retpos_, stackslots...); clear_frame(); } ~LuaStack() {}; int result(); private: // Push any value on the stack, by type. void push_any_value(LuaNilMarker s) const { lua_pushnil(L_); } void push_any_value(LuaSlot s) const { lua_pushvalue(L_, s); } void push_any_value(const std::string &s) const { lua_pushlstring(L_, s.c_str(), s.size()); } void push_any_value(const char *s) const { lua_pushstring(L_, s); } void push_any_value(double s) const { lua_pushnumber(L_, s); } void push_any_value(int s) const { lua_pushnumber(L_, s); } void push_any_value(bool b) const { lua_pushboolean(L_, b ? 1:0); } // Push multiple values on the stack, in order, by type. template void push_any_values(T0 arg0, T... args) { push_any_value(arg0); push_any_values(args...); } void push_any_values() { } private: // Push everything after the CFunction. Used in the implementation // of the 'call' template function. template void push_after_cfunction(LuaSlot s, T... args) { push_after_cfunction(args...); } template void push_after_cfunction(lua_CFunction f, T... args) { push_any_values(args...); } // Call the CFunction, verify that the number of return values is // correct, and pop everything before the CFunction. Used in the // implementation of the 'call' template function. template void call_cfunction_and_pop(int otop, LuaSlot s, T... args) { call_cfunction_and_pop(otop, args...); lua_replace(L_, s); } template void call_cfunction_and_pop(int otop, lua_CFunction fn, T... args) { int nret = fn(L_); check_nret(NRET, otop, nret); } // Check number of return values: xpected number of return values, // original stack top, and number of declared return values. void check_nret(int xnret, int otop, int nret) const; public: template void set(LuaSlot target, T value) const { push_any_value(value); lua_replace(L_, target); } int type(LuaSlot s) const { return lua_type(L_, s); } bool isboolean(LuaSlot s) const { return lua_isboolean(L_, s); } bool iscfunction(LuaSlot s) const { return lua_iscfunction(L_, s); } bool isfunction(LuaSlot s) const { return lua_isfunction(L_, s); } bool islightuserdata(LuaSlot s) const { return lua_islightuserdata(L_, s); } bool isnil(LuaSlot s) const { return lua_isnil(L_, s); } bool isnumber(LuaSlot s) const { return lua_type(L_, s) == LUA_TNUMBER; } bool isstring(LuaSlot s) const { return lua_type(L_, s) == LUA_TSTRING; } bool istable(LuaSlot s) const { return lua_istable(L_, s); } bool isthread(LuaSlot s) const { return lua_isthread(L_, s); } bool isuserdata(LuaSlot s) const { return lua_isuserdata(L_, s); } bool toboolean(LuaSlot s) const { return lua_toboolean(L_, s); } int tointeger(LuaSlot s) const { return lua_tointeger(L_, s); } double tonumber(LuaSlot s) const { return lua_tonumber(L_, s); } std::string tostring(LuaSlot s) const; lua_State *tothread(LuaSlot s) const { return lua_tothread(L_, s); } int checkint(LuaSlot s) const { return luaL_checkint(L_, s); } long checklong(LuaSlot s) const { return luaL_checklong(L_, s); } double checknumber(LuaSlot s) const { return luaL_checknumber(L_, s); } std::string checkstring(LuaSlot s) const; void checktype(LuaSlot s, int t) const { return luaL_checktype(L_, s, t); } void clearmetatable(LuaSlot tab) const; void setmetatable(LuaSlot tab, LuaSlot mt) const; void checknometa(LuaSlot index) const; void newtable(LuaSlot target) const; int next(LuaSlot tab, LuaSlot key, LuaSlot value) const; template void rawget(LuaSlot target, LuaSlot tab, KT key) const { push_any_value(key); lua_rawget(L_, tab); lua_replace(L_, target); } template void rawset(LuaSlot tab, KT key, VT value) const { push_any_value(key); push_any_value(value); lua_rawset(L_, tab); } template void setfield(LuaSlot tab, const char *field, VT value) const { push_any_value(value); lua_setfield(L_, tab, field); } void getfield(LuaSlot target, LuaSlot tab, const char *field) const { lua_getfield(L_, tab, field); lua_replace(L_, target); } // Call invokes any C function. It pushes the arguments on the stack, // calls the cfunction, verifies that the number of return values is as // expected, and pops the return values into LuaVars. template void call(T... args) { int otop = lua_gettop(L_); push_after_cfunction(args...); call_cfunction_and_pop<0>(otop, args...); } }; class LuaFunctionReg { private: int mode_; const char *name_; lua_CFunction func_; LuaFunctionReg *next_; static LuaFunctionReg *LuaFunctionRegistry; public: using List = std::vector; LuaFunctionReg(int m, const char *n, lua_CFunction f); static List all(); int get_mode() const { return mode_; } const char *get_name() const { return name_; } lua_CFunction get_func() const { return func_; } }; #define LuaDefineHidden(name) LuaDefineCore(name, 0) #define LuaDefineGlobalFunction(name) LuaDefineCore(name, 1) #define LuaDefineGlobalMethod(name) LuaDefineCore(name, 2) #define LuaDefineClassMethod(name) LuaDefineCore(name, 3) #define LuaDefineCore(name, mode) \ int name(lua_State *L); \ LuaFunctionReg reg_##name(mode, #name, name); \ int name(lua_State *L) #endif // LUASTACK_HPP