/** Set function environment. * Sets the table on top of the stack as environment of the function * at the given stack index. * @param idx stack index of function */ void LuaContext::setfenv(int idx) { #if LUA_VERSION_NUM > 501 // stack: ... func@idx ... env // find _ENV int n = 0; const char *val_name; while ((val_name = lua_getupvalue(__L, idx, ++n)) != NULL) { // ... env upval if (strcmp(val_name, "_ENV") == 0) { // found environment break; } else { // we're not interested, remove value from stack lua_pop(__L, 1); // ... env } } // found an environment if (val_name != NULL) { // ... env upval // create a new simple up value luaL_loadstring(__L, ""); // ... env upval chunk lua_pushvalue(__L, -3); // ... env upval chunk env lua_setupvalue(__L, -2, 1); // ... env upval func int act_idx = idx > 0 ? idx : idx - 2; lua_upvaluejoin(__L, act_idx, n, -1, 1); // ... env upval chunk lua_pop(__L, 3); // ... } else { throw Exception("No environment found"); } #else lua_setfenv(__L, idx); #endif }
static int db_upvaluejoin (lua_State *L) { int n1 = checkupval(L, 1, 2); int n2 = checkupval(L, 3, 4); luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); lua_upvaluejoin(L, 1, n1, 3, n2); return 0; }
int luaT_setfenv52(lua_State *L, int iIndex) { int iType = lua_type(L, iIndex); switch(iType) { case LUA_TUSERDATA: lua_setuservalue(L, iIndex); return 1; case LUA_TFUNCTION: if(lua_iscfunction(L, iIndex)) { // Our convention: upvalue at #1 is environment if(lua_setupvalue(L, iIndex, 1) == nullptr) { lua_pop(L, 1); return 0; } return 1; } else { // Language convention: upvalue called _ENV is environment, which // might be shared with other functions. const char* sUpName = nullptr; for(int i = 1; (sUpName = lua_getupvalue(L, iIndex, i)) ; ++i) { lua_pop(L, 1); // lua_getupvalue puts the value on the stack, but we just want to replace it if(std::strcmp(sUpName, "_ENV") == 0) { luaL_loadstring(L, "local upv = ... return function() return upv end"); lua_insert(L, -2); lua_call(L, 1, 1); lua_upvaluejoin(L, iIndex, i, -1, 1); lua_pop(L, 1); return 1; } } lua_pop(L, 1); return 0; } default: return 0; } }
void LuaDebug::UpvalueJoin(int funcindex1, int n1, int funcindex2, int n2) const { return lua_upvaluejoin(L(), funcindex1, n1, funcindex2, n2); }