#include "luastack.hpp" #include LuaSpecial LuaRegistry(LUA_REGISTRYINDEX); LuaSpecial LuaGlobals(LUA_GLOBALSINDEX); LuaNilMarker LuaNil; LuaNewTableMarker LuaNewTable; LuaDiscardMarker LuaDiscard; void LuaStack::make_tagged_pointer(LuaSlot target, void *ptr, LuaTypeTag tag, LuaDeleterFn del) { TaggedPointer *tp = (TaggedPointer*)lua_newuserdata(L_, sizeof(TaggedPointer)); tp->ptr = ptr; tp->tag = tag; tp->del = del; lua_pushlightuserdata(L_, (void*)tag); lua_rawget(L_, LUA_REGISTRYINDEX); if (lua_isnil(L_, -1)) luaL_error(L_, "type not registered with LuaDefineType"); lua_setmetatable(L_, -2); lua_replace(L_, target); } int LuaStack::collect_tagged_pointer(lua_State *L) { LuaStack::TaggedPointer *p = (LuaStack::TaggedPointer*)lua_touserdata(L, 1); if (p==0) { luaL_error(L, "lua deleter function received a non-userdata"); } if (p->ptr == 0) { luaL_error(L, "lua object already deleted"); } p->del(p->ptr); p->ptr = 0; return 0; } void LuaStack::register_all_userdata(lua_State *L) { LuaVar tab, lud; LuaStack LS(L, tab, lud); auto regs = LuaFunctionReg::all(); for (const LuaFunctionReg *r : regs) { const std::string &name = r->get_name(); lua_CFunction tag = r->get_func(); std::string mode = r->get_mode(); if (mode.find('t') != std::string::npos) { // Register type LS.newtable(tab); LS.setfield(tab, "type", name); LS.setfield(tab, "__gc", collect_tagged_pointer); LS.setlightuserdata(lud, (void *)tag); LS.rawset(LuaRegistry, lud, tab); } } LS.result(); } LuaFunctionReg::LuaFunctionReg(const char *m, const char *n, lua_CFunction f) { mode_ = m; name_ = n; func_ = f; next_ = LuaFunctionRegistry; LuaFunctionRegistry = this; } LuaFunctionReg::List LuaFunctionReg::all() { LuaFunctionReg::List result; for (const LuaFunctionReg *r = LuaFunctionRegistry; r != 0; r = r->next_) { result.push_back(r); } return result; } LuaFunctionReg *LuaFunctionReg::LuaFunctionRegistry; void LuaStack::count_slots_finalize(int narg, int nvar, int nret) { narg_ = narg; nret_ = nret; nvar_ = nvar; ngap_ = nret - nvar - narg; if (ngap_ < 0) ngap_ = 0; int argtop = lua_gettop(L_); argpos_ = argtop + 1 - narg_; gappos_ = argpos_ + narg_; varpos_ = gappos_ + ngap_; retpos_ = varpos_ + nvar_; rettop_ = retpos_ + nret_ - 1; finaltop_ = argpos_ + nret_ - 1; } void LuaStack::clear_frame() { lua_settop(L_, varpos_ - 1); for (int i = 0; i < nvar_ + nret_; i++) { lua_pushnil(L_); } } int LuaStack::result() { lua_settop(L_, rettop_); int i = finaltop_; for (int j = 0; j < nret_; j++) { lua_replace(L_, i); i -= 1; } lua_settop(L_, finaltop_); return nret_; } void LuaStack::pop_any_value(std::string &s) const { size_t len; const char *str = luaL_cklstring(L_, -1, &len); s = std::string(str, len); lua_pop(L_, 1); } void LuaStack::pop_any_value(LuaAcceptNilNumber &s) const { if (lua_isnil(L_, -1)) { s.v = 0.0; } else { s.v = luaL_cknumber(L_, -1); } lua_pop(L_, 1); } void LuaStack::pop_any_value(LuaAcceptNilInteger &s) const { if (lua_isnil(L_, -1)) { s.v = 0; } else { s.v = luaL_ckinteger(L_, -1); } lua_pop(L_, 1); } void LuaStack::pop_any_value(LuaAcceptNilString &s) const { if (lua_isnil(L_, -1)) { s.v = ""; } else { size_t len; const char *str = luaL_cklstring(L_, -1, &len); s.v = std::string(str, len); } lua_pop(L_, 1); } std::string LuaStack::ckstring(LuaSlot s) const { size_t len; const char *str = luaL_cklstring(L_, s, &len); return std::string(str, len); } void LuaStack::clearmetatable(LuaSlot tab) const { lua_pushnil(L_); lua_setmetatable(L_, tab); } void LuaStack::setmetatable(LuaSlot tab, LuaSlot mt) const { lua_pushvalue(L_, mt); lua_setmetatable(L_, tab); } void LuaStack::getmetatable(LuaSlot mt, LuaSlot tab) const { lua_getmetatable(L_, tab); lua_replace(L_, mt); } void LuaStack::checknometa(LuaSlot index) const { if (lua_istable(L_, index)) { if (!lua_getmetatable(L_, index)) { return; } } luaL_error(L_, "expected simple table with no metatable"); } int LuaStack::next(LuaSlot tab, LuaSlot key, LuaSlot value) const { lua_pushvalue(L_, key); int ret = lua_next(L_, tab); if (ret != 0) { lua_replace(L_, value); lua_replace(L_, key); } return ret; } bool LuaStack::isemptytable(LuaSlot tab) const { if (lua_istable(L_, tab)) { lua_pushnil(L_); if (lua_next(L_, tab) == 0) { return true; } lua_pop(L_, 2); } return false; } void LuaStack::newtable(LuaSlot target) const { lua_newtable(L_); lua_replace(L_, target); } void LuaStack::setlightuserdata(LuaSlot target, void *p) const { lua_pushlightuserdata(L_, p); lua_replace(L_, target); } void LuaStack::check_nret(int xnret, int otop, int nret) const { int ntop = lua_gettop(L_); if ((nret != xnret)||(ntop != otop + xnret)) { luaL_error(L_, "expected %d return values", xnret); } }