effil/src/cpp/function.cpp

82 lines
2.7 KiB
C++

#include "function.h"
namespace effil {
Function::Function(const sol::function& luaObject) {
assert(luaObject.valid());
assert(luaObject.get_type() == sol::type::function);
lua_State* state = luaObject.lua_state();
sol::stack::push(state, luaObject);
lua_Debug dbgInfo;
lua_getinfo(state, ">u", &dbgInfo); // function is popped from stack here
sol::stack::push(state, luaObject);
ctx_->function = dumpFunction(luaObject);
ctx_->upvalues.resize(dbgInfo.nups);
#if LUA_VERSION_NUM > 501
ctx_->envUpvaluePos = 0; // means no _G upvalue
lua_pushglobaltable(state);
const auto gTable = sol::stack::pop<sol::table>(state);
#endif // LUA_VERSION_NUM > 501
for (unsigned char i = 1; i <= dbgInfo.nups; ++i) {
const char* valueName = lua_getupvalue(state, -1, i); // push value on stack
(void)valueName; // get rid of 'unused' warning for Lua5.1
assert(valueName != nullptr);
#if LUA_VERSION_NUM > 501
if (gTable == sol::stack::get<sol::table>(state)) { // do not serialize _G
sol::stack::pop<sol::object>(state);
ctx_->envUpvaluePos = i;
continue;
}
#endif // LUA_VERSION_NUM > 501
StoredObject storedObject;
try {
const auto& upvalue = sol::stack::pop<sol::object>(state);
storedObject = createStoredObject(upvalue);
assert(storedObject.get() != nullptr);
}
catch(const std::exception& err) {
sol::stack::pop<sol::object>(state);
throw effil::Exception() << "bad function upvalue #" << (int)i << " (" << err.what() << ")";
}
if (storedObject->gcHandle() != nullptr) {
ctx_->addReference(storedObject->gcHandle());
storedObject->releaseStrongReference();
}
ctx_->upvalues[i - 1] = std::move(storedObject);
}
sol::stack::pop<sol::object>(state);
}
sol::object Function::loadFunction(lua_State* state) {
sol::function result = loadString(state, ctx_->function);
assert(result.valid());
sol::stack::push(state, result);
for(size_t i = 0; i < ctx_->upvalues.size(); ++i) {
#if LUA_VERSION_NUM > 501
if (ctx_->envUpvaluePos == i + 1) {
lua_pushglobaltable(state); // push _G to stack
lua_setupvalue(state, -2, i + 1); // pop _G and set as upvalue
continue;
}
#endif // LUA_VERSION_NUM > 501
assert(ctx_->upvalues[i].get() != nullptr);
const auto& obj = ctx_->upvalues[i]->unpack(sol::this_state{state});
sol::stack::push(state, obj);
lua_setupvalue(state, -2, i + 1);
}
return sol::stack::pop<sol::function>(state);
}
} // namespace effil