aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-05-22 18:15:13 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-05-22 18:15:13 +0200
commitd468b693d79ddb416c45669e5ca8400cbdc34e85 (patch)
treee31876c81dae1e3f8359c129f348ed3511342470 /src
parent9617dd452e529af3a12b14a98cd2edbfd93ea712 (diff)
downloadlanes-d468b693d79ddb416c45669e5ca8400cbdc34e85.tar.gz
lanes-d468b693d79ddb416c45669e5ca8400cbdc34e85.tar.bz2
lanes-d468b693d79ddb416c45669e5ca8400cbdc34e85.zip
DEBUGSPEW fprintf(stderr) → std::cerr
Diffstat (limited to 'src')
-rw-r--r--src/cancel.cpp2
-rw-r--r--src/compat.h9
-rw-r--r--src/debugspew.h19
-rw-r--r--src/deep.cpp4
-rw-r--r--src/intercopycontext.cpp70
-rw-r--r--src/lane.cpp14
-rw-r--r--src/lanes.cpp44
-rw-r--r--src/state.cpp56
-rw-r--r--src/tools.cpp33
-rw-r--r--src/tools.h2
-rw-r--r--src/universe.cpp10
11 files changed, 138 insertions, 125 deletions
diff --git a/src/cancel.cpp b/src/cancel.cpp
index 2fdd1ef..23d9d04 100644
--- a/src/cancel.cpp
+++ b/src/cancel.cpp
@@ -77,7 +77,7 @@ LUAG_FUNC(cancel_test)
77 77
78[[nodiscard]] static void cancel_hook(lua_State* L_, [[maybe_unused]] lua_Debug* ar_) 78[[nodiscard]] static void cancel_hook(lua_State* L_, [[maybe_unused]] lua_Debug* ar_)
79{ 79{
80 DEBUGSPEW_CODE(fprintf(stderr, "cancel_hook\n")); 80 DEBUGSPEW_CODE(DebugSpew(nullptr) << "cancel_hook" << std::endl);
81 if (cancel_test(L_) != CancelRequest::None) { 81 if (cancel_test(L_) != CancelRequest::None) {
82 lua_sethook(L_, nullptr, 0, 0); 82 lua_sethook(L_, nullptr, 0, 0);
83 raise_cancel_error(L_); 83 raise_cancel_error(L_);
diff --git a/src/compat.h b/src/compat.h
index f097fb6..e080749 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -247,6 +247,8 @@ LuaType luaG_getmodule(lua_State* L_, char const* name_);
247 247
248// ################################################################################################# 248// #################################################################################################
249 249
250#define STRINGVIEW_FMT "%.*s"
251
250// a replacement of lua_tolstring 252// a replacement of lua_tolstring
251[[nodiscard]] inline std::string_view lua_tostringview(lua_State* L_, int idx_) 253[[nodiscard]] inline std::string_view lua_tostringview(lua_State* L_, int idx_)
252{ 254{
@@ -255,6 +257,13 @@ LuaType luaG_getmodule(lua_State* L_, char const* name_);
255 return std::string_view{ _str, _len }; 257 return std::string_view{ _str, _len };
256} 258}
257 259
260[[nodiscard]] inline std::string_view luaL_checkstringview(lua_State* L_, int idx_)
261{
262 size_t _len{ 0 };
263 char const* _str{ luaL_checklstring(L_, idx_, &_len) };
264 return std::string_view{ _str, _len };
265}
266
258[[nodiscard]] inline std::string_view lua_pushstringview(lua_State* L_, std::string_view const& str_) 267[[nodiscard]] inline std::string_view lua_pushstringview(lua_State* L_, std::string_view const& str_)
259{ 268{
260#if LUA_VERSION_NUM == 501 269#if LUA_VERSION_NUM == 501
diff --git a/src/debugspew.h b/src/debugspew.h
index 0c3e14a..216f617 100644
--- a/src/debugspew.h
+++ b/src/debugspew.h
@@ -3,6 +3,8 @@
3#include "lanesconf.h" 3#include "lanesconf.h"
4#include "universe.h" 4#include "universe.h"
5 5
6#include <iostream>
7
6// ################################################################################################# 8// #################################################################################################
7 9
8#if USE_DEBUG_SPEW() 10#if USE_DEBUG_SPEW()
@@ -10,7 +12,7 @@
10class DebugSpewIndentScope 12class DebugSpewIndentScope
11{ 13{
12 private: 14 private:
13 Universe* const U; 15 Universe* const U{};
14 16
15 public: 17 public:
16 static char const* const debugspew_indent; 18 static char const* const debugspew_indent;
@@ -18,21 +20,28 @@ class DebugSpewIndentScope
18 DebugSpewIndentScope(Universe* U_) 20 DebugSpewIndentScope(Universe* U_)
19 : U{ U_ } 21 : U{ U_ }
20 { 22 {
21 if (U) 23 if (U) {
22 U->debugspewIndentDepth.fetch_add(1, std::memory_order_relaxed); 24 U->debugspewIndentDepth.fetch_add(1, std::memory_order_relaxed);
25 }
23 } 26 }
24 27
25 ~DebugSpewIndentScope() 28 ~DebugSpewIndentScope()
26 { 29 {
27 if (U) 30 if (U) {
28 U->debugspewIndentDepth.fetch_sub(1, std::memory_order_relaxed); 31 U->debugspewIndentDepth.fetch_sub(1, std::memory_order_relaxed);
32 }
29 } 33 }
30}; 34};
31 35
32// ################################################################################################# 36// #################################################################################################
33 37
34#define INDENT_BEGIN "%.*s " 38inline auto& DebugSpew(Universe const* const U_)
35#define INDENT_END(U_) , (U_ ? U_->debugspewIndentDepth.load(std::memory_order_relaxed) : 0), DebugSpewIndentScope::debugspew_indent 39{
40 if (!U_) {
41 return std::cerr;
42 }
43 return std::cerr << std::string_view{ DebugSpewIndentScope::debugspew_indent, static_cast<size_t>(U_->debugspewIndentDepth.load(std::memory_order_relaxed)) } << " ";
44}
36#define DEBUGSPEW_CODE(_code) _code 45#define DEBUGSPEW_CODE(_code) _code
37#define DEBUGSPEW_OR_NOT(a_, b_) a_ 46#define DEBUGSPEW_OR_NOT(a_, b_) a_
38#define DEBUGSPEW_PARAM_COMMA(param_) param_, 47#define DEBUGSPEW_PARAM_COMMA(param_) param_,
diff --git a/src/deep.cpp b/src/deep.cpp
index f23f0be..a39e0f8 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -249,7 +249,7 @@ std::string_view DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_,
249 lua_getglobal(L_, "require"); // L_: DPC proxy metatable require() 249 lua_getglobal(L_, "require"); // L_: DPC proxy metatable require()
250 // check that the module is already loaded (or being loaded, we are happy either way) 250 // check that the module is already loaded (or being loaded, we are happy either way)
251 if (lua_isfunction(L_, -1)) { 251 if (lua_isfunction(L_, -1)) {
252 lua_pushlstring(L_, _modname.data(), _modname.size()); // L_: DPC proxy metatable require() "module" 252 std::ignore = lua_pushstringview(L_, _modname); // L_: DPC proxy metatable require() "module"
253 if (luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) == LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED 253 if (luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) == LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED
254 lua_pushvalue(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED "module" 254 lua_pushvalue(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED "module"
255 lua_rawget(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED module 255 lua_rawget(L_, -2); // L_: DPC proxy metatable require() "module" _R._LOADED module
@@ -260,7 +260,7 @@ std::string_view DeepFactory::PushDeepProxy(DestState L_, DeepPrelude* prelude_,
260 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error? 260 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error?
261 if (_require_result != LuaError::OK) { 261 if (_require_result != LuaError::OK) {
262 // failed, return the error message 262 // failed, return the error message
263 lua_pushfstring(L_, "error while requiring '%s' identified by DeepFactory::moduleName: ", _modname.data()); 263 lua_pushfstring(L_, "error while requiring '" STRINGVIEW_FMT "' identified by DeepFactory::moduleName: ", _modname.size(), _modname.data());
264 lua_insert(L_, -2); // L_: DPC proxy metatable prefix error 264 lua_insert(L_, -2); // L_: DPC proxy metatable prefix error
265 lua_concat(L_, 2); // L_: DPC proxy metatable error 265 lua_concat(L_, 2); // L_: DPC proxy metatable error
266 return lua_tostringview(L_, -1); 266 return lua_tostringview(L_, -1);
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index 6ebbbb0..6623b16 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -98,8 +98,7 @@ THE SOFTWARE.
98 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" 98 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n"
99 } 99 }
100 std::string_view _fqn{ lua_tostringview(L1, -1) }; 100 std::string_view _fqn{ lua_tostringview(L1, -1) };
101 DEBUGSPEW_CODE(Universe* const _U = universe_get(L1)); 101 DEBUGSPEW_CODE(DebugSpew(universe_get(L1)) << "function [C] " << _fqn << std::endl);
102 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "function [C] %s \n" INDENT_END(_U), _fqn.data()));
103 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database 102 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
104 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... 103 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ...
105 STACK_CHECK(L1, 0); 104 STACK_CHECK(L1, 0);
@@ -220,7 +219,7 @@ void InterCopyContext::copy_func() const
220 // fills 'fname' 'namewhat' and 'linedefined', pops function 219 // fills 'fname' 'namewhat' and 'linedefined', pops function
221 lua_getinfo(L1, ">nS", &_ar); // L1: ... b 220 lua_getinfo(L1, ">nS", &_ar); // L1: ... b
222 _fname = _ar.namewhat; 221 _fname = _ar.namewhat;
223 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "FNAME: %s @ %d" INDENT_END(U), _ar.short_src, _ar.linedefined)); // just gives nullptr 222 DEBUGSPEW_CODE(DebugSpew(U) << "FNAME: " << _ar.short_src << " @ " << _ar.linedefined << std::endl);
224 } 223 }
225#endif // LOG_FUNC_INFO 224#endif // LOG_FUNC_INFO
226 { 225 {
@@ -267,15 +266,15 @@ void InterCopyContext::copy_func() const
267 lua_pushglobaltable(L1); // L1: ... _G 266 lua_pushglobaltable(L1); // L1: ... _G
268#endif // LUA_VERSION_NUM 267#endif // LUA_VERSION_NUM
269 for (_n = 0; (_c.name = lua_getupvalue(L1, L1_i, 1 + _n)) != nullptr; ++_n) { // L1: ... _G up[n] 268 for (_n = 0; (_c.name = lua_getupvalue(L1, L1_i, 1 + _n)) != nullptr; ++_n) { // L1: ... _G up[n]
270 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END(U), _n, _c.name)); 269 DEBUGSPEW_CODE(DebugSpew(U) << "UPNAME[" << _n << "]: " << _c.name << " -> ");
271#if LUA_VERSION_NUM >= 502 270#if LUA_VERSION_NUM >= 502
272 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table? 271 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table?
273 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); 272 DEBUGSPEW_CODE(DebugSpew(nullptr) << "pushing destination global scope" << std::endl);
274 lua_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues> 273 lua_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues>
275 } else 274 } else
276#endif // LUA_VERSION_NUM 275#endif // LUA_VERSION_NUM
277 { 276 {
278 DEBUGSPEW_CODE(fprintf(stderr, "copying value\n")); 277 DEBUGSPEW_CODE(DebugSpew(nullptr) << "copying value" << std::endl);
279 _c.L1_i = SourceIndex{ lua_gettop(L1) }; 278 _c.L1_i = SourceIndex{ lua_gettop(L1) };
280 if (!_c.inter_copy_one()) { // L2: ... {cache} ... function <upvalues> 279 if (!_c.inter_copy_one()) { // L2: ... {cache} ... function <upvalues>
281 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 280 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
@@ -323,7 +322,7 @@ void InterCopyContext::lookup_native_func() const
323 322
324 case LookupMode::ToKeeper: 323 case LookupMode::ToKeeper:
325 // push a sentinel closure that holds the lookup name as upvalue 324 // push a sentinel closure that holds the lookup name as upvalue
326 lua_pushlstring(L2, _fqn.data(), _fqn.size()); // L1: ... f ... L2: "f.q.n" 325 std::ignore = lua_pushstringview(L2, _fqn); // L1: ... f ... L2: "f.q.n"
327 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f 326 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f
328 break; 327 break;
329 328
@@ -332,7 +331,7 @@ void InterCopyContext::lookup_native_func() const
332 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {} 331 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {}
333 STACK_CHECK(L2, 1); 332 STACK_CHECK(L2, 1);
334 LUA_ASSERT(L1, lua_istable(L2, -1)); 333 LUA_ASSERT(L1, lua_istable(L2, -1));
335 lua_pushlstring(L2, _fqn.data(), _fqn.size()); // L1: ... f ... L2: {} "f.q.n" 334 std::ignore = lua_pushstringview(L2, _fqn); // L1: ... f ... L2: {} "f.q.n"
336 lua_rawget(L2, -2); // L1: ... f ... L2: {} f 335 lua_rawget(L2, -2); // L1: ... f ... L2: {} f
337 // nil means we don't know how to transfer stuff: user should do something 336 // nil means we don't know how to transfer stuff: user should do something
338 // anything other than function or table should not happen! 337 // anything other than function or table should not happen!
@@ -342,14 +341,14 @@ void InterCopyContext::lookup_native_func() const
342 lua_pop(L1, 1); // L1: ... f ... 341 lua_pop(L1, 1); // L1: ... f ...
343 lua_getglobal(L2, "decoda_name"); // L1: ... f ... L2: {} f decoda_name 342 lua_getglobal(L2, "decoda_name"); // L1: ... f ... L2: {} f decoda_name
344 char const* const _to{ lua_tostring(L2, -1) }; 343 char const* const _to{ lua_tostring(L2, -1) };
345 lua_pop(L2, 1); // L2: {} f 344 lua_pop(L2, 1); // L2: {} f
346 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 345 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
347 raise_luaL_error( 346 raise_luaL_error(
348 getErrL(), 347 getErrL(),
349 "%s%s: function '%s' not found in %s destination transfer database.", 348 "%s%s: function '" STRINGVIEW_FMT "' not found in %s destination transfer database.",
350 lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN ", 349 lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN ",
351 _from ? _from : "main", 350 _from ? _from : "main",
352 _fqn.data(), 351 _fqn.size(), _fqn.data(),
353 _to ? _to : "main"); 352 _to ? _to : "main");
354 return; 353 return;
355 } 354 }
@@ -398,7 +397,7 @@ void InterCopyContext::copy_cached_func() const
398 // push a light userdata uniquely representing the function 397 // push a light userdata uniquely representing the function
399 lua_pushlightuserdata(L2, _aspointer); // L2: ... {cache} ... p 398 lua_pushlightuserdata(L2, _aspointer); // L2: ... {cache} ... p
400 399
401 // fprintf( stderr, "<< ID: %s >>\n", lua_tostring( L2, -1)); 400 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << lua_tostringview(L2, -1) << " >>" << std::endl);
402 401
403 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p 402 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p
404 lua_rawget(L2, L2_cache_i); // L2: ... {cache} ... p function|nil|true 403 lua_rawget(L2, L2_cache_i); // L2: ... {cache} ... p function|nil|true
@@ -443,7 +442,7 @@ void InterCopyContext::copy_cached_func() const
443 442
444 case LookupMode::ToKeeper: 443 case LookupMode::ToKeeper:
445 // push a sentinel closure that holds the lookup name as upvalue 444 // push a sentinel closure that holds the lookup name as upvalue
446 lua_pushlstring(L2, _fqn.data(), _fqn.size()); // L1: ... t ... L2: "f.q.n" 445 std::ignore = lua_pushstringview(L2, _fqn); // L1: ... t ... L2: "f.q.n"
447 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f 446 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f
448 break; 447 break;
449 448
@@ -452,7 +451,7 @@ void InterCopyContext::copy_cached_func() const
452 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {} 451 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {}
453 STACK_CHECK(L2, 1); 452 STACK_CHECK(L2, 1);
454 LUA_ASSERT(L1, lua_istable(L2, -1)); 453 LUA_ASSERT(L1, lua_istable(L2, -1));
455 lua_pushlstring(L2, _fqn.data(), _fqn.size()); // L2: {} "f.q.n" 454 std::ignore = lua_pushstringview(L2, _fqn); // L2: {} "f.q.n"
456 lua_rawget(L2, -2); // L2: {} t 455 lua_rawget(L2, -2); // L2: {} t
457 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) 456 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
458 // but not when we extract something out of a keeper, as there is nothing to clone! 457 // but not when we extract something out of a keeper, as there is nothing to clone!
@@ -505,7 +504,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
505 std::string_view const _key{ lua_tostringview(L1, _key_i) }; 504 std::string_view const _key{ lua_tostringview(L1, _key_i) };
506 size_t const _bufLen{ strlen(name) + _key.size() + 2 }; // +2 for separator dot and terminating 0 505 size_t const _bufLen{ strlen(name) + _key.size() + 2 }; // +2 for separator dot and terminating 0
507 _valPath = static_cast<char*>(alloca(_bufLen)); 506 _valPath = static_cast<char*>(alloca(_bufLen));
508 sprintf(_valPath, "%s.%*s", name, static_cast<int>(_key.size()), _key.data()); 507 sprintf(_valPath, "%s." STRINGVIEW_FMT, name, (int) _key.size(), _key.data());
509 } 508 }
510#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 509#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
511 else if (lua_isinteger(L1, _key_i)) { 510 else if (lua_isinteger(L1, _key_i)) {
@@ -607,7 +606,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
607 // push a light userdata uniquely representing the table 606 // push a light userdata uniquely representing the table
608 lua_pushlightuserdata(L2, const_cast<void*>(_p)); // L1: ... t ... L2: ... p 607 lua_pushlightuserdata(L2, const_cast<void*>(_p)); // L1: ... t ... L2: ... p
609 608
610 // fprintf(stderr, "<< ID: %s >>\n", lua_tostring(L2, -1)); 609 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << lua_tostringview(L2, -1) << " >>" << std::endl);
611 610
612 lua_rawget(L2, L2_cache_i); // L1: ... t ... L2: ... {cached|nil} 611 lua_rawget(L2, L2_cache_i); // L1: ... t ... L2: ... {cached|nil}
613 bool const _not_found_in_cache{ lua_isnil(L2, -1) }; 612 bool const _not_found_in_cache{ lua_isnil(L2, -1) };
@@ -783,7 +782,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
783[[nodiscard]] bool InterCopyContext::inter_copy_boolean() const 782[[nodiscard]] bool InterCopyContext::inter_copy_boolean() const
784{ 783{
785 int const _v{ lua_toboolean(L1, L1_i) }; 784 int const _v{ lua_toboolean(L1, L1_i) };
786 DEBUGSPEW_CODE(fprintf(stderr, "%s\n", _v ? "true" : "false")); 785 DEBUGSPEW_CODE(DebugSpew(nullptr) << (_v ? "true" : "false") << std::endl);
787 lua_pushboolean(L2, _v); 786 lua_pushboolean(L2, _v);
788 return true; 787 return true;
789} 788}
@@ -798,7 +797,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
798 797
799 STACK_CHECK_START_REL(L1, 0); 798 STACK_CHECK_START_REL(L1, 0);
800 STACK_CHECK_START_REL(L2, 0); 799 STACK_CHECK_START_REL(L2, 0);
801 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name)); 800 DEBUGSPEW_CODE(DebugSpew(nullptr) << "FUNCTION " << name << std::endl);
802 801
803 if (lua_tocfunction(L1, L1_i) == userdata_clone_sentinel) { // we are actually copying a clonable full userdata from a keeper 802 if (lua_tocfunction(L1, L1_i) == userdata_clone_sentinel) { // we are actually copying a clonable full userdata from a keeper
804 // clone the full userdata again 803 // clone the full userdata again
@@ -873,9 +872,9 @@ void InterCopyContext::inter_copy_keyvaluepair() const
873 // clone:__lanesclone(dest, source, size) 872 // clone:__lanesclone(dest, source, size)
874 lua_call(L2, 3, 0); // L2: ... u 873 lua_call(L2, 3, 0); // L2: ... u
875 } else { // regular function 874 } else { // regular function
876 DEBUGSPEW_CODE(fprintf(stderr, "FUNCTION %s\n", name)); 875 DEBUGSPEW_CODE(DebugSpew(U) << "FUNCTION " << name << std::endl);
877 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); 876 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U });
878 copy_cached_func(); // L2: ... f 877 copy_cached_func(); // L2: ... f
879 } 878 }
880 STACK_CHECK(L2, 1); 879 STACK_CHECK(L2, 1);
881 STACK_CHECK(L1, 0); 880 STACK_CHECK(L1, 0);
@@ -887,7 +886,8 @@ void InterCopyContext::inter_copy_keyvaluepair() const
887[[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const 886[[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const
888{ 887{
889 void* const _p{ lua_touserdata(L1, L1_i) }; 888 void* const _p{ lua_touserdata(L1, L1_i) };
890 DEBUGSPEW_CODE(fprintf(stderr, "%p\n", _p)); 889 // TODO: recognize and print known UniqueKey names here
890 DEBUGSPEW_CODE(DebugSpew(nullptr) << _p << std::endl);
891 // when copying a nil sentinel in a non-keeper, write a nil in the destination 891 // when copying a nil sentinel in a non-keeper, write a nil in the destination
892 if (mode != LookupMode::ToKeeper && kNilSentinel.equals(L1, L1_i)) { 892 if (mode != LookupMode::ToKeeper && kNilSentinel.equals(L1, L1_i)) {
893 lua_pushnil(L2); 893 lua_pushnil(L2);
@@ -921,13 +921,13 @@ void InterCopyContext::inter_copy_keyvaluepair() const
921#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 921#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
922 if (lua_isinteger(L1, L1_i)) { 922 if (lua_isinteger(L1, L1_i)) {
923 lua_Integer const _v{ lua_tointeger(L1, L1_i) }; 923 lua_Integer const _v{ lua_tointeger(L1, L1_i) };
924 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", _v)); 924 DEBUGSPEW_CODE(DebugSpew(nullptr) << _v << std::endl);
925 lua_pushinteger(L2, _v); 925 lua_pushinteger(L2, _v);
926 } else 926 } else
927#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 927#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
928 { 928 {
929 lua_Number const _v{ lua_tonumber(L1, L1_i) }; 929 lua_Number const _v{ lua_tonumber(L1, L1_i) };
930 DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", _v)); 930 DEBUGSPEW_CODE(DebugSpew(nullptr) << _v << std::endl);
931 lua_pushnumber(L2, _v); 931 lua_pushnumber(L2, _v);
932 } 932 }
933 return true; 933 return true;
@@ -938,8 +938,8 @@ void InterCopyContext::inter_copy_keyvaluepair() const
938[[nodiscard]] bool InterCopyContext::inter_copy_string() const 938[[nodiscard]] bool InterCopyContext::inter_copy_string() const
939{ 939{
940 std::string_view const _s{ lua_tostringview(L1, L1_i) }; 940 std::string_view const _s{ lua_tostringview(L1, L1_i) };
941 DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", _s.data())); 941 DEBUGSPEW_CODE(DebugSpew(nullptr) << "'" << _s << "'" << std::endl);
942 lua_pushlstring(L2, _s.data(), _s.size()); 942 std::ignore = lua_pushstringview(L2, _s);
943 return true; 943 return true;
944} 944}
945 945
@@ -953,7 +953,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
953 953
954 STACK_CHECK_START_REL(L1, 0); 954 STACK_CHECK_START_REL(L1, 0);
955 STACK_CHECK_START_REL(L2, 0); 955 STACK_CHECK_START_REL(L2, 0);
956 DEBUGSPEW_CODE(fprintf(stderr, "TABLE %s\n", name)); 956 DEBUGSPEW_CODE(DebugSpew(nullptr) << "TABLE " << name << std::endl);
957 957
958 /* 958 /*
959 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) 959 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?)
@@ -1021,7 +1021,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1021 STACK_CHECK(L2, 0); 1021 STACK_CHECK(L2, 0);
1022 1022
1023 // Allow only deep userdata entities to be copied across 1023 // Allow only deep userdata entities to be copied across
1024 DEBUGSPEW_CODE(fprintf(stderr, "USERDATA\n")); 1024 DEBUGSPEW_CODE(DebugSpew(nullptr) << "USERDATA" << std::endl);
1025 if (tryCopyDeep()) { 1025 if (tryCopyDeep()) {
1026 STACK_CHECK(L1, 0); 1026 STACK_CHECK(L1, 0);
1027 STACK_CHECK(L2, 1); 1027 STACK_CHECK(L2, 1);
@@ -1084,18 +1084,18 @@ static char const* vt_names[] = {
1084 STACK_CHECK_START_REL(L1, 0); 1084 STACK_CHECK_START_REL(L1, 0);
1085 STACK_CHECK_START_REL(L2, 0); 1085 STACK_CHECK_START_REL(L2, 0);
1086 1086
1087 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "inter_copy_one()\n" INDENT_END(U))); 1087 DEBUGSPEW_CODE(DebugSpew(U) << "inter_copy_one()" << std::endl);
1088 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); 1088 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U });
1089 1089
1090 LuaType _val_type{ lua_type_as_enum(L1, L1_i) }; 1090 LuaType _val_type{ lua_type_as_enum(L1, L1_i) };
1091 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s %s: " INDENT_END(U), lua_type_names[static_cast<int>(_val_type)], vt_names[static_cast<int>(vt)])); 1091 DEBUGSPEW_CODE(DebugSpew(U) << lua_type_names[static_cast<int>(_val_type)] << " " << vt_names[static_cast<int>(vt)] << ": ");
1092 1092
1093 // Non-POD can be skipped if its metatable contains { __lanesignore = true } 1093 // Non-POD can be skipped if its metatable contains { __lanesignore = true }
1094 if (((1 << static_cast<int>(_val_type)) & kPODmask) == 0) { 1094 if (((1 << static_cast<int>(_val_type)) & kPODmask) == 0) {
1095 if (lua_getmetatable(L1, L1_i)) { // L1: ... mt 1095 if (lua_getmetatable(L1, L1_i)) { // L1: ... mt
1096 LuaType const _type{ luaG_getfield(L1, -1, "__lanesignore") }; // L1: ... mt ignore? 1096 LuaType const _type{ luaG_getfield(L1, -1, "__lanesignore") }; // L1: ... mt ignore?
1097 if (_type == LuaType::BOOLEAN && lua_toboolean(L1, -1)) { 1097 if (_type == LuaType::BOOLEAN && lua_toboolean(L1, -1)) {
1098 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END(U))); 1098 DEBUGSPEW_CODE(DebugSpew(U) << "__lanesignore -> LUA_TNIL" << std::endl);
1099 _val_type = LuaType::NIL; 1099 _val_type = LuaType::NIL;
1100 } 1100 }
1101 lua_pop(L1, 2); // L1: ... 1101 lua_pop(L1, 2); // L1: ...
@@ -1155,7 +1155,7 @@ static char const* vt_names[] = {
1155// else raise an error in whichever state is not a keeper 1155// else raise an error in whichever state is not a keeper
1156[[nodiscard]] InterCopyResult InterCopyContext::inter_copy_package() const 1156[[nodiscard]] InterCopyResult InterCopyContext::inter_copy_package() const
1157{ 1157{
1158 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy_package()\n" INDENT_END(U))); 1158 DEBUGSPEW_CODE(DebugSpew(U) << "InterCopyContext::inter_copy_package()" << std::endl);
1159 1159
1160 class OnExit 1160 class OnExit
1161 { 1161 {
@@ -1189,7 +1189,7 @@ static char const* vt_names[] = {
1189 return InterCopyResult::Error; 1189 return InterCopyResult::Error;
1190 } 1190 }
1191 if (luaG_getmodule(L2, LUA_LOADLIBNAME) == LuaType::NIL) { // package library not loaded: do nothing 1191 if (luaG_getmodule(L2, LUA_LOADLIBNAME) == LuaType::NIL) { // package library not loaded: do nothing
1192 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "'package' not loaded, nothing to do\n" INDENT_END(U))); 1192 DEBUGSPEW_CODE(DebugSpew(U) << "'package' not loaded, nothing to do" << std::endl);
1193 STACK_CHECK(L1, 0); 1193 STACK_CHECK(L1, 0);
1194 return InterCopyResult::Success; 1194 return InterCopyResult::Success;
1195 } 1195 }
@@ -1204,7 +1204,7 @@ static char const* vt_names[] = {
1204 if (!_entry) { 1204 if (!_entry) {
1205 continue; 1205 continue;
1206 } 1206 }
1207 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "package.%s\n" INDENT_END(U), _entry)); 1207 DEBUGSPEW_CODE(DebugSpew(U) << "package." << _entry << std::endl);
1208 if (luaG_getfield(L1, L1_i, _entry) == LuaType::NIL) { 1208 if (luaG_getfield(L1, L1_i, _entry) == LuaType::NIL) {
1209 lua_pop(L1, 1); 1209 lua_pop(L1, 1);
1210 } else { 1210 } else {
@@ -1238,13 +1238,13 @@ static char const* vt_names[] = {
1238{ 1238{
1239 LUA_ASSERT(L1, vt == VT::NORMAL); 1239 LUA_ASSERT(L1, vt == VT::NORMAL);
1240 1240
1241 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "InterCopyContext::inter_copy()\n" INDENT_END(U))); 1241 DEBUGSPEW_CODE(DebugSpew(U) << "InterCopyContext::inter_copy()" << std::endl);
1242 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); 1242 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U });
1243 1243
1244 int const _top_L1{ lua_gettop(L1) }; 1244 int const _top_L1{ lua_gettop(L1) };
1245 if (n_ > _top_L1) { 1245 if (n_ > _top_L1) {
1246 // requesting to copy more than is available? 1246 // requesting to copy more than is available?
1247 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "nothing to copy()\n" INDENT_END(U))); 1247 DEBUGSPEW_CODE(DebugSpew(U) << "nothing to copy" << std::endl);
1248 return InterCopyResult::NotEnoughValues; 1248 return InterCopyResult::NotEnoughValues;
1249 } 1249 }
1250 1250
diff --git a/src/lane.cpp b/src/lane.cpp
index 5904266..4b6500a 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -165,7 +165,7 @@ static LUAG_FUNC(thread_join)
165 break; 165 break;
166 166
167 default: 167 default:
168 DEBUGSPEW_CODE(fprintf(stderr, "Status: %d\n", _lane->status)); 168 DEBUGSPEW_CODE(DebugSpew(nullptr) << "Unknown Lane status: " << static_cast<int>(_lane->status) << std::endl);
169 LUA_ASSERT(L_, false); 169 LUA_ASSERT(L_, false);
170 _ret = 0; 170 _ret = 0;
171 } 171 }
@@ -278,7 +278,7 @@ static int thread_index_number(lua_State* L_)
278 lua_replace(L_, -3); // L_: lane n error() "error" 278 lua_replace(L_, -3); // L_: lane n error() "error"
279 lua_pushinteger(L_, 3); // L_: lane n error() "error" 3 279 lua_pushinteger(L_, 3); // L_: lane n error() "error" 3
280 lua_call(L_, 2, 0); // error(tostring(errstring), 3) -> doesn't return // L_: lane n 280 lua_call(L_, 2, 0); // error(tostring(errstring), 3) -> doesn't return // L_: lane n
281 raise_luaL_error(L_, "%s: should not get here!", _lane->debugName.data()); 281 raise_luaL_error(L_, STRINGVIEW_FMT ": should not get here!", _lane->debugName.size(), _lane->debugName.data());
282 } else { 282 } else {
283 lua_pop(L_, 1); // L_: lane n {uv} 283 lua_pop(L_, 1); // L_: lane n {uv}
284 } 284 }
@@ -316,7 +316,7 @@ static int thread_index_string(lua_State* L_)
316 lua_rawget(L_, -2); // L_: mt value 316 lua_rawget(L_, -2); // L_: mt value
317 // only "cancel" and "join" are registered as functions, any other string will raise an error 317 // only "cancel" and "join" are registered as functions, any other string will raise an error
318 if (!lua_iscfunction(L_, -1)) { 318 if (!lua_iscfunction(L_, -1)) {
319 raise_luaL_error(L_, "can't index a lane with '%s'", _keystr.data()); 319 raise_luaL_error(L_, "can't index a lane with '" STRINGVIEW_FMT "'", _keystr.size(), _keystr.data());
320 } 320 }
321 return 1; 321 return 1;
322} 322}
@@ -345,7 +345,7 @@ static LUAG_FUNC(thread_index)
345 lua_pushvalue(L_, kKey); // L_: mt error "Unknown key: " k 345 lua_pushvalue(L_, kKey); // L_: mt error "Unknown key: " k
346 lua_concat(L_, 2); // L_: mt error "Unknown key: <k>" 346 lua_concat(L_, 2); // L_: mt error "Unknown key: <k>"
347 lua_call(L_, 1, 0); // error( "Unknown key: " .. key) -> doesn't return // L_: mt 347 lua_call(L_, 1, 0); // error( "Unknown key: " .. key) -> doesn't return // L_: mt
348 raise_luaL_error(L_, "%s[%s]: should not get here!", _lane->debugName.data(), lua_typename(L_, lua_type(L_, kKey))); 348 raise_luaL_error(L_, STRINGVIEW_FMT "[%s]: should not get here!", _lane->debugName.size(), _lane->debugName.data(), lua_typename(L_, lua_type(L_, kKey)));
349 } 349 }
350} 350}
351 351
@@ -677,11 +677,11 @@ static void lane_main(Lane* lane_)
677 // in case of error and if it exists, fetch stack trace from registry and push it 677 // in case of error and if it exists, fetch stack trace from registry and push it
678 push_stack_trace(_L, lane_->errorTraceLevel, _rc, 1); // L: retvals|error [trace] 678 push_stack_trace(_L, lane_->errorTraceLevel, _rc, 1); // L: retvals|error [trace]
679 679
680 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END(_U), _L, get_errcode_name(_rc), kCancelError.equals(_L, 1) ? "cancelled" : lua_typename(_L, lua_type(_L, 1)))); 680 DEBUGSPEW_CODE(DebugSpew(_U) << "Lane " << _L << " body: " << get_errcode_name(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : lua_typename(_L, lua_type(_L, 1))) << ")" << std::endl);
681 // Call finalizers, if the script has set them up. 681 // Call finalizers, if the script has set them up.
682 // 682 //
683 LuaError const _rc2{ run_finalizers(_L, lane_->errorTraceLevel, _rc) }; 683 LuaError const _rc2{ run_finalizers(_L, lane_->errorTraceLevel, _rc) };
684 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END(_U), _L, get_errcode_name(_rc2))); 684 DEBUGSPEW_CODE(DebugSpew(_U) << "Lane " << _L << " finalizer: " << get_errcode_name(_rc2) << std::endl);
685 if (_rc2 != LuaError::OK) { // Error within a finalizer! 685 if (_rc2 != LuaError::OK) { // Error within a finalizer!
686 // the finalizer generated an error, and left its own error message [and stack trace] on the stack 686 // the finalizer generated an error, and left its own error message [and stack trace] on the stack
687 _rc = _rc2; // we're overruling the earlier script error or normal return 687 _rc = _rc2; // we're overruling the earlier script error or normal return
@@ -839,7 +839,7 @@ void Lane::changeDebugName(int nameIdx_)
839 (errorTraceLevel == ErrorTraceLevel::Minimal) ? "minimal" : 839 (errorTraceLevel == ErrorTraceLevel::Minimal) ? "minimal" :
840 (errorTraceLevel == ErrorTraceLevel::Basic) ? "basic" : 840 (errorTraceLevel == ErrorTraceLevel::Basic) ? "basic" :
841 (errorTraceLevel == ErrorTraceLevel::Extended) ? "extended" : 841 (errorTraceLevel == ErrorTraceLevel::Extended) ? "extended" :
842 nullptr 842 ""
843 }; 843 };
844 return _str; 844 return _str;
845} 845}
diff --git a/src/lanes.cpp b/src/lanes.cpp
index c91256e..a5c9c8b 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -166,17 +166,17 @@ LUAG_FUNC(set_thread_affinity)
166// upvalue[1]: _G.require 166// upvalue[1]: _G.require
167LUAG_FUNC(require) 167LUAG_FUNC(require)
168{ 168{
169 char const* _name{ lua_tostring(L_, 1) }; // L_: "name" ... 169 std::string_view const _name{ lua_tostringview(L_, 1) }; // L_: "name" ...
170 int const _nargs{ lua_gettop(L_) }; 170 int const _nargs{ lua_gettop(L_) };
171 DEBUGSPEW_CODE(Universe * _U{ universe_get(L_) }); 171 DEBUGSPEW_CODE(Universe * _U{ universe_get(L_) });
172 STACK_CHECK_START_REL(L_, 0); 172 STACK_CHECK_START_REL(L_, 0);
173 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lanes.require %s BEGIN\n" INDENT_END(_U), _name)); 173 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.require '" << _name << "' BEGIN" << std::endl);
174 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 174 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
175 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: "name" ... require 175 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: "name" ... require
176 lua_insert(L_, 1); // L_: require "name" ... 176 lua_insert(L_, 1); // L_: require "name" ...
177 lua_call(L_, _nargs, 1); // L_: module 177 lua_call(L_, _nargs, 1); // L_: module
178 populate_func_lookup_table(L_, -1, _name); 178 populate_func_lookup_table(L_, -1, _name);
179 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lanes.require %s END\n" INDENT_END(_U), _name)); 179 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.require '" << _name << "' END" << std::endl);
180 STACK_CHECK(L_, 0); 180 STACK_CHECK(L_, 0);
181 return 1; 181 return 1;
182} 182}
@@ -188,17 +188,17 @@ LUAG_FUNC(require)
188// lanes.register( "modname", module) 188// lanes.register( "modname", module)
189LUAG_FUNC(register) 189LUAG_FUNC(register)
190{ 190{
191 char const* _name{ luaL_checkstring(L_, 1) }; 191 std::string_view const _name{ luaL_checkstringview(L_, 1) };
192 LuaType const _mod_type{ lua_type_as_enum(L_, 2) }; 192 LuaType const _mod_type{ lua_type_as_enum(L_, 2) };
193 // ignore extra parameters, just in case 193 // ignore extra parameters, just in case
194 lua_settop(L_, 2); 194 lua_settop(L_, 2);
195 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type"); 195 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type");
196 DEBUGSPEW_CODE(Universe* _U = universe_get(L_)); 196 DEBUGSPEW_CODE(Universe* _U = universe_get(L_));
197 STACK_CHECK_START_REL(L_, 0); // "name" mod_table 197 STACK_CHECK_START_REL(L_, 0); // "name" mod_table
198 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lanes.register %s BEGIN\n" INDENT_END(_U), _name)); 198 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' BEGIN" << std::endl);
199 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 199 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
200 populate_func_lookup_table(L_, -1, _name); 200 populate_func_lookup_table(L_, -1, _name);
201 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lanes.register %s END\n" INDENT_END(_U), _name)); 201 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' END" << std::endl);
202 STACK_CHECK(L_, 0); 202 STACK_CHECK(L_, 0);
203 return 0; 203 return 0;
204} 204}
@@ -236,7 +236,7 @@ LUAG_FUNC(lane_new)
236 LUA_ASSERT(L_, _nargs >= 0); 236 LUA_ASSERT(L_, _nargs >= 0);
237 237
238 Universe* const _U{ universe_get(L_) }; 238 Universe* const _U{ universe_get(L_) };
239 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END(_U))); 239 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl);
240 240
241 char const* const _libs_str{ lua_tostring(L_, kLibsIdx) }; 241 char const* const _libs_str{ lua_tostring(L_, kLibsIdx) };
242 lua_State* const _L2{ luaG_newstate(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2: 242 lua_State* const _L2{ luaG_newstate(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2:
@@ -288,7 +288,7 @@ LUAG_FUNC(lane_new)
288 private: 288 private:
289 void prepareUserData() 289 void prepareUserData()
290 { 290 {
291 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: preparing lane userdata\n" INDENT_END(lane->U))); 291 DEBUGSPEW_CODE(DebugSpew(lane->U) << "lane_new: preparing lane userdata" << std::endl);
292 STACK_CHECK_START_REL(L, 0); 292 STACK_CHECK_START_REL(L, 0);
293 // a Lane full userdata needs a single uservalue 293 // a Lane full userdata needs a single uservalue
294 Lane** const _ud{ lua_newuserdatauv<Lane*>(L, 1) }; // L: ... lane 294 Lane** const _ud{ lua_newuserdatauv<Lane*>(L, 1) }; // L: ... lane
@@ -344,7 +344,7 @@ LUAG_FUNC(lane_new)
344 } 344 }
345 } onExit{ L_, _lane}; 345 } onExit{ L_, _lane};
346 // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation 346 // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation
347 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END(_U))); 347 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: launching thread" << std::endl);
348 // public Lanes API accepts a generic range -3/+3 348 // public Lanes API accepts a generic range -3/+3
349 // that will be remapped into the platform-specific scheduler priority scheme 349 // that will be remapped into the platform-specific scheduler priority scheme
350 // On some platforms, -3 is equivalent to -2 and +3 to +2 350 // On some platforms, -3 is equivalent to -2 and +3 to +2
@@ -371,7 +371,7 @@ LUAG_FUNC(lane_new)
371 // package 371 // package
372 int const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx }; 372 int const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx };
373 if (_package_idx != 0) { 373 if (_package_idx != 0) {
374 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END(_U))); 374 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl);
375 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack 375 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack
376 InterCopyContext c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, SourceIndex{ _package_idx }, {}, {}, {} }; 376 InterCopyContext c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, SourceIndex{ _package_idx }, {}, {}, {} };
377 [[maybe_unused]] InterCopyResult const ret{ c.inter_copy_package() }; 377 [[maybe_unused]] InterCopyResult const ret{ c.inter_copy_package() };
@@ -382,7 +382,7 @@ LUAG_FUNC(lane_new)
382 int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; 382 int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx };
383 if (_required_idx != 0) { 383 if (_required_idx != 0) {
384 int _nbRequired{ 1 }; 384 int _nbRequired{ 1 };
385 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require 'required' list\n" INDENT_END(_U))); 385 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl);
386 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 386 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
387 // should not happen, was checked in lanes.lua before calling lane_new() 387 // should not happen, was checked in lanes.lua before calling lane_new()
388 if (lua_type(L_, _required_idx) != LUA_TTABLE) { 388 if (lua_type(L_, _required_idx) != LUA_TTABLE) {
@@ -396,7 +396,7 @@ LUAG_FUNC(lane_new)
396 } else { 396 } else {
397 // require the module in the target state, and populate the lookup table there too 397 // require the module in the target state, and populate the lookup table there too
398 std::string_view const _name{ lua_tostringview(L_, -1) }; 398 std::string_view const _name{ lua_tostringview(L_, -1) };
399 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END(_U), _name.data())); 399 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl);
400 400
401 // require the module in the target lane 401 // require the module in the target lane
402 lua_getglobal(_L2, "require"); // L_: [fixed] args... n "modname" L2: require()? 402 lua_getglobal(_L2, "require"); // L_: [fixed] args... n "modname" L2: require()?
@@ -404,7 +404,7 @@ LUAG_FUNC(lane_new)
404 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: 404 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2:
405 raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); 405 raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first");
406 } else { 406 } else {
407 lua_pushlstring(_L2, _name.data(), _name.size()); // L_: [fixed] args... n "modname" L2: require() name 407 std::ignore = lua_pushstringview(_L2, _name); // L_: [fixed] args... n "modname" L2: require() name
408 LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode 408 LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode
409 if (_rc != LuaError::OK) { 409 if (_rc != LuaError::OK) {
410 // propagate error to main state if any 410 // propagate error to main state if any
@@ -414,7 +414,7 @@ LUAG_FUNC(lane_new)
414 } 414 }
415 // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret 415 // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret
416 // after requiring the module, register the functions it exported in our name<->function database 416 // after requiring the module, register the functions it exported in our name<->function database
417 populate_func_lookup_table(_L2, -1, _name.data()); 417 populate_func_lookup_table(_L2, -1, _name);
418 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: 418 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2:
419 } 419 }
420 } 420 }
@@ -430,7 +430,7 @@ LUAG_FUNC(lane_new)
430 // 430 //
431 int const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx }; 431 int const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx };
432 if (_globals_idx != 0) { 432 if (_globals_idx != 0) {
433 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer globals\n" INDENT_END(_U))); 433 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl);
434 if (!lua_istable(L_, _globals_idx)) { 434 if (!lua_istable(L_, _globals_idx)) {
435 raise_luaL_error(L_, "Expected table, got %s", luaL_typename(L_, _globals_idx)); 435 raise_luaL_error(L_, "Expected table, got %s", luaL_typename(L_, _globals_idx));
436 } 436 }
@@ -455,7 +455,7 @@ LUAG_FUNC(lane_new)
455 [[maybe_unused]] int const errorHandlerCount{ _lane->pushErrorHandler() }; // L_: [fixed] args... L2: eh? 455 [[maybe_unused]] int const errorHandlerCount{ _lane->pushErrorHandler() }; // L_: [fixed] args... L2: eh?
456 LuaType const _func_type{ lua_type_as_enum(L_, kFuncIdx) }; 456 LuaType const _func_type{ lua_type_as_enum(L_, kFuncIdx) };
457 if (_func_type == LuaType::FUNCTION) { 457 if (_func_type == LuaType::FUNCTION) {
458 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END(_U))); 458 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer lane body" << std::endl);
459 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 459 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
460 lua_pushvalue(L_, kFuncIdx); // L_: [fixed] args... func L2: eh? 460 lua_pushvalue(L_, kFuncIdx); // L_: [fixed] args... func L2: eh?
461 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; 461 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} };
@@ -464,7 +464,7 @@ LUAG_FUNC(lane_new)
464 raise_luaL_error(L_, "tried to copy unsupported types"); 464 raise_luaL_error(L_, "tried to copy unsupported types");
465 } 465 }
466 } else if (_func_type == LuaType::STRING) { 466 } else if (_func_type == LuaType::STRING) {
467 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: compile lane body\n" INDENT_END(_U))); 467 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: compile lane body" << std::endl);
468 // compile the string 468 // compile the string
469 if (luaL_loadstring(_L2, lua_tostring(L_, kFuncIdx)) != 0) { // L_: [fixed] args... L2: eh? func 469 if (luaL_loadstring(_L2, lua_tostring(L_, kFuncIdx)) != 0) { // L_: [fixed] args... L2: eh? func
470 raise_luaL_error(L_, "error when parsing lane function code"); 470 raise_luaL_error(L_, "error when parsing lane function code");
@@ -478,7 +478,7 @@ LUAG_FUNC(lane_new)
478 478
479 // revive arguments 479 // revive arguments
480 if (_nargs > 0) { 480 if (_nargs > 0) {
481 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END(_U))); 481 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer lane arguments" << std::endl);
482 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 482 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
483 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; 483 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} };
484 InterCopyResult const res{ _c.inter_move(_nargs) }; // L_: [fixed] L2: eh? func args... 484 InterCopyResult const res{ _c.inter_move(_nargs) }; // L_: [fixed] L2: eh? func args...
@@ -627,13 +627,13 @@ LUAG_FUNC(configure)
627 627
628 Universe* _U{ universe_get(L_) }; 628 Universe* _U{ universe_get(L_) };
629 bool const _from_master_state{ _U == nullptr }; 629 bool const _from_master_state{ _U == nullptr };
630 char const* const _name{ luaL_checkstring(L_, lua_upvalueindex(1)) }; 630 std::string_view const _name{ luaL_checkstringview(L_, lua_upvalueindex(1)) };
631 LUA_ASSERT(L_, lua_type(L_, 1) == LUA_TTABLE); 631 LUA_ASSERT(L_, lua_type(L_, 1) == LUA_TTABLE);
632 632
633 STACK_GROW(L_, 4); 633 STACK_GROW(L_, 4);
634 STACK_CHECK_START_ABS(L_, 1); // L_: settings 634 STACK_CHECK_START_ABS(L_, 1); // L_: settings
635 635
636 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: lanes.configure() BEGIN\n" INDENT_END(_U), L_)); 636 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": lanes.configure() BEGIN" << std::endl);
637 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 637 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
638 638
639 if (_U == nullptr) { 639 if (_U == nullptr) {
@@ -757,7 +757,7 @@ LUAG_FUNC(configure)
757 // because we will do it after on_state_create() is called, 757 // because we will do it after on_state_create() is called,
758 // and we don't want to skip _G because of caching in case globals are created then 758 // and we don't want to skip _G because of caching in case globals are created then
759 lua_pushglobaltable(L_); // L_: settings M _G 759 lua_pushglobaltable(L_); // L_: settings M _G
760 populate_func_lookup_table(L_, -1, nullptr); 760 populate_func_lookup_table(L_, -1, {});
761 lua_pop(L_, 1); // L_: settings M 761 lua_pop(L_, 1); // L_: settings M
762 } 762 }
763 lua_pop(L_, 1); // L_: settings 763 lua_pop(L_, 1); // L_: settings
@@ -765,7 +765,7 @@ LUAG_FUNC(configure)
765 // set _R[kConfigRegKey] = settings 765 // set _R[kConfigRegKey] = settings
766 kConfigRegKey.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); }); 766 kConfigRegKey.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); });
767 STACK_CHECK(L_, 1); 767 STACK_CHECK(L_, 1);
768 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: lanes.configure() END\n" INDENT_END(_U), L_)); 768 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": lanes.configure() END" << std::endl);
769 // Return the settings table 769 // Return the settings table
770 return 1; 770 return 1;
771} 771}
diff --git a/src/state.cpp b/src/state.cpp
index 90a7c5b..0175449 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -55,7 +55,7 @@ THE SOFTWARE.
55{ 55{
56 int const _args{ lua_gettop(L_) }; // L_: args 56 int const _args{ lua_gettop(L_) }; // L_: args
57 Universe* const _U{ universe_get(L_) }; 57 Universe* const _U{ universe_get(L_) };
58 // char const* modname = luaL_checkstring(L_, 1); 58 //[[maybe_unused]] std::string_view const _modname{ luaL_checkstringview(L_, 1) };
59 59
60 STACK_GROW(L_, 1); 60 STACK_GROW(L_, 1);
61 61
@@ -88,7 +88,7 @@ void serialize_require(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_)
88{ 88{
89 STACK_GROW(L_, 1); 89 STACK_GROW(L_, 1);
90 STACK_CHECK_START_REL(L_, 0); 90 STACK_CHECK_START_REL(L_, 0);
91 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "serializing require()\n" INDENT_END(U_))); 91 DEBUGSPEW_CODE(DebugSpew(U_) << "serializing require()" << std::endl);
92 92
93 // Check 'require' is there and not already wrapped; if not, do nothing 93 // Check 'require' is there and not already wrapped; if not, do nothing
94 // 94 //
@@ -155,23 +155,23 @@ namespace global
155 155
156// ################################################################################################# 156// #################################################################################################
157 157
158static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, char const* name_, size_t len_) 158static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, std::string_view const& name_)
159{ 159{
160 for (luaL_Reg const& _entry : global::sLibs) { 160 for (luaL_Reg const& _entry : global::sLibs) {
161 if (strncmp(name_, _entry.name, len_) == 0) { 161 if (name_ == _entry.name) {
162 lua_CFunction const _libfunc{ _entry.func }; 162 lua_CFunction const _libfunc{ _entry.func };
163 if (!_libfunc) { 163 if (!_libfunc) {
164 continue; 164 break;
165 } 165 }
166 name_ = _entry.name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ 166 std::string_view const _name{ _entry.name };
167 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END(U_), (int) len_, name_)); 167 DEBUGSPEW_CODE(DebugSpew(U_) << "opening '" << _name << "' library" << std::endl);
168 STACK_CHECK_START_REL(L_, 0); 168 STACK_CHECK_START_REL(L_, 0);
169 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) 169 // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack)
170 bool const isLanesCore{ _libfunc == require_lanes_core }; // don't want to create a global for "lanes.core" 170 bool const isLanesCore{ _libfunc == require_lanes_core }; // don't want to create a global for "lanes.core"
171 luaL_requiref(L_, name_, _libfunc, !isLanesCore); // L_: {lib} 171 luaL_requiref(L_, _name.data(), _libfunc, !isLanesCore); // L_: {lib}
172 // lanes.core doesn't declare a global, so scan it here and now 172 // lanes.core doesn't declare a global, so scan it here and now
173 if (isLanesCore) { 173 if (isLanesCore) {
174 populate_func_lookup_table(L_, -1, name_); 174 populate_func_lookup_table(L_, -1, _name);
175 } 175 }
176 lua_pop(L_, 1); // L_: 176 lua_pop(L_, 1); // L_:
177 STACK_CHECK(L_, 0); 177 STACK_CHECK(L_, 0);
@@ -182,14 +182,6 @@ static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, char con
182 182
183// ################################################################################################# 183// #################################################################################################
184 184
185template<size_t N>
186static inline void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, char const (&name_)[N])
187{
188 open1lib(DEBUGSPEW_PARAM_COMMA(U_) L_, name_, N - 1);
189}
190
191// #################################################################################################
192
193// just like lua_xmove, args are (from, to) 185// just like lua_xmove, args are (from, to)
194static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_) 186static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_)
195{ 187{
@@ -199,7 +191,7 @@ static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_)
199 STACK_CHECK_START_REL(L1_, 0); 191 STACK_CHECK_START_REL(L1_, 0);
200 STACK_CHECK_START_REL(L2_, 0); 192 STACK_CHECK_START_REL(L2_, 0);
201 193
202 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END(U_))); 194 DEBUGSPEW_CODE(DebugSpew(U_) << "copy_one_time_settings()" << std::endl);
203 195
204 kConfigRegKey.pushValue(L1_); // L1_: config 196 kConfigRegKey.pushValue(L1_); // L1_: config
205 // copy settings from from source to destination registry 197 // copy settings from from source to destination registry
@@ -275,7 +267,7 @@ void CallOnStateCreate(Universe* U_, lua_State* L_, lua_State* from_, LookupMode
275{ 267{
276 if (U_->onStateCreateFunc != nullptr) { 268 if (U_->onStateCreateFunc != nullptr) {
277 STACK_CHECK_START_REL(L_, 0); 269 STACK_CHECK_START_REL(L_, 0);
278 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END(U_))); 270 DEBUGSPEW_CODE(DebugSpew(U_) << "calling on_state_create()" << std::endl);
279 if (U_->onStateCreateFunc != reinterpret_cast<lua_CFunction>(InitializeOnStateCreate)) { 271 if (U_->onStateCreateFunc != reinterpret_cast<lua_CFunction>(InitializeOnStateCreate)) {
280 // C function: recreate a closure in the new state, bypassing the lookup scheme 272 // C function: recreate a closure in the new state, bypassing the lookup scheme
281 lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create() 273 lua_pushcfunction(L_, U_->onStateCreateFunc); // on_state_create()
@@ -333,11 +325,11 @@ lua_State* luaG_newstate(Universe* U_, SourceState from_, char const* libs_)
333 325
334 // neither libs (not even 'base') nor special init func: we are done 326 // neither libs (not even 'base') nor special init func: we are done
335 if (libs_ == nullptr && U_->onStateCreateFunc == nullptr) { 327 if (libs_ == nullptr && U_->onStateCreateFunc == nullptr) {
336 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "luaG_newstate(nullptr)\n" INDENT_END(U_))); 328 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl);
337 return _L; 329 return _L;
338 } 330 }
339 331
340 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END(U_))); 332 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate()" << std::endl);
341 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); 333 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ });
342 334
343 // copy settings (for example because it may contain a Lua on_state_create function) 335 // copy settings (for example because it may contain a Lua on_state_create function)
@@ -351,13 +343,13 @@ lua_State* luaG_newstate(Universe* U_, SourceState from_, char const* libs_)
351 // special "*" case (mainly to help with LuaJIT compatibility) 343 // special "*" case (mainly to help with LuaJIT compatibility)
352 // as we are called from luaopen_lanes_core() already, and that would deadlock 344 // as we are called from luaopen_lanes_core() already, and that would deadlock
353 if (libs_[0] == '*' && libs_[1] == 0) { 345 if (libs_[0] == '*' && libs_[1] == 0) {
354 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END(U_))); 346 DEBUGSPEW_CODE(DebugSpew(U_) << "opening ALL standard libraries" << std::endl);
355 luaL_openlibs(_L); 347 luaL_openlibs(_L);
356 // don't forget lanes.core for regular lane states 348 // don't forget lanes.core for regular lane states
357 open1lib(DEBUGSPEW_PARAM_COMMA(U_) _L, kLanesCoreLibName); 349 open1lib(DEBUGSPEW_PARAM_COMMA(U_) _L, kLanesCoreLibName);
358 libs_ = nullptr; // done with libs 350 libs_ = nullptr; // done with libs
359 } else { 351 } else {
360 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening base library\n" INDENT_END(U_))); 352 DEBUGSPEW_CODE(DebugSpew(U_) << "opening 'base' library" << std::endl);
361#if LUA_VERSION_NUM >= 502 353#if LUA_VERSION_NUM >= 502
362 // open base library the same way as in luaL_openlibs() 354 // open base library the same way as in luaL_openlibs()
363 luaL_requiref(_L, LUA_GNAME, luaopen_base, 1); 355 luaL_requiref(_L, LUA_GNAME, luaopen_base, 1);
@@ -373,17 +365,17 @@ lua_State* luaG_newstate(Universe* U_, SourceState from_, char const* libs_)
373 365
374 // scan all libraries, open them one by one 366 // scan all libraries, open them one by one
375 if (libs_) { 367 if (libs_) {
376 unsigned int len{ 0 }; 368 unsigned int _len{ 0 };
377 for (char const* p{ libs_ }; *p; p += len) { 369 for (char const* _p{ libs_ }; *_p; _p += _len) {
378 // skip delimiters ('.' can be part of name for "lanes.core") 370 // skip delimiters ('.' can be part of name for "lanes.core")
379 while (*p && !isalnum(*p) && *p != '.') 371 while (*_p && !isalnum(*_p) && *_p != '.')
380 ++p; 372 ++_p;
381 // skip name 373 // skip name
382 len = 0; 374 _len = 0;
383 while (isalnum(p[len]) || p[len] == '.') 375 while (isalnum(_p[_len]) || _p[_len] == '.')
384 ++len; 376 ++_len;
385 // open library 377 // open library
386 open1lib(DEBUGSPEW_PARAM_COMMA(U_) _L, p, len); 378 open1lib(DEBUGSPEW_PARAM_COMMA(U_) _L, { _p, _len });
387 } 379 }
388 } 380 }
389 lua_gc(_L, LUA_GCRESTART, 0); 381 lua_gc(_L, LUA_GCRESTART, 0);
@@ -398,7 +390,7 @@ lua_State* luaG_newstate(Universe* U_, SourceState from_, char const* libs_)
398 // after all this, register everything we find in our name<->function database 390 // after all this, register everything we find in our name<->function database
399 lua_pushglobaltable(_L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack 391 lua_pushglobaltable(_L); // Lua 5.2 no longer has LUA_GLOBALSINDEX: we must push globals table on the stack
400 STACK_CHECK(_L, 1); 392 STACK_CHECK(_L, 1);
401 populate_func_lookup_table(_L, -1, nullptr); 393 populate_func_lookup_table(_L, -1, {});
402 394
403#if 1 && USE_DEBUG_SPEW() 395#if 1 && USE_DEBUG_SPEW()
404 // dump the lookup database contents 396 // dump the lookup database contents
diff --git a/src/tools.cpp b/src/tools.cpp
index ba0785b..5f12995 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -129,7 +129,7 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L
129 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i 129 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i
130 int const _fqn{ ctxBase_ + 1 }; 130 int const _fqn{ ctxBase_ + 1 };
131 131
132 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "update_lookup_entry()\n" INDENT_END(U_))); 132 DEBUGSPEW_CODE(DebugSpew(U_) << "update_lookup_entry()" << std::endl);
133 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); 133 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ });
134 134
135 STACK_CHECK_START_REL(L_, 0); 135 STACK_CHECK_START_REL(L_, 0);
@@ -154,7 +154,7 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L
154 // Therefore, when we encounter an object for which a name was previously registered, we need to select the names 154 // Therefore, when we encounter an object for which a name was previously registered, we need to select the names
155 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded 155 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded
156 if (!_prevName.empty() && (_prevName.size() < _newName.size() || lua_lessthan(L_, -2, -1))) { 156 if (!_prevName.empty() && (_prevName.size() < _newName.size() || lua_lessthan(L_, -2, -1))) {
157 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -3)), _newName.data(), _prevName.data())); 157 DEBUGSPEW_CODE(DebugSpew(U_) << lua_typename(L_, lua_type(L_, -3)) << " '" << _newName << "' remains named '" << _prevName << "'" << std::endl);
158 // the previous name is 'smaller' than the one we just generated: keep it! 158 // the previous name is 'smaller' than the one we just generated: keep it!
159 lua_pop(L_, 3); // L_: ... {bfc} k 159 lua_pop(L_, 3); // L_: ... {bfc} k
160 } else { 160 } else {
@@ -168,7 +168,7 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L
168 } else { 168 } else {
169 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n" 169 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n"
170 } 170 }
171 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END(U_), lua_typename(L_, lua_type(L_, -2)), _newName.data())); 171 DEBUGSPEW_CODE(DebugSpew(U_) << lua_typename(L_, lua_type(L_, -2)) << " '" << _newName << "'" << std::endl);
172 // prepare the stack for database feed 172 // prepare the stack for database feed
173 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n" 173 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n"
174 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o 174 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o
@@ -195,7 +195,7 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_)
195 int const _fqn{ dbIdx_ + 1 }; 195 int const _fqn{ dbIdx_ + 1 };
196 // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops 196 // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops
197 int const _cache{ dbIdx_ + 2 }; 197 int const _cache{ dbIdx_ + 2 };
198 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END(U_))); 198 DEBUGSPEW_CODE(DebugSpew(U_) << "populate_func_lookup_table_recur()" << std::endl);
199 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); 199 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ });
200 200
201 STACK_GROW(L_, 6); 201 STACK_GROW(L_, 6);
@@ -215,7 +215,7 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_)
215 lua_pop(L_, 1); // L_: ... {i_} 215 lua_pop(L_, 1); // L_: ... {i_}
216 STACK_CHECK(L_, 0); 216 STACK_CHECK(L_, 0);
217 if (_visit_count > 0) { 217 if (_visit_count > 0) {
218 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "already visited\n" INDENT_END(U_))); 218 DEBUGSPEW_CODE(DebugSpew(U_) << "already visited" << std::endl);
219 return; 219 return;
220 } 220 }
221 221
@@ -262,8 +262,8 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_)
262 ++depth_; 262 ++depth_;
263 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 263 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
264 while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} 264 while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {}
265 DEBUGSPEW_CODE(char const* _key = (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostring(L_, -2) : "not a string"); 265 DEBUGSPEW_CODE(std::string_view const _key{ (lua_type(L_, -2) == LUA_TSTRING) ? lua_tostringview(L_, -2) : std::string_view{ "<not a string>" } });
266 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "table '%s'\n" INDENT_END(U_), _key)); 266 DEBUGSPEW_CODE(DebugSpew(U_) << "table '"<< _key <<"'" << std::endl);
267 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ U_ }); 267 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ U_ });
268 // un-visit this table in case we do need to process it 268 // un-visit this table in case we do need to process it
269 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 269 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
@@ -298,11 +298,12 @@ static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U_)
298// ################################################################################################# 298// #################################################################################################
299 299
300// create a "fully.qualified.name" <-> function equivalence database 300// create a "fully.qualified.name" <-> function equivalence database
301void populate_func_lookup_table(lua_State* L_, int i_, char const* name_) 301void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_)
302{ 302{
303 int const _in_base = lua_absindex(L_, i_); 303 int const _in_base = lua_absindex(L_, i_);
304 DEBUGSPEW_CODE(Universe* _U = universe_get(L_)); 304 DEBUGSPEW_CODE(Universe* _U = universe_get(L_));
305 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END(_U), L_, name_ ? name_ : "nullptr")); 305 std::string_view _name{ name_.empty() ? std::string_view{} : name_ };
306 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": populate_func_lookup_table('" << _name << "')" << std::endl);
306 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 307 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
307 STACK_GROW(L_, 3); 308 STACK_GROW(L_, 3);
308 STACK_CHECK_START_REL(L_, 0); 309 STACK_CHECK_START_REL(L_, 0);
@@ -311,20 +312,22 @@ void populate_func_lookup_table(lua_State* L_, int i_, char const* name_)
311 STACK_CHECK(L_, 1); 312 STACK_CHECK(L_, 1);
312 LUA_ASSERT(L_, lua_istable(L_, -1)); 313 LUA_ASSERT(L_, lua_istable(L_, -1));
313 if (lua_type(L_, _in_base) == LUA_TFUNCTION) { // for example when a module is a simple function 314 if (lua_type(L_, _in_base) == LUA_TFUNCTION) { // for example when a module is a simple function
314 name_ = name_ ? name_ : "nullptr"; 315 if (_name.empty()) {
316 _name = "nullptr";
317 }
315 lua_pushvalue(L_, _in_base); // L_: {} f 318 lua_pushvalue(L_, _in_base); // L_: {} f
316 lua_pushstring(L_, name_); // L_: {} f _name 319 std::ignore = lua_pushstringview(L_, _name); // L_: {} f name_
317 lua_rawset(L_, -3); // L_: {} 320 lua_rawset(L_, -3); // L_: {}
318 lua_pushstring(L_, name_); // L_: {} _name 321 std::ignore = lua_pushstringview(L_, _name); // L_: {} name_
319 lua_pushvalue(L_, _in_base); // L_: {} _name f 322 lua_pushvalue(L_, _in_base); // L_: {} name_ f
320 lua_rawset(L_, -3); // L_: {} 323 lua_rawset(L_, -3); // L_: {}
321 lua_pop(L_, 1); // L_: 324 lua_pop(L_, 1); // L_:
322 } else if (lua_type(L_, _in_base) == LUA_TTABLE) { 325 } else if (lua_type(L_, _in_base) == LUA_TTABLE) {
323 lua_newtable(L_); // L_: {} {fqn} 326 lua_newtable(L_); // L_: {} {fqn}
324 int _startDepth{ 0 }; 327 int _startDepth{ 0 };
325 if (name_) { 328 if (!_name.empty()) {
326 STACK_CHECK(L_, 2); 329 STACK_CHECK(L_, 2);
327 lua_pushstring(L_, name_); // L_: {} {fqn} "name" 330 std::ignore = lua_pushstringview(L_, _name); // L_: {} {fqn} "name"
328 // generate a name, and if we already had one name, keep whichever is the shorter 331 // generate a name, and if we already had one name, keep whichever is the shorter
329 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t 332 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t
330 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(_U) L_, _dbIdx, _startDepth); // L_: {} {fqn} "name" 333 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(_U) L_, _dbIdx, _startDepth); // L_: {} {fqn} "name"
diff --git a/src/tools.h b/src/tools.h
index be76fd9..4857eeb 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -24,7 +24,7 @@ enum class FuncSubType
24 24
25[[nodiscard]] int luaG_nameof(lua_State* L_); 25[[nodiscard]] int luaG_nameof(lua_State* L_);
26 26
27void populate_func_lookup_table(lua_State* L_, int i_, char const* name_); 27void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_);
28 28
29// ################################################################################################# 29// #################################################################################################
30 30
diff --git a/src/universe.cpp b/src/universe.cpp
index 548475e..0bab844 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -322,20 +322,20 @@ void Universe::terminateFreeRunningLanes(lua_State* L_, lua_Duration shutdownTim
322 // give threads time to act on their cancel 322 // give threads time to act on their cancel
323 std::this_thread::yield(); 323 std::this_thread::yield();
324 // count the number of cancelled thread that didn't have the time to act yet 324 // count the number of cancelled thread that didn't have the time to act yet
325 int n{ 0 }; 325 int _n{ 0 };
326 { 326 {
327 std::lock_guard<std::mutex> _guard{ selfdestructMutex }; 327 std::lock_guard<std::mutex> _guard{ selfdestructMutex };
328 Lane* _lane{ selfdestructFirst }; 328 Lane* _lane{ selfdestructFirst };
329 while (_lane != SELFDESTRUCT_END) { 329 while (_lane != SELFDESTRUCT_END) {
330 if (_lane->cancelRequest != CancelRequest::None) 330 if (_lane->cancelRequest != CancelRequest::None)
331 ++n; 331 ++_n;
332 _lane = _lane->selfdestruct_next; 332 _lane = _lane->selfdestruct_next;
333 } 333 }
334 } 334 }
335 // if timeout elapsed, or we know all threads have acted, stop waiting 335 // if timeout elapsed, or we know all threads have acted, stop waiting
336 std::chrono::time_point<std::chrono::steady_clock> _now = std::chrono::steady_clock::now(); 336 std::chrono::time_point<std::chrono::steady_clock> _now = std::chrono::steady_clock::now();
337 if (n == 0 || (_now >= _until)) { 337 if (_n == 0 || (_now >= _until)) {
338 DEBUGSPEW_CODE(fprintf(stderr, "%d uncancelled lane(s) remain after waiting %fs at process end.\n", n, shutdownTimeout_.count())); 338 DEBUGSPEW_CODE(DebugSpew(this) << _n << " uncancelled lane(s) remain after waiting " << shutdownTimeout_.count() << "s at process end." << std::endl);
339 break; 339 break;
340 } 340 }
341 } 341 }
@@ -354,7 +354,7 @@ void Universe::terminateFreeRunningLanes(lua_State* L_, lua_Duration shutdownTim
354 Lane* _lane{ selfdestructFirst }; 354 Lane* _lane{ selfdestructFirst };
355 if (_lane != SELFDESTRUCT_END) { 355 if (_lane != SELFDESTRUCT_END) {
356 // this causes a leak because we don't call U's destructor (which could be bad if the still running lanes are accessing it) 356 // this causes a leak because we don't call U's destructor (which could be bad if the still running lanes are accessing it)
357 raise_luaL_error(L_, "Zombie thread %s refuses to die!", _lane->debugName.data()); 357 raise_luaL_error(L_, "Zombie thread " STRINGVIEW_FMT " refuses to die!", _lane->debugName.size(), _lane->debugName.data());
358 } 358 }
359 } 359 }
360} 360}