From a6247ecf707ae9c28c259bb1cec02e92e87d135e Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Wed, 29 May 2024 15:31:52 +0200 Subject: Organized namespace 'state' --- src/lanes.cpp | 4 +- src/state.cpp | 529 ++++++++++++++++++++++++++++--------------------------- src/state.h | 13 +- src/universe.cpp | 4 +- 4 files changed, 283 insertions(+), 267 deletions(-) diff --git a/src/lanes.cpp b/src/lanes.cpp index 04b0955..9fc7fc9 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp @@ -240,7 +240,7 @@ LUAG_FUNC(lane_new) DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl); std::optional _libs_str{ lua_isnil(L_, kLibsIdx) ? std::nullopt : std::make_optional(lua_tostringview(L_, kLibsIdx)) }; - lua_State* const _L2{ luaG_newstate(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2: + lua_State* const _L2{ state::NewLaneState(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2: STACK_CHECK_START_REL(_L2, 0); // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) @@ -663,7 +663,7 @@ LUAG_FUNC(configure) // Linked chains handling _U->selfdestructFirst = SELFDESTRUCT_END; _U->initializeAllocatorFunction(L_); - InitializeOnStateCreate(_U, L_); + state::InitializeOnStateCreate(_U, L_); _U->initializeKeepers(L_); STACK_CHECK(L_, 1); diff --git a/src/state.cpp b/src/state.cpp index b747a9f..5589c30 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -43,17 +43,23 @@ THE SOFTWARE. // ################################################################################################# -/*---=== luaG_newstate ===---*/ - -[[nodiscard]] static int require_lanes_core(lua_State* L_) -{ - // leaves a copy of 'lanes.core' module table on the stack - luaL_requiref(L_, kLanesCoreLibName, luaopen_lanes_core, 0); - return 1; -} +static constexpr char const* kOnStateCreate{ "on_state_create" }; // update lanes.lua if the name changes! +// ################################################################################################# // ################################################################################################# namespace { + // ############################################################################################# + // ############################################################################################# + + [[nodiscard]] static int require_lanes_core(lua_State* L_) + { + // leaves a copy of 'lanes.core' module table on the stack + luaL_requiref(L_, kLanesCoreLibName, luaopen_lanes_core, 0); + return 1; + } + + // ############################################################################################# + namespace local { static luaL_Reg const sLibs[] = { { "base", nullptr }, // ignore "base" (already acquired it) @@ -87,291 +93,302 @@ namespace { }; } // namespace local -} // namespace -// ################################################################################################# + // ############################################################################################# -static void Open1Lib(lua_State* L_, std::string_view const& name_) -{ - for (luaL_Reg const& _entry : local::sLibs) { - if (name_ == _entry.name) { - lua_CFunction const _libfunc{ _entry.func }; - if (!_libfunc) { + static void Open1Lib(lua_State* L_, std::string_view const& name_) + { + for (luaL_Reg const& _entry : local::sLibs) { + if (name_ == _entry.name) { + lua_CFunction const _libfunc{ _entry.func }; + if (!_libfunc) { + break; + } + std::string_view const _name{ _entry.name }; + DEBUGSPEW_CODE(DebugSpew(universe_get(L_)) << "opening '" << _name << "' library" << std::endl); + STACK_CHECK_START_REL(L_, 0); + // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) + bool const isLanesCore{ _libfunc == require_lanes_core }; // don't want to create a global for "lanes.core" + luaL_requiref(L_, _name.data(), _libfunc, !isLanesCore); // L_: {lib} + // lanes.core doesn't declare a global, so scan it here and now + if (isLanesCore) { + tools::PopulateFuncLookupTable(L_, -1, _name); + } + lua_pop(L_, 1); // L_: + STACK_CHECK(L_, 0); break; } - std::string_view const _name{ _entry.name }; - DEBUGSPEW_CODE(DebugSpew(universe_get(L_)) << "opening '" << _name << "' library" << std::endl); - STACK_CHECK_START_REL(L_, 0); - // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) - bool const isLanesCore{ _libfunc == require_lanes_core }; // don't want to create a global for "lanes.core" - luaL_requiref(L_, _name.data(), _libfunc, !isLanesCore); // L_: {lib} - // lanes.core doesn't declare a global, so scan it here and now - if (isLanesCore) { - tools::PopulateFuncLookupTable(L_, -1, _name); - } - lua_pop(L_, 1); // L_: - STACK_CHECK(L_, 0); - break; } } -} -// ################################################################################################# + // ############################################################################################# -// just like lua_xmove, args are (from, to) -static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_) -{ - DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); + // just like lua_xmove, args are (from, to) + static void CopyOneTimeSettings(Universe* U_, SourceState L1_, DestState L2_) + { + DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); - STACK_GROW(L1_, 2); - STACK_CHECK_START_REL(L1_, 0); - STACK_CHECK_START_REL(L2_, 0); + STACK_GROW(L1_, 2); + STACK_CHECK_START_REL(L1_, 0); + STACK_CHECK_START_REL(L2_, 0); - DEBUGSPEW_CODE(DebugSpew(U_) << "copy_one_time_settings()" << std::endl); + DEBUGSPEW_CODE(DebugSpew(U_) << "CopyOneTimeSettings()" << std::endl); - kConfigRegKey.pushValue(L1_); // L1_: config - // copy settings from from source to destination registry - InterCopyContext _c{ U_, L2_, L1_, {}, {}, {}, {}, {} }; - if (_c.inter_move(1) != InterCopyResult::Success) { // L1_: L2_: config - raise_luaL_error(L1_, "failed to copy settings when loading " kLanesCoreLibName); + kConfigRegKey.pushValue(L1_); // L1_: config + // copy settings from from source to destination registry + InterCopyContext _c{ U_, L2_, L1_, {}, {}, {}, {}, {} }; + if (_c.inter_move(1) != InterCopyResult::Success) { // L1_: L2_: config + raise_luaL_error(L1_, "failed to copy settings when loading " kLanesCoreLibName); + } + // set L2:_R[kConfigRegKey] = settings + kConfigRegKey.setValue(L2_, [](lua_State* L_) { lua_insert(L_, -2); }); // L1_: L2_: config + STACK_CHECK(L2_, 0); + STACK_CHECK(L1_, 0); } - // set L2:_R[kConfigRegKey] = settings - kConfigRegKey.setValue(L2_, [](lua_State* L_) { lua_insert(L_, -2); }); // L1_: L2_: config - STACK_CHECK(L2_, 0); - STACK_CHECK(L1_, 0); -} + // ############################################################################################# + // ############################################################################################# +} // namespace +// ################################################################################################# // ################################################################################################# -static constexpr char const* kOnStateCreate{ "on_state_create" }; // update lanes.lua if the name changes! +// ################################################################################################# +// ################################################################################################# +namespace state { + // ############################################################################################# + // ############################################################################################# + + void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_) + { + if (U_->onStateCreateFunc == nullptr) { + return; + } -void InitializeOnStateCreate(Universe* U_, lua_State* L_) -{ - STACK_CHECK_START_REL(L_, 1); // L_: settings - if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil - // store C function pointer in an internal variable - U_->onStateCreateFunc = lua_tocfunction(L_, -1); // L_: settings on_state_create - if (U_->onStateCreateFunc != nullptr) { - // make sure the function doesn't have upvalues - char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval? - if (_upname != nullptr) { // should be "" for C functions with upvalues if any - raise_luaL_error(L_, "%s shouldn't have upvalues", kOnStateCreate); + STACK_CHECK_START_REL(L_, 0); + DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl); + if (U_->onStateCreateFunc != reinterpret_cast(InitializeOnStateCreate)) { + // C function: recreate a closure in the new state, bypassing the lookup scheme + lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create() + } else { // Lua function located in the config table, copied when we opened "lanes.core" + if (mode_ != LookupMode::LaneBody) { + // if attempting to call in a keeper state, do nothing because the function doesn't exist there + // this doesn't count as an error though + STACK_CHECK(L_, 0); + return; } - // remove this C function from the config table so that it doesn't cause problems - // when we transfer the config table in newly created Lua states - lua_pushnil(L_); // L_: settings on_state_create nil - lua_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create - } else { - // optim: store marker saying we have such a function in the config table - U_->onStateCreateFunc = reinterpret_cast(InitializeOnStateCreate); + kConfigRegKey.pushValue(L_); // L_: {} + STACK_CHECK(L_, 1); + std::ignore = luaG_getfield(L_, -1, kOnStateCreate); // L_: {} on_state_create() + lua_remove(L_, -2); // L_: on_state_create() + } + STACK_CHECK(L_, 1); + // capture error and raise it in caller state + std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; + std::ignore = lua_pushstringview(L_, _stateType); // L_: on_state_create() "" + if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { + raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate, lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1))); } + STACK_CHECK(L_, 0); } - lua_pop(L_, 1); // L_: settings - STACK_CHECK(L_, 1); -} -// ################################################################################################# + // ############################################################################################# -lua_State* create_state([[maybe_unused]] Universe* U_, lua_State* from_) -{ - lua_State* const _L { - std::invoke( - [U = U_, from = from_]() { - if constexpr (LUAJIT_FLAVOR() == 64) { - // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... - return luaL_newstate(); - } else { - if (U->provideAllocator != nullptr) { // we have a function we can call to obtain an allocator - lua_pushcclosure(from, U->provideAllocator, 0); - lua_call(from, 0, 1); - AllocatorDefinition* const _def{ lua_tofulluserdata(from, -1) }; - lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) }; - lua_pop(from, 1); - return _L; + lua_State* CreateState([[maybe_unused]] Universe* U_, lua_State* from_) + { + lua_State* const _L { + std::invoke( + [U = U_, from = from_]() { + if constexpr (LUAJIT_FLAVOR() == 64) { + // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... + return luaL_newstate(); } else { - // reuse the allocator provided when the master state was created - return lua_newstate(U->protectedAllocator.allocF, U->protectedAllocator.allocUD); + if (U->provideAllocator != nullptr) { // we have a function we can call to obtain an allocator + lua_pushcclosure(from, U->provideAllocator, 0); + lua_call(from, 0, 1); + AllocatorDefinition* const _def{ lua_tofulluserdata(from, -1) }; + lua_State* const _L{ lua_newstate(_def->allocF, _def->allocUD) }; + lua_pop(from, 1); + return _L; + } else { + // reuse the allocator provided when the master state was created + return lua_newstate(U->protectedAllocator.allocF, U->protectedAllocator.allocUD); + } } } - } - ) - }; - - if (_L == nullptr) { - raise_luaL_error(from_, "luaG_newstate() failed while creating state; out of memory"); - } - return _L; -} - -// ################################################################################################# + ) + }; -void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_) -{ - if (U_->onStateCreateFunc == nullptr) { - return; + if (_L == nullptr) { + raise_luaL_error(from_, "luaG_newstate() failed while creating state; out of memory"); + } + return _L; } - STACK_CHECK_START_REL(L_, 0); - DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl); - if (U_->onStateCreateFunc != reinterpret_cast(InitializeOnStateCreate)) { - // C function: recreate a closure in the new state, bypassing the lookup scheme - lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create() - } else { // Lua function located in the config table, copied when we opened "lanes.core" - if (mode_ != LookupMode::LaneBody) { - // if attempting to call in a keeper state, do nothing because the function doesn't exist there - // this doesn't count as an error though - STACK_CHECK(L_, 0); - return; + // ############################################################################################# + + void InitializeOnStateCreate(Universe* U_, lua_State* L_) + { + STACK_CHECK_START_REL(L_, 1); // L_: settings + if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil + // store C function pointer in an internal variable + U_->onStateCreateFunc = lua_tocfunction(L_, -1); // L_: settings on_state_create + if (U_->onStateCreateFunc != nullptr) { + // make sure the function doesn't have upvalues + char const* _upname{ lua_getupvalue(L_, -1, 1) }; // L_: settings on_state_create upval? + if (_upname != nullptr) { // should be "" for C functions with upvalues if any + raise_luaL_error(L_, "%s shouldn't have upvalues", kOnStateCreate); + } + // remove this C function from the config table so that it doesn't cause problems + // when we transfer the config table in newly created Lua states + lua_pushnil(L_); // L_: settings on_state_create nil + lua_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create + } else { + // optim: store marker saying we have such a function in the config table + U_->onStateCreateFunc = reinterpret_cast(InitializeOnStateCreate); + } } - kConfigRegKey.pushValue(L_); // L_: {} + lua_pop(L_, 1); // L_: settings STACK_CHECK(L_, 1); - std::ignore = luaG_getfield(L_, -1, kOnStateCreate); // L_: {} on_state_create() - lua_remove(L_, -2); // L_: on_state_create() } - STACK_CHECK(L_, 1); - // capture error and raise it in caller state - std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; - std::ignore = lua_pushstringview(L_, _stateType); // L_: on_state_create() "" - if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { - raise_luaL_error(from_, "%s failed: \"%s\"", kOnStateCreate, lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1))); - } - STACK_CHECK(L_, 0); -} -// ################################################################################################# - -/* - * Like 'luaL_openlibs()' but allows the set of libraries be selected - * - * nullptr no libraries, not even base - * "" base library only - * "io,string" named libraries - * "*" all libraries - * - * Base ("unpack", "print" etc.) is always added, unless 'libs' is nullptr. - * - * *NOT* called for keeper states! - * - */ -lua_State* luaG_newstate(Universe* U_, SourceState from_, std::optional const& libs_) -{ - DestState const _L{ create_state(U_, from_) }; - - STACK_GROW(_L, 2); - STACK_CHECK_START_ABS(_L, 0); - - // copy the universe as a light userdata (only the master state holds the full userdata) - // that way, if Lanes is required in this new state, we'll know we are part of this universe - universe_store(_L, U_); - STACK_CHECK(_L, 0); - - // we'll need this every time we transfer some C function from/to this state - kLookupRegKey.setValue(_L, [](lua_State* L_) { lua_newtable(L_); }); - STACK_CHECK(_L, 0); - - // neither libs (not even 'base') nor special init func: we are done - if (!libs_.has_value() && U_->onStateCreateFunc == nullptr) { - DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl); - return _L; - } + // ############################################################################################# + + /* + * Like 'luaL_openlibs()' but allows the set of libraries be selected + * + * nullptr no libraries, not even base + * "" base library only + * "io,string" named libraries + * "*" all libraries + * + * Base ("unpack", "print" etc.) is always added, unless 'libs' is nullptr. + * + */ + lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional const& libs_) + { + DestState const _L{ CreateState(U_, from_) }; + + STACK_GROW(_L, 2); + STACK_CHECK_START_ABS(_L, 0); + + // copy the universe as a light userdata (only the master state holds the full userdata) + // that way, if Lanes is required in this new state, we'll know we are part of this universe + universe_store(_L, U_); + STACK_CHECK(_L, 0); + + // we'll need this every time we transfer some C function from/to this state + kLookupRegKey.setValue(_L, [](lua_State* L_) { lua_newtable(L_); }); + STACK_CHECK(_L, 0); + + // neither libs (not even 'base') nor special init func: we are done + if (!libs_.has_value() && U_->onStateCreateFunc == nullptr) { + DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl); + return _L; + } - DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate()" << std::endl); - DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); - - // copy settings (for example because it may contain a Lua on_state_create function) - copy_one_time_settings(U_, from_, _L); - - // 'lua.c' stops GC during initialization so perhaps it is a good idea. :) - lua_gc(_L, LUA_GCSTOP, 0); - - // Anything causes 'base' and 'jit' to be taken in - std::string_view _libs{}; - if (libs_.has_value()) { - _libs = libs_.value(); - // special "*" case (mainly to help with LuaJIT compatibility) - // as we are called from luaopen_lanes_core() already, and that would deadlock - if (_libs == "*") { - DEBUGSPEW_CODE(DebugSpew(U_) << "opening ALL standard libraries" << std::endl); - luaL_openlibs(_L); - // don't forget lanes.core for regular lane states - Open1Lib(_L, kLanesCoreLibName); - _libs = ""; // done with libs - } else { - if constexpr (LUAJIT_FLAVOR() != 0) { // building against LuaJIT headers, always open jit - DEBUGSPEW_CODE(DebugSpew(U_) << "opening 'jit' library" << std::endl); - Open1Lib(_L, LUA_JITLIBNAME); - } - DEBUGSPEW_CODE(DebugSpew(U_) << "opening 'base' library" << std::endl); - if constexpr (LUA_VERSION_NUM >= 502) { - // open base library the same way as in luaL_openlibs() - luaL_requiref(_L, LUA_GNAME, luaopen_base, 1); - lua_pop(_L, 1); + DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate()" << std::endl); + DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); + + // copy settings (for example because it may contain a Lua on_state_create function) + CopyOneTimeSettings(U_, from_, _L); + + // 'lua.c' stops GC during initialization so perhaps it is a good idea. :) + lua_gc(_L, LUA_GCSTOP, 0); + + // Anything causes 'base' and 'jit' to be taken in + std::string_view _libs{}; + if (libs_.has_value()) { + _libs = libs_.value(); + // special "*" case (mainly to help with LuaJIT compatibility) + // as we are called from luaopen_lanes_core() already, and that would deadlock + if (_libs == "*") { + DEBUGSPEW_CODE(DebugSpew(U_) << "opening ALL standard libraries" << std::endl); + luaL_openlibs(_L); + // don't forget lanes.core for regular lane states + Open1Lib(_L, kLanesCoreLibName); + _libs = ""; // done with libs } else { - lua_pushcfunction(_L, luaopen_base); - lua_pushstring(_L, ""); - lua_call(_L, 1, 0); + if constexpr (LUAJIT_FLAVOR() != 0) { // building against LuaJIT headers, always open jit + DEBUGSPEW_CODE(DebugSpew(U_) << "opening 'jit' library" << std::endl); + Open1Lib(_L, LUA_JITLIBNAME); + } + DEBUGSPEW_CODE(DebugSpew(U_) << "opening 'base' library" << std::endl); + if constexpr (LUA_VERSION_NUM >= 502) { + // open base library the same way as in luaL_openlibs() + luaL_requiref(_L, LUA_GNAME, luaopen_base, 1); + lua_pop(_L, 1); + } else { + lua_pushcfunction(_L, luaopen_base); + lua_pushstring(_L, ""); + lua_call(_L, 1, 0); + } } } - } - STACK_CHECK(_L, 0); - - // scan all libraries, open them one by one - if (!_libs.empty()) { - unsigned int _len{ 0 }; - for (char const* _p{ _libs.data() }; *_p; _p += _len) { - // skip delimiters ('.' can be part of name for "lanes.core") - while (*_p && !std::isalnum(*_p) && *_p != '.') { - ++_p; - } - // skip name - _len = 0; - while (std::isalnum(_p[_len]) || _p[_len] == '.') { - ++_len; + STACK_CHECK(_L, 0); + + // scan all libraries, open them one by one + if (!_libs.empty()) { + unsigned int _len{ 0 }; + for (char const* _p{ _libs.data() }; *_p; _p += _len) { + // skip delimiters ('.' can be part of name for "lanes.core") + while (*_p && !std::isalnum(*_p) && *_p != '.') { + ++_p; + } + // skip name + _len = 0; + while (std::isalnum(_p[_len]) || _p[_len] == '.') { + ++_len; + } + // open library + Open1Lib(_L, { _p, _len }); } - // open library - Open1Lib(_L, { _p, _len }); } - } - lua_gc(_L, LUA_GCRESTART, 0); - - tools::SerializeRequire(_L); - - // call this after the base libraries are loaded and GC is restarted - // will raise an error in from_ in case of problem - CallOnStateCreate(U_, _L, from_, LookupMode::LaneBody); - - STACK_CHECK(_L, 0); - // after all this, register everything we find in our name<->function database - lua_pushglobaltable(_L); // L: _G - tools::PopulateFuncLookupTable(_L, -1, {}); - lua_pop(_L, 1); // L: - STACK_CHECK(_L, 0); - - if constexpr (USE_DEBUG_SPEW()) { - DEBUGSPEW_CODE(DebugSpew(U_) << std::source_location::current().function_name() << " LOOKUP DB CONTENTS" << std::endl); - DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ U_ }); - // dump the lookup database contents - kLookupRegKey.pushValue(_L); // L: {} - lua_pushnil(_L); // L: {} nil - while (lua_next(_L, -2)) { // L: {} k v - std::ignore = lua_pushstringview(_L, "["); // L: {} k v "[" - - lua_getglobal(_L, "tostring"); // L: {} k v "[" tostring - lua_pushvalue(_L, -4); // L: {} k v "[" tostring k - lua_call(_L, 1, 1); // L: {} k v "[" 'k' - - std::ignore = lua_pushstringview(_L, "] = "); // L: {} k v "[" 'k' "] = " - - lua_getglobal(_L, "tostring"); // L: {} k v "[" 'k' "] = " tostring - lua_pushvalue(_L, -5); // L: {} k v "[" 'k' "] = " tostring v - lua_call(_L, 1, 1); // L: {} k v "[" 'k' "] = " 'v' - lua_concat(_L, 4); // L: {} k v "[k] = v" - DEBUGSPEW_CODE(DebugSpew(U_) << lua_tostringview(_L, -1) << std::endl); - lua_pop(_L, 2); // L: {} k - } // lua_next() // L: {} + lua_gc(_L, LUA_GCRESTART, 0); + + tools::SerializeRequire(_L); + + // call this after the base libraries are loaded and GC is restarted + // will raise an error in from_ in case of problem + CallOnStateCreate(U_, _L, from_, LookupMode::LaneBody); + + STACK_CHECK(_L, 0); + // after all this, register everything we find in our name<->function database + lua_pushglobaltable(_L); // L: _G + tools::PopulateFuncLookupTable(_L, -1, {}); lua_pop(_L, 1); // L: + STACK_CHECK(_L, 0); + + if constexpr (USE_DEBUG_SPEW()) { + DEBUGSPEW_CODE(DebugSpew(U_) << std::source_location::current().function_name() << " LOOKUP DB CONTENTS" << std::endl); + DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ U_ }); + // dump the lookup database contents + kLookupRegKey.pushValue(_L); // L: {} + lua_pushnil(_L); // L: {} nil + while (lua_next(_L, -2)) { // L: {} k v + std::ignore = lua_pushstringview(_L, "["); // L: {} k v "[" + + lua_getglobal(_L, "tostring"); // L: {} k v "[" tostring + lua_pushvalue(_L, -4); // L: {} k v "[" tostring k + lua_call(_L, 1, 1); // L: {} k v "[" 'k' + + std::ignore = lua_pushstringview(_L, "] = "); // L: {} k v "[" 'k' "] = " + + lua_getglobal(_L, "tostring"); // L: {} k v "[" 'k' "] = " tostring + lua_pushvalue(_L, -5); // L: {} k v "[" 'k' "] = " tostring v + lua_call(_L, 1, 1); // L: {} k v "[" 'k' "] = " 'v' + lua_concat(_L, 4); // L: {} k v "[k] = v" + DEBUGSPEW_CODE(DebugSpew(U_) << lua_tostringview(_L, -1) << std::endl); + lua_pop(_L, 2); // L: {} k + } // lua_next() // L: {} + lua_pop(_L, 1); // L: + } + + STACK_CHECK(_L, 0); + return _L; } - STACK_CHECK(_L, 0); - return _L; -} + // ############################################################################################# + // ############################################################################################# +} // namespace state +// ################################################################################################# +// ################################################################################################# diff --git a/src/state.h b/src/state.h index ff70196..9b42786 100644 --- a/src/state.h +++ b/src/state.h @@ -7,12 +7,11 @@ enum class LookupMode; class Universe; -// ################################################################################################# +namespace state { -[[nodiscard]] lua_State* create_state(Universe* U_, lua_State* from_); -[[nodiscard]] lua_State* luaG_newstate(Universe* U_, SourceState from_, std::optional const& libs_); + void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_); + [[nodiscard]] lua_State* CreateState(Universe* U_, lua_State* from_); + void InitializeOnStateCreate(Universe* U_, lua_State* L_); + [[nodiscard]] lua_State* NewLaneState(Universe* U_, SourceState from_, std::optional const& libs_); -// ################################################################################################# - -void InitializeOnStateCreate(Universe* U_, lua_State* L_); -void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_); +} // namespace state diff --git a/src/universe.cpp b/src/universe.cpp index 172cc4c..77f799b 100644 --- a/src/universe.cpp +++ b/src/universe.cpp @@ -265,7 +265,7 @@ void Universe::initializeKeepers(lua_State* L_) for (int const _i : std::ranges::iota_view{ 0, _nb_keepers }) { // note that we will leak K if we raise an error later - KeeperState const _K{ create_state(this, L_) }; // L_: settings K: + KeeperState const _K{ state::CreateState(this, L_) }; // L_: settings K: if (_K == nullptr) { raise_luaL_error(L_, "out of memory while creating keeper states"); } @@ -307,7 +307,7 @@ void Universe::initializeKeepers(lua_State* L_) // attempt to call on_state_create(), if we have one and it is a C function // (only support a C function because we can't transfer executable Lua code in keepers) // will raise an error in L_ in case of problem - CallOnStateCreate(this, _K, L_, LookupMode::ToKeeper); + state::CallOnStateCreate(this, _K, L_, LookupMode::ToKeeper); // to see VM name in Decoda debugger lua_pushfstring(_K, "Keeper #%d", _i + 1); // L_: settings K: "Keeper #n" -- cgit v1.2.3-55-g6feb