#include "luastack.hpp" #include "util.hpp" #include LuaSpecial LuaRegistry(LUA_REGISTRYINDEX); LuaNilMarker LuaNil; LuaNewTableMarker LuaNewTable; 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; lua_Integer LuaStack::ckinteger(LuaSlot s) const { luaL_checktype(L_, s, LUA_TNUMBER); return lua_tointeger(L_, s); } lua_Number LuaStack::cknumber(LuaSlot s) const { luaL_checktype(L_, s, LUA_TNUMBER); return lua_tonumber(L_, s); } std::string LuaStack::ckstring(LuaSlot s) const { luaL_checktype(L_, s, LUA_TSTRING); size_t len; const char *str = lua_tolstring(L_, s, &len); return std::string(str, len); } lua_State *LuaStack::ckthread(LuaSlot s) const { luaL_checktype(L_, s, LUA_TTHREAD); return lua_tothread(L_, s); } 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(lua_Integer &s) const { luaL_checktype(L_, -1, LUA_TNUMBER); s = lua_tointeger(L_, -1); lua_pop(L_, 1); } void LuaStack::pop_any_value(lua_Number &s) const { luaL_checktype(L_, -1, LUA_TNUMBER); s = lua_tonumber(L_, -1); lua_pop(L_, 1); } void LuaStack::pop_any_value(std::string &s) const { luaL_checktype(L_, -1, LUA_TSTRING); size_t len; const char *str = lua_tolstring(L_, -1, &len); s = std::string(str, len); lua_pop(L_, 1); } 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; } void LuaStack::getglobaltable(LuaSlot target) const { lua_pushglobaltable(L_); lua_replace(L_, target); } void LuaStack::newtable(LuaSlot target) const { lua_newtable(L_); lua_replace(L_, target); } lua_State *LuaStack::newthread(LuaSlot target) const { lua_State *result = lua_newthread(L_); lua_replace(L_, target); return result; } void LuaStack::getclass(LuaSlot classtab, LuaSlot classname) const { lua_checkstack(L_, 20); LuaVar globtab, cname; LuaStack LS(L_, globtab, cname); // Convert class name to a table. if (LS.isstring(classname)) { if (LS.rawequal(classname, "_G")) { luaL_error(L_, "_G is explicitly not allowed as a class name"); } LS.getglobaltable(globtab); LS.rawget(classtab, globtab, classname); if (!LS.istable(classtab)) { luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); } LS.rawget(cname, classtab, "__class"); if (!LS.rawequal(cname, classname)) { luaL_error(L_, "Not a class: %s", lua_tostring(L_, classname)); } } else { LS.set(classtab, classname); if (!LS.istable(classtab)) { luaL_error(L_, "parameter must be a class"); } LS.rawget(cname, classtab, "__class"); if (!LS.isstring(cname)) { luaL_error(L_, "table is not a class"); } } // OK, we're done. LS.result(); } void LuaStack::makeclass(LuaSlot classtab, LuaSlot classname) const { lua_checkstack(L_, 20); LuaVar globtab; LuaStack LS(L_, globtab); // Validate the class name. if (!LS.isstring(classname)) { luaL_error(L_, "Not a class name: %s", lua_tostring(L_, classname)); } if (LS.rawequal(classname, "_G")) { luaL_error(L_, "_G is explicitly not allowed as a class name"); } // Fetch the global environment from the registry. LS.getglobaltable(globtab); // Get the classtab from the global environment. // Create it if it doesn't exist. LS.rawget(classtab, globtab, classname); if (LS.isnil(classtab)) { LS.newtable(classtab); LS.rawset(globtab, classname, classtab); } // If the name isn't bound to a table, abort. if (!LS.istable(classtab)) { luaL_error(L_, "%s is not a class", ckstring(classname).c_str()); } // Repair the special fields. LS.rawset(classtab, "__index", classtab); LS.rawset(classtab, "__class", classname); // Put the stack back. LS.result(); } void LuaStack::makesubtable(LuaSlot sub, LuaSlot tab, const char *name) const { rawget(sub, tab, name); if (istable(sub)) { return; } else if (isnil(sub)) { newtable(sub); rawset(tab, name, sub); return; } else { luaL_error(L_, "%s is not a table", name); } } void LuaStack::cleartable(LuaSlot tab) const { checktable(tab); lua_pushnil(L_); while (lua_next(L_, tab.index()) != 0) { lua_pop(L_, 1); // Pop the old value. lua_pushvalue(L_, -1); // Clone the key lua_pushnil(L_); // Push the new value. lua_settable(L_, tab.index()); } } 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); } }