aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-10-08 18:42:39 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-10-08 18:42:39 +0200
commit16b5070c0cd56e10c5074eb9903dbc3ae4e15a61 (patch)
treef6d5cdb74b505e13aa3261f7ab6192da0133b7b9
parente939e5e6a894a042d3301e47faa05264445f27f6 (diff)
downloadlanes-16b5070c0cd56e10c5074eb9903dbc3ae4e15a61.tar.gz
lanes-16b5070c0cd56e10c5074eb9903dbc3ae4e15a61.tar.bz2
lanes-16b5070c0cd56e10c5074eb9903dbc3ae4e15a61.zip
Sprinkling StackIndex all over the place
-rw-r--r--deep_test/deep_test.cpp20
-rw-r--r--src/cancel.cpp10
-rw-r--r--src/compat.cpp20
-rw-r--r--src/compat.h48
-rw-r--r--src/debug.h4
-rw-r--r--src/deep.cpp24
-rw-r--r--src/deep.h6
-rw-r--r--src/intercopycontext.cpp82
-rw-r--r--src/intercopycontext.h4
-rw-r--r--src/keeper.cpp88
-rw-r--r--src/keeper.h10
-rw-r--r--src/lane.cpp140
-rw-r--r--src/lane.h6
-rw-r--r--src/lanes.cpp68
-rw-r--r--src/linda.cpp52
-rw-r--r--src/linda.h2
-rw-r--r--src/lindafactory.cpp6
-rw-r--r--src/luaerrors.h6
-rw-r--r--src/macros_and_utils.h5
-rw-r--r--src/nameof.cpp18
-rw-r--r--src/state.cpp6
-rw-r--r--src/tools.cpp50
-rw-r--r--src/tools.h6
-rw-r--r--src/unique.hpp22
-rw-r--r--src/uniquekey.h24
-rw-r--r--src/universe.cpp47
26 files changed, 394 insertions, 380 deletions
diff --git a/deep_test/deep_test.cpp b/deep_test/deep_test.cpp
index c071dc6..39352f3 100644
--- a/deep_test/deep_test.cpp
+++ b/deep_test/deep_test.cpp
@@ -47,7 +47,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
47 47
48[[nodiscard]] static int deep_gc(lua_State* L) 48[[nodiscard]] static int deep_gc(lua_State* L)
49{ 49{
50 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; 50 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, StackIndex{ 1 })) };
51 luaL_argcheck(L, 1, !_self->inUse.load(), "being collected while in use!"); 51 luaL_argcheck(L, 1, !_self->inUse.load(), "being collected while in use!");
52 return 0; 52 return 0;
53} 53}
@@ -56,7 +56,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
56 56
57[[nodiscard]] static int deep_tostring(lua_State* L) 57[[nodiscard]] static int deep_tostring(lua_State* L)
58{ 58{
59 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; 59 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, StackIndex{ 1 })) };
60 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 60 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
61 luaG_pushstring(L, "%p:deep(%d)", _self, _self->val); 61 luaG_pushstring(L, "%p:deep(%d)", _self, _self->val);
62 _self->inUse.fetch_sub(1, std::memory_order_seq_cst); 62 _self->inUse.fetch_sub(1, std::memory_order_seq_cst);
@@ -68,10 +68,10 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
68// won't actually do anything as deep userdata don't have uservalue slots 68// won't actually do anything as deep userdata don't have uservalue slots
69[[nodiscard]] static int deep_getuv(lua_State* L) 69[[nodiscard]] static int deep_getuv(lua_State* L)
70{ 70{
71 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; 71 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, StackIndex{ 1 })) };
72 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 72 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
73 int _uv = (int) luaL_optinteger(L, 2, 1); 73 int _uv = (int) luaL_optinteger(L, 2, 1);
74 lua_getiuservalue(L, 1, _uv); 74 lua_getiuservalue(L, StackIndex{ 1 }, _uv);
75 _self->inUse.fetch_sub(1, std::memory_order_seq_cst); 75 _self->inUse.fetch_sub(1, std::memory_order_seq_cst);
76 return 1; 76 return 1;
77} 77}
@@ -80,7 +80,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
80 80
81[[nodiscard]] static int deep_invoke(lua_State* L) 81[[nodiscard]] static int deep_invoke(lua_State* L)
82{ 82{
83 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; 83 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, StackIndex{ 1 })) };
84 luaL_argcheck(L, 2, lua_gettop(L) >= 2, "need something to call"); 84 luaL_argcheck(L, 2, lua_gettop(L) >= 2, "need something to call");
85 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 85 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
86 lua_call(L, lua_gettop(L) - 2, LUA_MULTRET); 86 lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
@@ -92,7 +92,7 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
92 92
93[[nodiscard]] static int deep_set(lua_State* const L_) 93[[nodiscard]] static int deep_set(lua_State* const L_)
94{ 94{
95 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, 1)) }; 95 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, StackIndex{ 1 })) };
96 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 96 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
97 lua_Integer _i = lua_tointeger(L_, 2); 97 lua_Integer _i = lua_tointeger(L_, 2);
98 _self->val = _i; 98 _self->val = _i;
@@ -104,11 +104,11 @@ void MyDeepFactory::deleteDeepObjectInternal(lua_State* const L_, DeepPrelude* c
104 104
105[[nodiscard]] static int deep_setuv(lua_State* L) 105[[nodiscard]] static int deep_setuv(lua_State* L)
106{ 106{
107 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, 1)) }; 107 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L, StackIndex{ 1 })) };
108 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 108 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
109 int _uv = (int) luaL_optinteger(L, 2, 1); 109 int _uv = (int) luaL_optinteger(L, 2, 1);
110 lua_settop(L, 3); 110 lua_settop(L, 3);
111 lua_pushboolean(L, lua_setiuservalue(L, 1, _uv) != 0); 111 lua_pushboolean(L, lua_setiuservalue(L, StackIndex{ 1 }, _uv) != 0);
112 _self->inUse.fetch_sub(1, std::memory_order_seq_cst); 112 _self->inUse.fetch_sub(1, std::memory_order_seq_cst);
113 return 1; 113 return 1;
114} 114}
@@ -160,7 +160,7 @@ struct MyClonableUserdata
160 MyClonableUserdata* self = static_cast<MyClonableUserdata*>(lua_touserdata(L, 1)); 160 MyClonableUserdata* self = static_cast<MyClonableUserdata*>(lua_touserdata(L, 1));
161 int uv = (int) luaL_optinteger(L, 2, 1); 161 int uv = (int) luaL_optinteger(L, 2, 1);
162 lua_settop(L, 3); 162 lua_settop(L, 3);
163 lua_pushboolean(L, lua_setiuservalue(L, 1, uv) != 0); 163 lua_pushboolean(L, lua_setiuservalue(L, StackIndex{ 1 }, uv) != 0);
164 return 1; 164 return 1;
165} 165}
166 166
@@ -170,7 +170,7 @@ struct MyClonableUserdata
170{ 170{
171 MyClonableUserdata* self = static_cast<MyClonableUserdata*>(lua_touserdata(L, 1)); 171 MyClonableUserdata* self = static_cast<MyClonableUserdata*>(lua_touserdata(L, 1));
172 int uv = (int) luaL_optinteger(L, 2, 1); 172 int uv = (int) luaL_optinteger(L, 2, 1);
173 lua_getiuservalue(L, 1, uv); 173 lua_getiuservalue(L, StackIndex{ 1 }, uv);
174 return 1; 174 return 1;
175} 175}
176 176
diff --git a/src/cancel.cpp b/src/cancel.cpp
index 15a2c83..2cd3c53 100644
--- a/src/cancel.cpp
+++ b/src/cancel.cpp
@@ -103,7 +103,7 @@ CancelOp WhichCancelOp(std::string_view const& opString_)
103 103
104// ################################################################################################# 104// #################################################################################################
105 105
106[[nodiscard]] static CancelOp WhichCancelOp(lua_State* const L_, int const idx_) 106[[nodiscard]] static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_)
107{ 107{
108 if (luaG_type(L_, idx_) == LuaType::STRING) { 108 if (luaG_type(L_, idx_) == LuaType::STRING) {
109 std::string_view const _str{ luaG_tostring(L_, idx_) }; 109 std::string_view const _str{ luaG_tostring(L_, idx_) };
@@ -141,8 +141,8 @@ LUAG_FUNC(cancel_test)
141// bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane]) 141// bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane])
142LUAG_FUNC(thread_cancel) 142LUAG_FUNC(thread_cancel)
143{ 143{
144 Lane* const _lane{ ToLane(L_, 1) }; 144 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) };
145 CancelOp const _op{ WhichCancelOp(L_, 2) }; // this removes the op string from the stack 145 CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // this removes the op string from the stack
146 146
147 int _hook_count{ 0 }; 147 int _hook_count{ 0 };
148 if (static_cast<int>(_op) > static_cast<int>(CancelOp::Soft)) { // hook is requested 148 if (static_cast<int>(_op) > static_cast<int>(CancelOp::Soft)) { // hook is requested
@@ -154,12 +154,12 @@ LUAG_FUNC(thread_cancel)
154 } 154 }
155 155
156 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 156 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
157 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 157 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
158 lua_Duration const duration{ lua_tonumber(L_, 2) }; 158 lua_Duration const duration{ lua_tonumber(L_, 2) };
159 if (duration.count() >= 0.0) { 159 if (duration.count() >= 0.0) {
160 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 160 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
161 } else { 161 } else {
162 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 162 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
163 } 163 }
164 lua_remove(L_, 2); // argument is processed, remove it 164 lua_remove(L_, 2); // argument is processed, remove it
165 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key 165 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
diff --git a/src/compat.cpp b/src/compat.cpp
index 4076aa6..1f8eaf9 100644
--- a/src/compat.cpp
+++ b/src/compat.cpp
@@ -5,10 +5,10 @@
5 5
6// ################################################################################################# 6// #################################################################################################
7 7
8int luaG_getalluservalues(lua_State* const L_, int const idx_) 8int luaG_getalluservalues(lua_State* const L_, StackIndex const idx_)
9{ 9{
10 STACK_CHECK_START_REL(L_, 0); 10 STACK_CHECK_START_REL(L_, 0);
11 int const _idx{ luaG_absindex(L_, idx_) }; 11 StackIndex const _idx{ luaG_absindex(L_, idx_) };
12 int _nuv{ 0 }; 12 int _nuv{ 0 };
13 do { 13 do {
14 // we don't know how many uservalues we are going to extract, there might be a lot... 14 // we don't know how many uservalues we are going to extract, there might be a lot...
@@ -27,12 +27,12 @@ int luaG_getalluservalues(lua_State* const L_, int const idx_)
27LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_) 27LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_)
28{ 28{
29 STACK_CHECK_START_REL(L_, 0); 29 STACK_CHECK_START_REL(L_, 0);
30 LuaType _type{ luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil 30 LuaType _type{ luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil
31 if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil 31 if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil
32 STACK_CHECK(L_, 1); 32 STACK_CHECK(L_, 1);
33 return _type; 33 return _type;
34 } 34 }
35 _type = luaG_getfield(L_, -1, name_); // L_: _R._LOADED {module}|nil 35 _type = luaG_getfield(L_, kIdxTop, name_); // L_: _R._LOADED {module}|nil
36 lua_remove(L_, -2); // L_: {module}|nil 36 lua_remove(L_, -2); // L_: {module}|nil
37 STACK_CHECK(L_, 1); 37 STACK_CHECK(L_, 1);
38 return _type; 38 return _type;
@@ -45,17 +45,17 @@ LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_)
45// ################################################################################################# 45// #################################################################################################
46 46
47// Copied from Lua 5.2 loadlib.c 47// Copied from Lua 5.2 loadlib.c
48int luaL_getsubtable(lua_State* L_, int idx_, const char* fname_) 48int luaL_getsubtable(lua_State* const L_, StackIndex const idx_, char const* fname_)
49{ 49{
50 lua_getfield(L_, idx_, fname_); 50 lua_getfield(L_, idx_, fname_);
51 if (lua_istable(L_, -1)) 51 if (lua_istable(L_, -1))
52 return 1; /* table already there */ 52 return 1; /* table already there */
53 else { 53 else {
54 lua_pop(L_, 1); /* remove previous result */ 54 lua_pop(L_, 1); /* remove previous result */
55 idx_ = luaG_absindex(L_, idx_); 55 StackIndex const _absidx{ luaG_absindex(L_, idx_) };
56 lua_newtable(L_); 56 lua_newtable(L_);
57 lua_pushvalue(L_, -1); /* copy to be left at top */ 57 lua_pushvalue(L_, -1); /* copy to be left at top */
58 lua_setfield(L_, idx_, fname_); /* assign new table to field */ 58 lua_setfield(L_, _absidx, fname_); /* assign new table to field */
59 return 0; /* false, because did not find table there */ 59 return 0; /* false, because did not find table there */
60 } 60 }
61} 61}
@@ -66,7 +66,7 @@ void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, in
66 lua_pushcfunction(L_, openf_); 66 lua_pushcfunction(L_, openf_);
67 lua_pushstring(L_, modname_); /* argument to open function */ 67 lua_pushstring(L_, modname_); /* argument to open function */
68 lua_call(L_, 1, 1); /* open module */ 68 lua_call(L_, 1, 1); /* open module */
69 luaL_getsubtable(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); 69 luaL_getsubtable(L_, kIdxRegistry, LUA_LOADED_TABLE);
70 lua_pushvalue(L_, -2); /* make copy of module (call result) */ 70 lua_pushvalue(L_, -2); /* make copy of module (call result) */
71 lua_setfield(L_, -2, modname_); /* _LOADED[modname] = module */ 71 lua_setfield(L_, -2, modname_); /* _LOADED[modname] = module */
72 lua_pop(L_, 1); /* remove _LOADED table */ 72 lua_pop(L_, 1); /* remove _LOADED table */
@@ -92,7 +92,7 @@ void* lua_newuserdatauv(lua_State* L_, size_t sz_, [[maybe_unused]] int nuvalue_
92// ################################################################################################# 92// #################################################################################################
93 93
94// push on stack uservalue #n of full userdata at idx 94// push on stack uservalue #n of full userdata at idx
95int lua_getiuservalue(lua_State* const L_, int const idx_, int const n_) 95int lua_getiuservalue(lua_State* const L_, StackIndex const idx_, int const n_)
96{ 96{
97 STACK_CHECK_START_REL(L_, 0); 97 STACK_CHECK_START_REL(L_, 0);
98 // full userdata can have only 1 uservalue before 5.4 98 // full userdata can have only 1 uservalue before 5.4
@@ -129,7 +129,7 @@ int lua_getiuservalue(lua_State* const L_, int const idx_, int const n_)
129 129
130// Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. 130// Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index.
131// Returns 0 if the userdata does not have that value. 131// Returns 0 if the userdata does not have that value.
132int lua_setiuservalue(lua_State* L_, int idx_, int n_) 132int lua_setiuservalue(lua_State* const L_, StackIndex const idx_, int const n_)
133{ 133{
134 if (n_ > 1 134 if (n_ > 1
135#if LUA_VERSION_NUM == 501 135#if LUA_VERSION_NUM == 501
diff --git a/src/compat.h b/src/compat.h
index 8b3eb98..90e72a3 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -32,6 +32,10 @@
32 32
33// ################################################################################################# 33// #################################################################################################
34 34
35static constexpr StackIndex kIdxRegistry{ LUA_REGISTRYINDEX };
36
37// #################################################################################################
38
35// a strong-typed wrapper over lua types to see them easier in a debugger 39// a strong-typed wrapper over lua types to see them easier in a debugger
36enum class LuaType 40enum class LuaType
37{ 41{
@@ -53,13 +57,13 @@ enum class LuaType
53// add some Lua 5.3-style API when building for Lua 5.1 57// add some Lua 5.3-style API when building for Lua 5.1
54#if LUA_VERSION_NUM == 501 58#if LUA_VERSION_NUM == 501
55 59
56inline size_t lua_rawlen(lua_State* L_, int idx_) 60inline size_t lua_rawlen(lua_State* L_, StackIndex idx_)
57{ 61{
58 return lua_objlen(L_, idx_); 62 return lua_objlen(L_, idx_);
59} 63}
60void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_); // implementation copied from Lua 5.2 sources 64void luaL_requiref(lua_State* L_, const char* modname_, lua_CFunction openf_, int glb_); // implementation copied from Lua 5.2 sources
61 65
62int luaL_getsubtable(lua_State* L_, int idx_, const char* fname_); 66int luaL_getsubtable(lua_State* L_, StackIndex idx_, const char* fname_);
63 67
64#endif // LUA_VERSION_NUM == 501 68#endif // LUA_VERSION_NUM == 501
65 69
@@ -80,8 +84,8 @@ inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_)
80#if LUA_VERSION_NUM < 504 84#if LUA_VERSION_NUM < 504
81 85
82void* lua_newuserdatauv(lua_State* L_, size_t sz_, int nuvalue_); 86void* lua_newuserdatauv(lua_State* L_, size_t sz_, int nuvalue_);
83int lua_getiuservalue(lua_State* L_, int idx_, int n_); 87int lua_getiuservalue(lua_State* L_, StackIndex idx_, int n_);
84int lua_setiuservalue(lua_State* L_, int idx_, int n_); 88int lua_setiuservalue(lua_State* L_, StackIndex idx_, int n_);
85 89
86#define LUA_GNAME "_G" 90#define LUA_GNAME "_G"
87 91
@@ -92,7 +96,7 @@ int lua_setiuservalue(lua_State* L_, int idx_, int n_);
92// wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way 96// wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way
93#if LUA_VERSION_NUM == 504 97#if LUA_VERSION_NUM == 504
94 98
95inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_) 99inline int luaL_optint(lua_State* L_, StackIndex n_, lua_Integer d_)
96{ 100{
97 return static_cast<int>(luaL_optinteger(L_, n_, d_)); 101 return static_cast<int>(luaL_optinteger(L_, n_, d_));
98} 102}
@@ -123,7 +127,7 @@ inline constexpr LuaError ToLuaError(int const rc_)
123// ################################################################################################# 127// #################################################################################################
124 128
125// break lexical order for that one because it's needed below 129// break lexical order for that one because it's needed below
126inline LuaType luaG_type(lua_State* const L_, int const idx_) 130inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_)
127{ 131{
128 return static_cast<LuaType>(lua_type(L_, idx_)); 132 return static_cast<LuaType>(lua_type(L_, idx_));
129} 133}
@@ -135,9 +139,9 @@ inline LuaType luaG_type(lua_State* const L_, int const idx_)
135// ################################################################################################# 139// #################################################################################################
136 140
137// use this in place of lua_absindex to save a function call 141// use this in place of lua_absindex to save a function call
138inline int luaG_absindex(lua_State* L_, int idx_) 142inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_)
139{ 143{
140 return (((idx_) >= 0 || (idx_) <= LUA_REGISTRYINDEX) ? (idx_) : lua_gettop(L_) + (idx_) + 1); 144 return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : lua_gettop(L_) + idx_ + 1 };
141} 145}
142 146
143// ################################################################################################# 147// #################################################################################################
@@ -171,7 +175,7 @@ static inline int luaG_dump(lua_State* const L_, lua_Writer const writer_, void*
171 175
172// ################################################################################################# 176// #################################################################################################
173 177
174int luaG_getalluservalues(lua_State* L_, int idx_); 178int luaG_getalluservalues(lua_State* L_, StackIndex idx_);
175 179
176// ################################################################################################# 180// #################################################################################################
177 181
@@ -184,7 +188,7 @@ concept RequiresOldLuaGetfield = requires(LUA_GETFIELD f_)
184}; 188};
185 189
186template <RequiresOldLuaGetfield LUA_GETFIELD> 190template <RequiresOldLuaGetfield LUA_GETFIELD>
187static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, int const idx_, std::string_view const& name_) 191static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_)
188{ 192{
189 f_(L_, idx_, name_.data()); 193 f_(L_, idx_, name_.data());
190 return lua_type(L_, -1); 194 return lua_type(L_, -1);
@@ -201,14 +205,14 @@ concept RequiresNewLuaGetfield = requires(LUA_GETFIELD f_)
201}; 205};
202 206
203template <RequiresNewLuaGetfield LUA_GETFIELD> 207template <RequiresNewLuaGetfield LUA_GETFIELD>
204static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, int const idx_, std::string_view const& name_) 208static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackIndex const idx_, std::string_view const& name_)
205{ 209{
206 return f_(L_, idx_, name_.data()); 210 return f_(L_, idx_, name_.data());
207} 211}
208 212
209// ------------------------------------------------------------------------------------------------- 213// -------------------------------------------------------------------------------------------------
210 214
211static inline LuaType luaG_getfield(lua_State* const L_, int const idx_, std::string_view const& name_) 215static inline LuaType luaG_getfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_)
212{ 216{
213 return static_cast<LuaType>(WrapLuaGetField(lua_getfield, L_, idx_, name_)); 217 return static_cast<LuaType>(WrapLuaGetField(lua_getfield, L_, idx_, name_));
214} 218}
@@ -306,14 +310,14 @@ inline void luaG_pushglobaltable(lua_State* const L_)
306#ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1 310#ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1
307 ::lua_pushvalue(L_, LUA_GLOBALSINDEX); 311 ::lua_pushvalue(L_, LUA_GLOBALSINDEX);
308#else // LUA_GLOBALSINDEX 312#else // LUA_GLOBALSINDEX
309 ::lua_rawgeti(L_, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); 313 ::lua_rawgeti(L_, kIdxRegistry, LUA_RIDX_GLOBALS);
310#endif // LUA_GLOBALSINDEX 314#endif // LUA_GLOBALSINDEX
311} 315}
312 316
313// ################################################################################################# 317// #################################################################################################
314 318
315inline void luaG_setfield(lua_State* const L_, int const idx_, char const* k_) = delete; 319inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, char const* k_) = delete;
316inline void luaG_setfield(lua_State* const L_, int const idx_, std::string_view const& k_) 320inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, std::string_view const& k_)
317{ 321{
318 lua_setfield(L_, idx_, k_.data()); 322 lua_setfield(L_, idx_, k_.data());
319} 323}
@@ -336,7 +340,7 @@ inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname
336 340
337// a small helper to extract a full userdata pointer from the stack in a safe way 341// a small helper to extract a full userdata pointer from the stack in a safe way
338template <typename T> 342template <typename T>
339[[nodiscard]] T* luaG_tofulluserdata(lua_State* const L_, int const index_) 343[[nodiscard]] T* luaG_tofulluserdata(lua_State* const L_, StackIndex const index_)
340{ 344{
341 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA); 345 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA);
342 return static_cast<T*>(lua_touserdata(L_, index_)); 346 return static_cast<T*>(lua_touserdata(L_, index_));
@@ -345,7 +349,7 @@ template <typename T>
345// ------------------------------------------------------------------------------------------------- 349// -------------------------------------------------------------------------------------------------
346 350
347template <typename T> 351template <typename T>
348[[nodiscard]] auto luaG_tolightuserdata(lua_State* const L_, int const index_) 352[[nodiscard]] auto luaG_tolightuserdata(lua_State* const L_, StackIndex const index_)
349{ 353{
350 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_)); 354 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_));
351 if constexpr (std::is_pointer_v<T>) { 355 if constexpr (std::is_pointer_v<T>) {
@@ -364,7 +368,7 @@ template <typename T>
364 368
365// ------------------------------------------------------------------------------------------------- 369// -------------------------------------------------------------------------------------------------
366 370
367[[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, int const idx_) 371[[nodiscard]] inline std::string_view luaG_typename(lua_State* const L_, StackIndex const idx_)
368{ 372{
369 return luaG_typename(L_, luaG_type(L_, idx_)); 373 return luaG_typename(L_, luaG_type(L_, idx_));
370} 374}
@@ -375,21 +379,21 @@ template <typename T>
375#define STRINGVIEW_FMT "%.*s" 379#define STRINGVIEW_FMT "%.*s"
376 380
377// a replacement of lua_tolstring 381// a replacement of lua_tolstring
378[[nodiscard]] inline std::string_view luaG_tostring(lua_State* const L_, int const idx_) 382[[nodiscard]] inline std::string_view luaG_tostring(lua_State* const L_, StackIndex const idx_)
379{ 383{
380 size_t _len{ 0 }; 384 size_t _len{ 0 };
381 char const* _str{ lua_tolstring(L_, idx_, &_len) }; 385 char const* _str{ lua_tolstring(L_, idx_, &_len) };
382 return _str ? std::string_view{ _str, _len } : ""; 386 return _str ? std::string_view{ _str, _len } : "";
383} 387}
384 388
385[[nodiscard]] inline std::string_view luaG_checkstring(lua_State* const L_, int const idx_) 389[[nodiscard]] inline std::string_view luaG_checkstring(lua_State* const L_, StackIndex const idx_)
386{ 390{
387 size_t _len{ 0 }; 391 size_t _len{ 0 };
388 char const* _str{ luaL_checklstring(L_, idx_, &_len) }; 392 char const* _str{ luaL_checklstring(L_, idx_, &_len) };
389 return std::string_view{ _str, _len }; 393 return std::string_view{ _str, _len };
390} 394}
391 395
392[[nodiscard]] inline std::string_view luaG_optstring(lua_State* const L_, int const idx_, std::string_view const& default_) 396[[nodiscard]] inline std::string_view luaG_optstring(lua_State* const L_, StackIndex const idx_, std::string_view const& default_)
393{ 397{
394 if (lua_isnoneornil(L_, idx_)) { 398 if (lua_isnoneornil(L_, idx_)) {
395 return default_; 399 return default_;
@@ -406,7 +410,7 @@ inline std::string_view luaG_pushstring(lua_State* const L_, std::string_view co
406 if constexpr (LUA_VERSION_NUM == 501) { 410 if constexpr (LUA_VERSION_NUM == 501) {
407 // lua_pushlstring doesn't return a value in Lua 5.1 411 // lua_pushlstring doesn't return a value in Lua 5.1
408 lua_pushlstring(L_, str_.data(), str_.size()); 412 lua_pushlstring(L_, str_.data(), str_.size());
409 return luaG_tostring(L_, -1); 413 return luaG_tostring(L_, kIdxTop);
410 } else { 414 } else {
411 return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() }; 415 return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() };
412 } 416 }
diff --git a/src/debug.h b/src/debug.h
index 0f5c6bc..b9a82f1 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -36,8 +36,8 @@ class StackChecker
36 int oldtop; 36 int oldtop;
37 37
38 public: 38 public:
39 using Relative = Unique<int>; 39 DECLARE_UNIQUE_TYPE(Relative, int);
40 using Absolute = Unique<int>; 40 DECLARE_UNIQUE_TYPE(Absolute, int);
41 41
42 StackChecker(lua_State* const L_, Relative const offset_, SourceLocation const& where_ = Where()) 42 StackChecker(lua_State* const L_, Relative const offset_, SourceLocation const& where_ = Where())
43 : L{ L_ } 43 : L{ L_ }
diff --git a/src/deep.cpp b/src/deep.cpp
index bac011f..a244f8b 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -70,7 +70,7 @@ namespace {
70 */ 70 */
71 [[nodiscard]] static int DeepGC(lua_State* const L_) 71 [[nodiscard]] static int DeepGC(lua_State* const L_)
72 { 72 {
73 DeepPrelude* const* const _proxy{ luaG_tofulluserdata<DeepPrelude*>(L_, 1) }; 73 DeepPrelude* const* const _proxy{ luaG_tofulluserdata<DeepPrelude*>(L_, StackIndex{ 1 }) };
74 DeepPrelude* const _p{ *_proxy }; 74 DeepPrelude* const _p{ *_proxy };
75 75
76 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded 76 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded
@@ -130,7 +130,7 @@ void DeepFactory::DeleteDeepObject(lua_State* const L_, DeepPrelude* const o_)
130 130
131// ################################################################################################# 131// #################################################################################################
132 132
133bool DeepFactory::IsDeepUserdata(lua_State* const L_, int const idx_) 133bool DeepFactory::IsDeepUserdata(lua_State* const L_, StackIndex const idx_)
134{ 134{
135 return LookupFactory(L_, idx_, LookupMode::LaneBody) != nullptr; 135 return LookupFactory(L_, idx_, LookupMode::LaneBody) != nullptr;
136} 136}
@@ -138,7 +138,7 @@ bool DeepFactory::IsDeepUserdata(lua_State* const L_, int const idx_)
138// ################################################################################################# 138// #################################################################################################
139 139
140// Return the registered factory for 'index' (deep userdata proxy), or nullptr if 'index' is not a deep userdata proxy. 140// Return the registered factory for 'index' (deep userdata proxy), or nullptr if 'index' is not a deep userdata proxy.
141DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, int const index_, LookupMode const mode_) 141DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, StackIndex const index_, LookupMode const mode_)
142{ 142{
143 // when looking inside a keeper, we are 100% sure the object is a deep userdata 143 // when looking inside a keeper, we are 100% sure the object is a deep userdata
144 if (mode_ == LookupMode::FromKeeper) { 144 if (mode_ == LookupMode::FromKeeper) {
@@ -159,7 +159,7 @@ DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, int const index_, L
159 // replace metatable with the factory pointer, if it is actually a deep userdata 159 // replace metatable with the factory pointer, if it is actually a deep userdata
160 LookupDeep(L_); // L_: deep ... factory|nil 160 LookupDeep(L_); // L_: deep ... factory|nil
161 161
162 DeepFactory* const _ret{ luaG_tolightuserdata<DeepFactory>(L_, -1) }; // nullptr if not a userdata 162 DeepFactory* const _ret{ luaG_tolightuserdata<DeepFactory>(L_, kIdxTop) }; // nullptr if not a userdata
163 lua_pop(L_, 1); 163 lua_pop(L_, 1);
164 STACK_CHECK(L_, 0); 164 STACK_CHECK(L_, 0);
165 return _ret; 165 return _ret;
@@ -207,7 +207,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
207 207
208 if (lua_isnil(L_, -1)) { // No metatable yet. 208 if (lua_isnil(L_, -1)) { // No metatable yet.
209 lua_pop(L_, 1); // L_: DPC proxy 209 lua_pop(L_, 1); // L_: DPC proxy
210 int const _oldtop{ lua_gettop(L_) }; 210 StackIndex const _oldtop{ lua_gettop(L_) };
211 // 1 - make one and register it 211 // 1 - make one and register it
212 if (mode_ != LookupMode::ToKeeper) { 212 if (mode_ != LookupMode::ToKeeper) {
213 _factory.createMetatable(L_); // L_: DPC proxy metatable 213 _factory.createMetatable(L_); // L_: DPC proxy metatable
@@ -216,7 +216,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
216 raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value"); 216 raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value");
217 } 217 }
218 // if the metatable contains a __gc, we will call it from our own 218 // if the metatable contains a __gc, we will call it from our own
219 std::ignore = luaG_getfield(L_, -1, "__gc"); // L_: DPC proxy metatable __gc 219 std::ignore = luaG_getfield(L_, kIdxTop, "__gc"); // L_: DPC proxy metatable __gc
220 } else { 220 } else {
221 // keepers need a minimal metatable that only contains our own __gc 221 // keepers need a minimal metatable that only contains our own __gc
222 lua_createtable(L_, 0, 1); // L_: DPC proxy metatable 222 lua_createtable(L_, 0, 1); // L_: DPC proxy metatable
@@ -245,7 +245,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
245 } 245 }
246 246
247 luaG_pushstring(L_, _modname); // L_: DPC proxy metatable require() "module" 247 luaG_pushstring(L_, _modname); // L_: DPC proxy metatable require() "module"
248 if (luaG_getfield(L_, LUA_REGISTRYINDEX, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED 248 if (luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED
249 // no L.registry._LOADED; can this ever happen? 249 // no L.registry._LOADED; can this ever happen?
250 lua_pop(L_, 6); // L_: 250 lua_pop(L_, 6); // L_:
251 raise_luaL_error(errL_, "unexpected error while requiring a module identified by DeepFactory::moduleName"); 251 raise_luaL_error(errL_, "unexpected error while requiring a module identified by DeepFactory::moduleName");
@@ -263,7 +263,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
263 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error? 263 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error?
264 if (_require_result != LuaError::OK) { 264 if (_require_result != LuaError::OK) {
265 // failed, raise the error in the proper state 265 // failed, raise the error in the proper state
266 raise_luaL_error(errL_, luaG_tostring(L_, -1)); 266 raise_luaL_error(errL_, luaG_tostring(L_, kIdxTop));
267 } 267 }
268 } 268 }
269 } else { // already loaded, we are happy 269 } else { // already loaded, we are happy
@@ -272,7 +272,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
272 } 272 }
273 } 273 }
274 STACK_CHECK(L_, 3); // L_: DPC proxy metatable 274 STACK_CHECK(L_, 3); // L_: DPC proxy metatable
275 LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::USERDATA); 275 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::USERDATA);
276 LUA_ASSERT(L_, lua_istable(L_, -1)); 276 LUA_ASSERT(L_, lua_istable(L_, -1));
277 lua_setmetatable(L_, -2); // L_: DPC proxy 277 lua_setmetatable(L_, -2); // L_: DPC proxy
278 278
@@ -281,7 +281,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
281 lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy 281 lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy
282 lua_rawset(L_, -4); // L_: DPC proxy 282 lua_rawset(L_, -4); // L_: DPC proxy
283 lua_remove(L_, -2); // L_: proxy 283 lua_remove(L_, -2); // L_: proxy
284 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::USERDATA); 284 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::USERDATA);
285 STACK_CHECK(L_, 1); 285 STACK_CHECK(L_, 1);
286} 286}
287 287
@@ -306,7 +306,7 @@ void DeepFactory::pushDeepUserdata(DestState const L_, int const nuv_) const
306{ 306{
307 STACK_GROW(L_, 1); 307 STACK_GROW(L_, 1);
308 STACK_CHECK_START_REL(L_, 0); 308 STACK_CHECK_START_REL(L_, 0);
309 int const _oldtop{ lua_gettop(L_) }; 309 StackIndex const _oldtop{ lua_gettop(L_) };
310 DeepPrelude* const _prelude{ newDeepObjectInternal(L_) }; 310 DeepPrelude* const _prelude{ newDeepObjectInternal(L_) };
311 if (_prelude == nullptr) { 311 if (_prelude == nullptr) {
312 raise_luaL_error(L_, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)"); 312 raise_luaL_error(L_, "DeepFactory::newDeepObjectInternal failed to create deep userdata (out of memory)");
@@ -365,7 +365,7 @@ void DeepFactory::storeDeepLookup(lua_State* const L_) const
365 * Reference count is not changed, and access to the deep userdata is not 365 * Reference count is not changed, and access to the deep userdata is not
366 * serialized. It is the module's responsibility to prevent conflicting usage. 366 * serialized. It is the module's responsibility to prevent conflicting usage.
367 */ 367 */
368DeepPrelude* DeepFactory::toDeep(lua_State* const L_, int const index_) const 368DeepPrelude* DeepFactory::toDeep(lua_State* const L_, StackIndex const index_) const
369{ 369{
370 STACK_CHECK_START_REL(L_, 0); 370 STACK_CHECK_START_REL(L_, 0);
371 // ensure it is actually a deep userdata we created 371 // ensure it is actually a deep userdata we created
diff --git a/src/deep.h b/src/deep.h
index c4c6fd7..d919f64 100644
--- a/src/deep.h
+++ b/src/deep.h
@@ -66,11 +66,11 @@ class DeepFactory
66 public: 66 public:
67 // NVI: public interface 67 // NVI: public interface
68 static void DeleteDeepObject(lua_State* L_, DeepPrelude* o_); 68 static void DeleteDeepObject(lua_State* L_, DeepPrelude* o_);
69 [[nodiscard]] static bool IsDeepUserdata(lua_State* const L_, int const idx_); 69 [[nodiscard]] static bool IsDeepUserdata(lua_State* const L_, StackIndex const idx_);
70 [[nodiscard]] static DeepFactory* LookupFactory(lua_State* L_, int index_, LookupMode mode_); 70 [[nodiscard]] static DeepFactory* LookupFactory(lua_State* L_, StackIndex index_, LookupMode mode_);
71 static void PushDeepProxy(DestState L_, DeepPrelude* o_, int nuv_, LookupMode mode_, lua_State* errL_); 71 static void PushDeepProxy(DestState L_, DeepPrelude* o_, int nuv_, LookupMode mode_, lua_State* errL_);
72 void pushDeepUserdata(DestState L_, int nuv_) const; 72 void pushDeepUserdata(DestState L_, int nuv_) const;
73 [[nodiscard]] DeepPrelude* toDeep(lua_State* L_, int index_) const; 73 [[nodiscard]] DeepPrelude* toDeep(lua_State* L_, StackIndex index_) const;
74}; 74};
75 75
76// ################################################################################################# 76// #################################################################################################
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index e29132d..d21995c 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -100,7 +100,7 @@ THE SOFTWARE.
100 lua_pushvalue(L1, L1_i); // L1: ... v ... {} v 100 lua_pushvalue(L1, L1_i); // L1: ... v ... {} v
101 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" 101 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n"
102 } 102 }
103 std::string_view _fqn{ luaG_tostring(L1, -1) }; 103 std::string_view _fqn{ luaG_tostring(L1, kIdxTop) };
104 DEBUGSPEW_CODE(DebugSpew(U) << "function [C] " << _fqn << std::endl); 104 DEBUGSPEW_CODE(DebugSpew(U) << "function [C] " << _fqn << std::endl);
105 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database 105 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
106 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... 106 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ...
@@ -108,11 +108,12 @@ THE SOFTWARE.
108 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables) 108 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables)
109 // try to discover the name of the function we want to send 109 // try to discover the name of the function we want to send
110 kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name 110 kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name
111 std::string_view const _from{ luaG_tostring(L1, -1) }; 111 std::string_view const _from{ luaG_tostring(L1, kIdxTop) };
112 lua_pushcfunction(L1, LG_nameof); // L1: ... v ... lane_name LG_nameof 112 lua_pushcfunction(L1, LG_nameof); // L1: ... v ... lane_name LG_nameof
113 lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name LG_nameof t 113 lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name LG_nameof t
114 lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil 114 lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil
115 std::string_view const _typewhat{ (luaG_type(L1, -2) == LuaType::STRING) ? luaG_tostring(L1, -2) : luaG_typename(L1, -2) }; 115 StackIndex const _indexTypeWhat{ -2 };
116 std::string_view const _typewhat{ (luaG_type(L1, _indexTypeWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexTypeWhat) : luaG_typename(L1, _indexTypeWhat) };
116 // second return value can be nil if the table was not found 117 // second return value can be nil if the table was not found
117 // probable reason: the function was removed from the source Lua state before Lanes was required. 118 // probable reason: the function was removed from the source Lua state before Lanes was required.
118 std::string_view _what, _gotchaA, _gotchaB; 119 std::string_view _what, _gotchaA, _gotchaB;
@@ -123,7 +124,8 @@ THE SOFTWARE.
123 } else { 124 } else {
124 _gotchaA = ""; 125 _gotchaA = "";
125 _gotchaB = ""; 126 _gotchaB = "";
126 _what = (luaG_type(L1, -1) == LuaType::STRING) ? luaG_tostring(L1, -1) : luaG_typename(L1, -1); 127 StackIndex const _indexWhat{ kIdxTop };
128 _what = (luaG_type(L1, _indexWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexWhat) : luaG_typename(L1, _indexWhat);
127 } 129 }
128 raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat.data(), _gotchaA.data(), _what.data(), _from.empty() ? "main" : _from.data(), _gotchaB.data()); 130 raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat.data(), _gotchaA.data(), _what.data(), _from.empty() ? "main" : _from.data(), _gotchaB.data());
129 } 131 }
@@ -139,15 +141,15 @@ THE SOFTWARE.
139static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull }; 141static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
140 142
141// get a unique ID for metatable at [i]. 143// get a unique ID for metatable at [i].
142[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, int idx_) 144[[nodiscard]] static lua_Integer get_mt_id(Universe* U_, lua_State* L_, StackIndex const idx_)
143{ 145{
144 idx_ = luaG_absindex(L_, idx_); 146 StackIndex const _absidx{ luaG_absindex(L_, idx_) };
145 147
146 STACK_GROW(L_, 3); 148 STACK_GROW(L_, 3);
147 149
148 STACK_CHECK_START_REL(L_, 0); 150 STACK_CHECK_START_REL(L_, 0);
149 std::ignore = kMtIdRegKey.getSubTable(L_, 0, 0); // L_: ... _R[kMtIdRegKey] 151 std::ignore = kMtIdRegKey.getSubTable(L_, 0, 0); // L_: ... _R[kMtIdRegKey]
150 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} 152 lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] {mt}
151 lua_rawget(L_, -2); // L_: ... _R[kMtIdRegKey] mtk? 153 lua_rawget(L_, -2); // L_: ... _R[kMtIdRegKey] mtk?
152 154
153 lua_Integer _id{ lua_tointeger(L_, -1) }; // 0 for nil 155 lua_Integer _id{ lua_tointeger(L_, -1) }; // 0 for nil
@@ -158,12 +160,12 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
158 _id = U_->nextMetatableId.fetch_add(1, std::memory_order_relaxed); 160 _id = U_->nextMetatableId.fetch_add(1, std::memory_order_relaxed);
159 161
160 // Create two-way references: id_uint <-> table 162 // Create two-way references: id_uint <-> table
161 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] {mt} 163 lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] {mt}
162 lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] {mt} id 164 lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] {mt} id
163 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey] 165 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
164 166
165 lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] id 167 lua_pushinteger(L_, _id); // L_: ... _R[kMtIdRegKey] id
166 lua_pushvalue(L_, idx_); // L_: ... _R[kMtIdRegKey] id {mt} 168 lua_pushvalue(L_, _absidx); // L_: ... _R[kMtIdRegKey] id {mt}
167 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey] 169 lua_rawset(L_, -3); // L_: ... _R[kMtIdRegKey]
168 } 170 }
169 lua_pop(L_, 1); // L_: ... 171 lua_pop(L_, 1); // L_: ...
@@ -223,7 +225,7 @@ void InterCopyContext::copyFunction() const
223 } 225 }
224 226
225 { 227 {
226 std::string_view const _bytecode{ luaG_tostring(L1, -1) }; // L1: ... b 228 std::string_view const _bytecode{ luaG_tostring(L1, kIdxTop) }; // L1: ... b
227 LUA_ASSERT(L1, !_bytecode.empty()); 229 LUA_ASSERT(L1, !_bytecode.empty());
228 STACK_GROW(L2, 2); 230 STACK_GROW(L2, 2);
229 // Note: Line numbers seem to be taken precisely from the 231 // Note: Line numbers seem to be taken precisely from the
@@ -282,7 +284,7 @@ void InterCopyContext::copyFunction() const
282 STACK_CHECK(L1, 0); 284 STACK_CHECK(L1, 0);
283 285
284 // Set upvalues (originally set to 'nil' by 'lua_load') 286 // Set upvalues (originally set to 'nil' by 'lua_load')
285 for (int const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) { 287 for (StackIndex const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) {
286 // assign upvalue, popping it from the stack 288 // assign upvalue, popping it from the stack
287 [[maybe_unused]] std::string_view const _upname{ lua_setupvalue(L2, _func_index, _n) };// L2: ... {cache} ... function 289 [[maybe_unused]] std::string_view const _upname{ lua_setupvalue(L2, _func_index, _n) };// L2: ... {cache} ... function
288 LUA_ASSERT(L1, !_upname.empty()); // not having enough slots? 290 LUA_ASSERT(L1, !_upname.empty()); // not having enough slots?
@@ -325,10 +327,10 @@ void InterCopyContext::lookupNativeFunction() const
325 // anything other than function or table should not happen! 327 // anything other than function or table should not happen!
326 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) { 328 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) {
327 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name 329 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name
328 std::string_view const _from{ luaG_tostring(L1, -1) }; 330 std::string_view const _from{ luaG_tostring(L1, kIdxTop) };
329 lua_pop(L1, 1); // L1: ... f ... 331 lua_pop(L1, 1); // L1: ... f ...
330 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name 332 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name
331 std::string_view const _to{ luaG_tostring(L2, -1) }; 333 std::string_view const _to{ luaG_tostring(L2, kIdxTop) };
332 lua_pop(L2, 1); // L2: {} f 334 lua_pop(L2, 1); // L2: {} f
333 raise_luaL_error( 335 raise_luaL_error(
334 getErrL(), 336 getErrL(),
@@ -433,17 +435,17 @@ void InterCopyContext::copyCachedFunction() const
433 return false; 435 return false;
434 } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table 436 } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table
435 kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name 437 kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name
436 std::string_view const _from{ luaG_tostring(L1, -1) }; 438 std::string_view const _from{ luaG_tostring(L1, kIdxTop) };
437 lua_pop(L1, 1); // L1: ... t ... 439 lua_pop(L1, 1); // L1: ... t ...
438 kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name 440 kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name
439 std::string_view const _to{ luaG_tostring(L2, -1) }; 441 std::string_view const _to{ luaG_tostring(L2, kIdxTop) };
440 lua_pop(L2, 1); // L1: ... t ... L2: {} t 442 lua_pop(L2, 1); // L1: ... t ... L2: {} t
441 raise_luaL_error( 443 raise_luaL_error(
442 getErrL(), 444 getErrL(),
443 "%s: source table '%s' found as %s in %s destination transfer database.", 445 "%s: source table '%s' found as %s in %s destination transfer database.",
444 _from.empty() ? "main" : _from.data(), 446 _from.empty() ? "main" : _from.data(),
445 _fqn.data(), 447 _fqn.data(),
446 luaG_typename(L2, -1).data(), 448 luaG_typename(L2, kIdxTop).data(),
447 _to.empty() ? "main" : _to.data()); 449 _to.empty() ? "main" : _to.data());
448 } 450 }
449 lua_remove(L2, -2); // L1: ... t ... L2: t 451 lua_remove(L2, -2); // L1: ... t ... L2: t
@@ -490,13 +492,13 @@ void InterCopyContext::interCopyKeyValuePair() const
490 _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0 492 _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0
491 sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key); 493 sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key);
492 } else if (luaG_type(L1, _key_i) == LuaType::LIGHTUSERDATA) { 494 } else if (luaG_type(L1, _key_i) == LuaType::LIGHTUSERDATA) {
493 void* const key{ lua_touserdata(L1, _key_i) }; 495 void* const _key{ lua_touserdata(L1, _key_i) };
494 _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0 496 _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0
495 sprintf(_valPath, "%s[U:%p]", name.data(), key); 497 sprintf(_valPath, "%s[U:%p]", name.data(), _key);
496 } else if (luaG_type(L1, _key_i) == LuaType::BOOLEAN) { 498 } else if (luaG_type(L1, _key_i) == LuaType::BOOLEAN) {
497 int const key{ lua_toboolean(L1, _key_i) }; 499 int const _key{ lua_toboolean(L1, _key_i) };
498 _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0 500 _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0
499 sprintf(_valPath, "%s[%s]", name.data(), key ? "true" : "false"); 501 sprintf(_valPath, "%s[%s]", name.data(), _key ? "true" : "false");
500 } 502 }
501 } 503 }
502 504
@@ -533,7 +535,7 @@ LuaType InterCopyContext::processConversion() const
533 } 535 }
534 // we have a metatable // L1: ... mt 536 // we have a metatable // L1: ... mt
535 static constexpr std::string_view kConvertField{ "__lanesconvert" }; 537 static constexpr std::string_view kConvertField{ "__lanesconvert" };
536 LuaType const _converterType{ luaG_getfield(L1, -1, kConvertField) }; // L1: ... mt kConvertField 538 LuaType const _converterType{ luaG_getfield(L1, kIdxTop, kConvertField) }; // L1: ... mt kConvertField
537 switch (_converterType) { 539 switch (_converterType) {
538 case LuaType::NIL: 540 case LuaType::NIL:
539 // no __lanesconvert, nothing to do 541 // no __lanesconvert, nothing to do
@@ -541,7 +543,7 @@ LuaType InterCopyContext::processConversion() const
541 break; 543 break;
542 544
543 case LuaType::LIGHTUSERDATA: 545 case LuaType::LIGHTUSERDATA:
544 if (kNilSentinel.equals(L1, -1)) { 546 if (kNilSentinel.equals(L1, kIdxTop)) {
545 DEBUGSPEW_CODE(DebugSpew(U) << "converted " << luaG_typename(L1, _val_type) << " to nil" << std::endl); 547 DEBUGSPEW_CODE(DebugSpew(U) << "converted " << luaG_typename(L1, _val_type) << " to nil" << std::endl);
546 lua_replace(L1, L1_i); // L1: ... mt 548 lua_replace(L1, L1_i); // L1: ... mt
547 lua_pop(L1, 1); // L1: ... 549 lua_pop(L1, 1); // L1: ...
@@ -553,7 +555,7 @@ LuaType InterCopyContext::processConversion() const
553 555
554 case LuaType::STRING: 556 case LuaType::STRING:
555 // kConvertField == "decay" -> replace source value with it's pointer 557 // kConvertField == "decay" -> replace source value with it's pointer
556 if (std::string_view const _mode{ luaG_tostring(L1, -1) }; _mode == "decay") { 558 if (std::string_view const _mode{ luaG_tostring(L1, kIdxTop) }; _mode == "decay") {
557 lua_pop(L1, 1); // L1: ... mt 559 lua_pop(L1, 1); // L1: ... mt
558 lua_pushlightuserdata(L1, const_cast<void*>(lua_topointer(L1, L1_i))); // L1: ... mt decayed 560 lua_pushlightuserdata(L1, const_cast<void*>(lua_topointer(L1, L1_i))); // L1: ... mt decayed
559 lua_replace(L1, L1_i); // L1: ... mt 561 lua_replace(L1, L1_i); // L1: ... mt
@@ -592,7 +594,7 @@ LuaType InterCopyContext::processConversion() const
592 } 594 }
593 STACK_CHECK(L1, 1); 595 STACK_CHECK(L1, 1);
594 596
595 lua_Integer const _mt_id{ get_mt_id(U, L1, -1) }; // Unique id for the metatable 597 lua_Integer const _mt_id{ get_mt_id(U, L1, kIdxTop) }; // Unique id for the metatable
596 598
597 STACK_CHECK_START_REL(L2, 0); 599 STACK_CHECK_START_REL(L2, 0);
598 STACK_GROW(L2, 4); 600 STACK_GROW(L2, 4);
@@ -693,7 +695,7 @@ LuaType InterCopyContext::processConversion() const
693 } 695 }
694 696
695 // no __lanesclone? -> not clonable 697 // no __lanesclone? -> not clonable
696 if (luaG_getfield(L1, -1, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil 698 if (luaG_getfield(L1, kIdxTop, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil
697 lua_pop(L1, 2); // L1: ... 699 lua_pop(L1, 2); // L1: ...
698 STACK_CHECK(L1, 0); 700 STACK_CHECK(L1, 0);
699 return false; 701 return false;
@@ -703,7 +705,7 @@ LuaType InterCopyContext::processConversion() const
703 705
704 // we need to copy over the uservalues of the userdata as well 706 // we need to copy over the uservalues of the userdata as well
705 { 707 {
706 int const _mt{ luaG_absindex(L1, -2) }; // L1: ... mt __lanesclone 708 StackIndex const _mt{ luaG_absindex(L1, StackIndex{ -2 }) }; // L1: ... mt __lanesclone
707 size_t const userdata_size{ lua_rawlen(L1, _L1_i) }; 709 size_t const userdata_size{ lua_rawlen(L1, _L1_i) };
708 // extract all the uservalues, but don't transfer them yet 710 // extract all the uservalues, but don't transfer them yet
709 int const _nuv{ luaG_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]* 711 int const _nuv{ luaG_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]*
@@ -738,13 +740,13 @@ LuaType InterCopyContext::processConversion() const
738 // assign uservalues 740 // assign uservalues
739 int _uvi{ _nuv }; 741 int _uvi{ _nuv };
740 while (_uvi > 0) { 742 while (_uvi > 0) {
741 _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; 743 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
742 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv 744 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv
743 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 745 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
744 } 746 }
745 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]* 747 lua_pop(L1, 1); // L1: ... mt __lanesclone [uv]*
746 // this pops the value from the stack 748 // this pops the value from the stack
747 lua_setiuservalue(L2, -2, _uvi); // L2: ... u 749 lua_setiuservalue(L2, StackIndex{ -2 }, _uvi); // L2: ... u
748 --_uvi; 750 --_uvi;
749 } 751 }
750 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination 752 // when we are done, all uservalues are popped from the source stack, and we want only the single transferred value in the destination
@@ -792,11 +794,11 @@ LuaType InterCopyContext::processConversion() const
792 // transfer all uservalues of the source in the destination 794 // transfer all uservalues of the source in the destination
793 { 795 {
794 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name }; 796 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, name };
795 int const _clone_i{ lua_gettop(L2) }; 797 StackIndex const _clone_i{ lua_gettop(L2) };
796 STACK_GROW(L2, _nuv); 798 STACK_GROW(L2, _nuv);
797 int _uvi{ _nuv }; 799 int _uvi{ _nuv };
798 while (_uvi) { 800 while (_uvi) {
799 _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; 801 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
800 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv 802 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv
801 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 803 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
802 } 804 }
@@ -862,7 +864,7 @@ LuaType InterCopyContext::processConversion() const
862 _source = lua_touserdata(L1, -1); 864 _source = lua_touserdata(L1, -1);
863 void* _clone{ nullptr }; 865 void* _clone{ nullptr };
864 // get the number of bytes to allocate for the clone 866 // get the number of bytes to allocate for the clone
865 size_t const userdata_size{ lua_rawlen(L1, -1) }; 867 size_t const userdata_size{ lua_rawlen(L1, kIdxTop) };
866 { 868 {
867 // extract uservalues (don't transfer them yet) 869 // extract uservalues (don't transfer them yet)
868 int const _nuv{ luaG_getalluservalues(L1, source_i) }; // L1: ... u [uv]* 870 int const _nuv{ luaG_getalluservalues(L1, source_i) }; // L1: ... u [uv]*
@@ -880,13 +882,13 @@ LuaType InterCopyContext::processConversion() const
880 InterCopyContext _c{ *this }; 882 InterCopyContext _c{ *this };
881 int _uvi{ _nuv }; 883 int _uvi{ _nuv };
882 while (_uvi > 0) { 884 while (_uvi > 0) {
883 _c.L1_i = SourceIndex{ luaG_absindex(L1, -1) }; 885 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop) };
884 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv 886 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv
885 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 887 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
886 } 888 }
887 lua_pop(L1, 1); // L1: ... u [uv]* 889 lua_pop(L1, 1); // L1: ... u [uv]*
888 // this pops the value from the stack 890 // this pops the value from the stack
889 lua_setiuservalue(L2, -2, _uvi); // L2: ... mt u 891 lua_setiuservalue(L2, StackIndex{ -2 }, _uvi); // L2: ... mt u
890 --_uvi; 892 --_uvi;
891 } 893 }
892 // when we are done, all uservalues are popped from the stack, we can pop the source as well 894 // when we are done, all uservalues are popped from the stack, we can pop the source as well
@@ -897,7 +899,7 @@ LuaType InterCopyContext::processConversion() const
897 // perform the custom cloning part 899 // perform the custom cloning part
898 lua_insert(L2, -2); // L2: ... u mt 900 lua_insert(L2, -2); // L2: ... u mt
899 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with 901 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
900 LuaType const _funcType{ luaG_getfield(L2, -1, "__lanesclone") }; // L2: ... u mt __lanesclone 902 LuaType const _funcType{ luaG_getfield(L2, kIdxTop, "__lanesclone") }; // L2: ... u mt __lanesclone
901 if (_funcType != LuaType::FUNCTION) { 903 if (_funcType != LuaType::FUNCTION) {
902 raise_luaL_error(getErrL(), "INTERNAL ERROR: __lanesclone is a %s, not a function", luaG_typename(L2, _funcType).data()); 904 raise_luaL_error(getErrL(), "INTERNAL ERROR: __lanesclone is a %s, not a function", luaG_typename(L2, _funcType).data());
903 } 905 }
@@ -1191,7 +1193,7 @@ namespace {
1191 { 1193 {
1192 private: 1194 private:
1193 lua_State* const L2; 1195 lua_State* const L2;
1194 int const top_L2; 1196 StackIndex const top_L2;
1195 DEBUGSPEW_CODE(DebugSpewIndentScope scope); 1197 DEBUGSPEW_CODE(DebugSpewIndentScope scope);
1196 1198
1197 public: 1199 public:
@@ -1246,7 +1248,7 @@ namespace {
1246 STACK_CHECK(L1, 0); 1248 STACK_CHECK(L1, 0);
1247 } 1249 }
1248 if (_result == InterCopyResult::Success) { 1250 if (_result == InterCopyResult::Success) {
1249 luaG_setfield(L2, -2, _entry); // set package[entry] 1251 luaG_setfield(L2, StackIndex{ -2 }, _entry); // set package[entry]
1250 } else { 1252 } else {
1251 std::string_view const _msg{ luaG_pushstring(L1, "failed to copy package.%s", _entry.data()) }; 1253 std::string_view const _msg{ luaG_pushstring(L1, "failed to copy package.%s", _entry.data()) };
1252 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later 1254 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
@@ -1273,7 +1275,7 @@ namespace {
1273 DEBUGSPEW_CODE(DebugSpew(U) << "InterCopyContext::interCopy()" << std::endl); 1275 DEBUGSPEW_CODE(DebugSpew(U) << "InterCopyContext::interCopy()" << std::endl);
1274 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U }); 1276 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U });
1275 1277
1276 int const _top_L1{ lua_gettop(L1) }; 1278 StackIndex const _top_L1{ lua_gettop(L1) };
1277 int const _available{ (L1_i != 0) ? (_top_L1 - L1_i + 1) : _top_L1 }; 1279 int const _available{ (L1_i != 0) ? (_top_L1 - L1_i + 1) : _top_L1 };
1278 if (n_ > _available) { 1280 if (n_ > _available) {
1279 // requesting to copy more than is available? 1281 // requesting to copy more than is available?
@@ -1289,17 +1291,17 @@ namespace {
1289 * function entries, avoiding the same entries to be passed on as multiple 1291 * function entries, avoiding the same entries to be passed on as multiple
1290 * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner! 1292 * copies. ESSENTIAL i.e. for handling upvalue tables in the right manner!
1291 */ 1293 */
1292 int const _top_L2{ lua_gettop(L2) }; // L2: ... 1294 StackIndex const _top_L2{ lua_gettop(L2) }; // L2: ...
1293 lua_newtable(L2); // L2: ... cache 1295 lua_newtable(L2); // L2: ... cache
1294 1296
1295 InterCopyContext _c{ U, L2, L1, CacheIndex{ _top_L2 + 1 }, {}, VT::NORMAL, mode, "?" }; 1297 InterCopyContext _c{ U, L2, L1, CacheIndex{ _top_L2 + 1 }, {}, VT::NORMAL, mode, "?" };
1296 InterCopyResult _copyok{ InterCopyResult::Success }; 1298 InterCopyResult _copyok{ InterCopyResult::Success };
1297 STACK_CHECK_START_REL(L1, 0); 1299 STACK_CHECK_START_REL(L1, 0);
1298 // if L1_i is specified, start here, else take the _n items off the top of the stack 1300 // if L1_i is specified, start here, else take the _n items off the top of the stack
1299 for (int _i{ L1_i != 0 ? L1_i : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) { 1301 for (StackIndex _i{ L1_i != 0 ? L1_i : (_top_L1 - n_ + 1) }, _j{ 1 }; _j <= n_; ++_i, ++_j) {
1300 char _tmpBuf[16]; 1302 char _tmpBuf[16];
1301 if (U->verboseErrors) { 1303 if (U->verboseErrors) {
1302 sprintf(_tmpBuf, "arg_%d", _j); 1304 sprintf(_tmpBuf, "arg_%d", _j.operator int());
1303 _c.name = _tmpBuf; 1305 _c.name = _tmpBuf;
1304 } 1306 }
1305 _c.L1_i = SourceIndex{ _i }; 1307 _c.L1_i = SourceIndex{ _i };
diff --git a/src/intercopycontext.h b/src/intercopycontext.h
index 8d4b68f..a9be267 100644
--- a/src/intercopycontext.h
+++ b/src/intercopycontext.h
@@ -23,8 +23,8 @@ enum class InterCopyResult
23 23
24// ################################################################################################# 24// #################################################################################################
25 25
26using CacheIndex = Unique<int>; 26DECLARE_UNIQUE_TYPE(CacheIndex, StackIndex);
27using SourceIndex = Unique<int>; 27DECLARE_UNIQUE_TYPE(SourceIndex, StackIndex);
28class InterCopyContext 28class InterCopyContext
29{ 29{
30 public: 30 public:
diff --git a/src/keeper.cpp b/src/keeper.cpp
index 58796b8..46f580b 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -82,10 +82,10 @@ class KeyUD
82 82
83 [[nodiscard]] bool changeLimit(LindaLimit limit_); 83 [[nodiscard]] bool changeLimit(LindaLimit limit_);
84 [[nodiscard]] static KeyUD* Create(KeeperState K_); 84 [[nodiscard]] static KeyUD* Create(KeeperState K_);
85 [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, int idx_); 85 [[nodiscard]] static KeyUD* GetPtr(KeeperState K_, StackIndex idx_);
86 void peek(KeeperState K_, int count_) const; // keepercall_get 86 void peek(KeeperState K_, int count_) const; // keepercall_get
87 [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched] 87 [[nodiscard]] int pop(KeeperState K_, int minCount_, int maxCount_); // keepercall_receive[_batched]
88 void prepareAccess(KeeperState K_, int idx_) const; 88 void prepareAccess(KeeperState K_, StackIndex idx_) const;
89 [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set 89 [[nodiscard]] bool push(KeeperState K_, int count_, bool enforceLimit_); // keepercall_send and keepercall_set
90 void pushFillStatus(KeeperState K_) const; 90 void pushFillStatus(KeeperState K_) const;
91 static void PushFillStatus(KeeperState K_, KeyUD const* key_); 91 static void PushFillStatus(KeeperState K_, KeyUD const* key_);
@@ -116,14 +116,14 @@ KeyUD* KeyUD::Create(KeeperState const K_)
116 KeyUD* const _key{ new (K_) KeyUD{} }; 116 KeyUD* const _key{ new (K_) KeyUD{} };
117 STACK_CHECK(K_, 1); 117 STACK_CHECK(K_, 1);
118 lua_newtable(K_); 118 lua_newtable(K_);
119 lua_setiuservalue(K_, -2, kContentsTableIndex); 119 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex);
120 STACK_CHECK(K_, 1); 120 STACK_CHECK(K_, 1);
121 return _key; 121 return _key;
122} 122}
123 123
124// ################################################################################################# 124// #################################################################################################
125 125
126KeyUD* KeyUD::GetPtr(KeeperState const K_, int idx_) 126KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_)
127{ 127{
128 return luaG_tofulluserdata<KeyUD>(K_, idx_); 128 return luaG_tofulluserdata<KeyUD>(K_, idx_);
129} 129}
@@ -137,7 +137,7 @@ KeyUD* KeyUD::GetPtr(KeeperState const K_, int idx_)
137void KeyUD::peek(KeeperState const K_, int const count_) const 137void KeyUD::peek(KeeperState const K_, int const count_) const
138{ 138{
139 STACK_CHECK_START_ABS(K_, 1); 139 STACK_CHECK_START_ABS(K_, 1);
140 LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); // K_: KeyUD 140 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: KeyUD
141 if (count <= 0) { // no data is available 141 if (count <= 0) { // no data is available
142 lua_pop(K_, 1); // K_: 142 lua_pop(K_, 1); // K_:
143 lua_pushinteger(K_, 0); // K_: 0 143 lua_pushinteger(K_, 0); // K_: 0
@@ -145,7 +145,7 @@ void KeyUD::peek(KeeperState const K_, int const count_) const
145 } 145 }
146 146
147 // read <count_> value off the fifo, if possible 147 // read <count_> value off the fifo, if possible
148 prepareAccess(K_, -1); // K_: fifo 148 prepareAccess(K_, kIdxTop); // K_: fifo
149 int const _count{ std::min(count_, count) }; 149 int const _count{ std::min(count_, count) };
150 lua_pushinteger(K_, _count); // K_: fifo _count 150 lua_pushinteger(K_, _count); // K_: fifo _count
151 lua_insert(K_, 1); // K_: _count fifo 151 lua_insert(K_, 1); // K_: _count fifo
@@ -171,9 +171,9 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_)
171 return 0; 171 return 0;
172 } 172 }
173 int const _popCount{ std::min(count, maxCount_) }; 173 int const _popCount{ std::min(count, maxCount_) };
174 LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); // K_: ... this 174 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this
175 prepareAccess(K_, -1); // K_: ... fifo 175 prepareAccess(K_, kIdxTop); // K_: ... fifo
176 int const _fifo_idx{ lua_gettop(K_) }; 176 StackIndex const _fifo_idx{ lua_gettop(K_) };
177 // each iteration pushes a value on the stack! 177 // each iteration pushes a value on the stack!
178 STACK_GROW(K_, _popCount + 2); 178 STACK_GROW(K_, _popCount + 2);
179 // skip first item, we will push it last 179 // skip first item, we will push it last
@@ -202,9 +202,9 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_)
202 202
203// expects 'this' at the specified index 203// expects 'this' at the specified index
204// replaces it by its uservalue on the stack (the table holding the fifo values) 204// replaces it by its uservalue on the stack (the table holding the fifo values)
205void KeyUD::prepareAccess(KeeperState const K_, int const idx_) const 205void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const
206{ 206{
207 int const _idx{ luaG_absindex(K_, idx_) }; 207 StackIndex const _idx{ luaG_absindex(K_, idx_) };
208 LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this); 208 LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this);
209 // we can replace the key userdata in the stack without fear of it being GCed, there are other references around 209 // we can replace the key userdata in the stack without fear of it being GCed, there are other references around
210 lua_getiuservalue(K_, _idx, kContentsTableIndex); 210 lua_getiuservalue(K_, _idx, kContentsTableIndex);
@@ -217,7 +217,7 @@ void KeyUD::prepareAccess(KeeperState const K_, int const idx_) const
217// out: nothing, removes all pushed values from the stack 217// out: nothing, removes all pushed values from the stack
218bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) 218bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_)
219{ 219{
220 int const _fifoIdx{ luaG_absindex(K_, -1 - count_) }; 220 StackIndex const _fifoIdx{ luaG_absindex(K_, StackIndex{ -1 - count_ }) };
221 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... 221 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val...
222 if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room 222 if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room
223 return false; 223 return false;
@@ -270,13 +270,13 @@ void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_)
270// expects 'this' on top of the stack 270// expects 'this' on top of the stack
271bool KeyUD::reset(KeeperState const K_) 271bool KeyUD::reset(KeeperState const K_)
272{ 272{
273 LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); 273 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this);
274 STACK_CHECK_START_REL(K_, 0); 274 STACK_CHECK_START_REL(K_, 0);
275 bool const _wasFull{ (limit > 0) && (count >= limit) }; 275 bool const _wasFull{ (limit > 0) && (count >= limit) };
276 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 276 // empty the KeyUD: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
277 // if we have an actual limit, use it to preconfigure the table 277 // if we have an actual limit, use it to preconfigure the table
278 lua_createtable(K_, (limit <= 0) ? 0 : limit, 0); // K_: KeysDB key val... KeyUD {} 278 lua_createtable(K_, (limit <= 0) ? 0 : limit, 0); // K_: KeysDB key val... KeyUD {}
279 lua_setiuservalue(K_, -2, kContentsTableIndex); // K_: KeysDB key val... KeyUD 279 lua_setiuservalue(K_, StackIndex{ -2 }, kContentsTableIndex); // K_: KeysDB key val... KeyUD
280 first = 1; 280 first = 1;
281 count = 0; 281 count = 0;
282 STACK_CHECK(K_, 0); 282 STACK_CHECK(K_, 0);
@@ -290,20 +290,20 @@ bool KeyUD::reset(KeeperState const K_)
290// out: the KeysDB table of the linda is pushed at the top of the stack 290// out: the KeysDB table of the linda is pushed at the top of the stack
291// xxh64 of string "kLindasRegKey" generated at https://www.pelock.com/products/hash-calculator 291// xxh64 of string "kLindasRegKey" generated at https://www.pelock.com/products/hash-calculator
292static constexpr RegistryUniqueKey kLindasRegKey{ 0x3AE0D5243A88B962ull }; 292static constexpr RegistryUniqueKey kLindasRegKey{ 0x3AE0D5243A88B962ull };
293static void PushKeysDB(KeeperState const K_, int const idx_) 293static void PushKeysDB(KeeperState const K_, StackIndex const idx_)
294{ 294{
295 STACK_GROW(K_, 5); 295 STACK_GROW(K_, 5);
296 STACK_CHECK_START_REL(K_, 0); 296 STACK_CHECK_START_REL(K_, 0);
297 int const _idx{ luaG_absindex(K_, idx_) }; 297 StackIndex const _absidx{ luaG_absindex(K_, idx_) };
298 kLindasRegKey.pushValue(K_); // K_: ... LindasDB 298 kLindasRegKey.pushValue(K_); // K_: ... LindasDB
299 lua_pushvalue(K_, _idx); // K_: ... LindasDB linda 299 lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda
300 lua_rawget(K_, -2); // K_: ... LindasDB KeysDB 300 lua_rawget(K_, -2); // K_: ... LindasDB KeysDB
301 STACK_CHECK(K_, 2); 301 STACK_CHECK(K_, 2);
302 if (lua_isnil(K_, -1)) { 302 if (lua_isnil(K_, -1)) {
303 lua_pop(K_, 1); // K_: ... LindasDB 303 lua_pop(K_, 1); // K_: ... LindasDB
304 // add a new KeysDB table for this linda 304 // add a new KeysDB table for this linda
305 lua_newtable(K_); // K_: ... LindasDB KeysDB 305 lua_newtable(K_); // K_: ... LindasDB KeysDB
306 lua_pushvalue(K_, _idx); // K_: ... LindasDB KeysDB linda 306 lua_pushvalue(K_, _absidx); // K_: ... LindasDB KeysDB linda
307 lua_pushvalue(K_, -2); // K_: ... LindasDB KeysDB linda KeysDB 307 lua_pushvalue(K_, -2); // K_: ... LindasDB KeysDB linda KeysDB
308 lua_rawset(K_, -4); // K_: ... LindasDB KeysDB 308 lua_rawset(K_, -4); // K_: ... LindasDB KeysDB
309 } 309 }
@@ -326,12 +326,12 @@ int keepercall_count(lua_State* const L_)
326 switch (lua_gettop(_K)) { 326 switch (lua_gettop(_K)) {
327 // no key is specified: return a table giving the count of all known keys 327 // no key is specified: return a table giving the count of all known keys
328 case 1: // _K: linda 328 case 1: // _K: linda
329 PushKeysDB(_K, 1); // _K: linda KeysDB 329 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda KeysDB
330 lua_newtable(_K); // _K: linda KeysDB out 330 lua_newtable(_K); // _K: linda KeysDB out
331 lua_replace(_K, 1); // _K: out KeysDB 331 lua_replace(_K, 1); // _K: out KeysDB
332 lua_pushnil(_K); // _K: out KeysDB nil 332 lua_pushnil(_K); // _K: out KeysDB nil
333 while (lua_next(_K, 2)) { // _K: out KeysDB key KeyUD 333 while (lua_next(_K, 2)) { // _K: out KeysDB key KeyUD
334 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 334 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
335 lua_pop(_K, 1); // _K: out KeysDB key 335 lua_pop(_K, 1); // _K: out KeysDB key
336 lua_pushvalue(_K, -1); // _K: out KeysDB key key 336 lua_pushvalue(_K, -1); // _K: out KeysDB key key
337 lua_pushinteger(_K, _key->count); // _K: out KeysDB key key count 337 lua_pushinteger(_K, _key->count); // _K: out KeysDB key key count
@@ -342,13 +342,13 @@ int keepercall_count(lua_State* const L_)
342 342
343 // 1 key is specified: return its count 343 // 1 key is specified: return its count
344 case 2: // _K: linda key 344 case 2: // _K: linda key
345 PushKeysDB(_K, 1); // _K: linda key KeysDB 345 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB
346 lua_replace(_K, 1); // _K: KeysDB key 346 lua_replace(_K, 1); // _K: KeysDB key
347 lua_rawget(_K, -2); // _K: KeysDB KeyUD|nil 347 lua_rawget(_K, -2); // _K: KeysDB KeyUD|nil
348 if (lua_isnil(_K, -1)) { // the key is unknown // _K: KeysDB nil 348 if (lua_isnil(_K, -1)) { // the key is unknown // _K: KeysDB nil
349 lua_remove(_K, -2); // _K: nil 349 lua_remove(_K, -2); // _K: nil
350 } else { // the key is known // _K: KeysDB KeyUD 350 } else { // the key is known // _K: KeysDB KeyUD
351 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 351 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
352 lua_pushinteger(_K, _key->count); // _K: KeysDB KeyUD count 352 lua_pushinteger(_K, _key->count); // _K: KeysDB KeyUD count
353 lua_replace(_K, -3); // _K: count KeyUD 353 lua_replace(_K, -3); // _K: count KeyUD
354 lua_pop(_K, 1); // _K: count 354 lua_pop(_K, 1); // _K: count
@@ -358,14 +358,14 @@ int keepercall_count(lua_State* const L_)
358 // a variable number of keys is specified: return a table of their counts 358 // a variable number of keys is specified: return a table of their counts
359 default: // _K: linda keys... key#1 359 default: // _K: linda keys... key#1
360 lua_pushvalue(_K, 2); // duplicate the first key of the list // _K: linda keys... key#1 360 lua_pushvalue(_K, 2); // duplicate the first key of the list // _K: linda keys... key#1
361 PushKeysDB(_K, 1); // _K: linda keys... key#1 KeysDB 361 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda keys... key#1 KeysDB
362 lua_newtable(_K); // _K: linda keys... key#1 KeysDB out 362 lua_newtable(_K); // _K: linda keys... key#1 KeysDB out
363 lua_replace(_K, 1); // _K: out keys... key#1 KeysDB 363 lua_replace(_K, 1); // _K: out keys... key#1 KeysDB
364 lua_replace(_K, 2); // the list of keys is the same, but for key#1 moved at the end // _K: out KeysDB keys... 364 lua_replace(_K, 2); // the list of keys is the same, but for key#1 moved at the end // _K: out KeysDB keys...
365 while (lua_gettop(_K) > 2) { 365 while (lua_gettop(_K) > 2) {
366 lua_pushvalue(_K, -1); // _K: out KeysDB keys... key 366 lua_pushvalue(_K, -1); // _K: out KeysDB keys... key
367 lua_rawget(_K, 2); // _K: out KeysDB keys... KeyUD|nil 367 lua_rawget(_K, 2); // _K: out KeysDB keys... KeyUD|nil
368 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 368 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
369 lua_pop(_K, 1); // _K: out KeysDB keys... 369 lua_pop(_K, 1); // _K: out KeysDB keys...
370 if (_key != nullptr) { // the key is known 370 if (_key != nullptr) { // the key is known
371 lua_pushinteger(_K, _key->count); // _K: out KeysDB keys... count 371 lua_pushinteger(_K, _key->count); // _K: out KeysDB keys... count
@@ -410,11 +410,11 @@ int keepercall_get(lua_State* const L_)
410 _count = static_cast<int>(lua_tointeger(_K, 3)); // linda:get() made sure _count >= 1 410 _count = static_cast<int>(lua_tointeger(_K, 3)); // linda:get() made sure _count >= 1
411 lua_pop(_K, 1); // _K: linda key 411 lua_pop(_K, 1); // _K: linda key
412 } 412 }
413 PushKeysDB(_K, 1); // _K: linda key KeysDB 413 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB
414 lua_replace(_K, 1); // _K: KeysDB key 414 lua_replace(_K, 1); // _K: KeysDB key
415 lua_rawget(_K, 1); // _K: KeysDB KeyUD 415 lua_rawget(_K, 1); // _K: KeysDB KeyUD
416 lua_remove(_K, 1); // _K: KeyUD 416 lua_remove(_K, 1); // _K: KeyUD
417 KeyUD const* const _key{ KeyUD::GetPtr(_K, -1) }; 417 KeyUD const* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
418 if (_key != nullptr) { 418 if (_key != nullptr) {
419 _key->peek(_K, _count); // _K: N val... 419 _key->peek(_K, _count); // _K: N val...
420 } else { 420 } else {
@@ -438,11 +438,11 @@ int keepercall_limit(lua_State* const L_)
438 bool const _reading{ lua_gettop(_K) == 2 }; 438 bool const _reading{ lua_gettop(_K) == 2 };
439 LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent 439 LindaLimit const _limit{ static_cast<LindaLimit::type>(luaL_optinteger(_K, 3, -1)) }; // -1 if we read nil because the argument is absent
440 lua_settop(_K, 2); // _K: linda key 440 lua_settop(_K, 2); // _K: linda key
441 PushKeysDB(_K, 1); // _K: linda key KeysDB 441 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB
442 lua_replace(_K, 1); // _K: KeysDB key 442 lua_replace(_K, 1); // _K: KeysDB key
443 lua_pushvalue(_K, -1); // _K: KeysDB key key 443 lua_pushvalue(_K, -1); // _K: KeysDB key key
444 lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil 444 lua_rawget(_K, -3); // _K: KeysDB key KeyUD|nil
445 KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; 445 KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) };
446 if (_reading) { 446 if (_reading) {
447 // remove any clutter on the stack 447 // remove any clutter on the stack
448 lua_settop(_K, 0); // _K: 448 lua_settop(_K, 0); // _K:
@@ -476,14 +476,14 @@ int keepercall_limit(lua_State* const L_)
476int keepercall_receive(lua_State* const L_) 476int keepercall_receive(lua_State* const L_)
477{ 477{
478 KeeperState const _K{ L_ }; 478 KeeperState const _K{ L_ };
479 int const _top{ lua_gettop(_K) }; 479 StackIndex const _top{ lua_gettop(_K) };
480 PushKeysDB(_K, 1); // _K: linda keys... KeysDB 480 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda keys... KeysDB
481 lua_replace(_K, 1); // _K: KeysDB keys... 481 lua_replace(_K, 1); // _K: KeysDB keys...
482 482
483 for (int const _keyIdx : std::ranges::iota_view{ 2, _top + 1 }) { 483 for (StackIndex const _keyIdx : std::ranges::iota_view{ StackIndex{ 2 }, _top + 1 }) {
484 lua_pushvalue(_K, _keyIdx); // _K: KeysDB keys... key[i] 484 lua_pushvalue(_K, _keyIdx); // _K: KeysDB keys... key[i]
485 lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD 485 lua_rawget(_K, 1); // _K: KeysDB keys... KeyUD
486 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 486 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
487 if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to 487 if (_key != nullptr) { // it's fine to attempt a read on a key that wasn't yet written to
488 int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val 488 int const _popped{ _key->pop(_K, 1, 1) }; // _K: KeysDB keys... val
489 if (_popped > 0) { 489 if (_popped > 0) {
@@ -514,12 +514,12 @@ int keepercall_receive_batched(lua_State* const L_)
514 int const _max_count{ static_cast<int>(luaL_optinteger(_K, 4, _min_count)) }; 514 int const _max_count{ static_cast<int>(luaL_optinteger(_K, 4, _min_count)) };
515 lua_settop(_K, 2); // _K: linda key 515 lua_settop(_K, 2); // _K: linda key
516 lua_insert(_K, 1); // _K: key linda 516 lua_insert(_K, 1); // _K: key linda
517 PushKeysDB(_K, 2); // _K: key linda KeysDB 517 PushKeysDB(_K, StackIndex{ 2 }); // _K: key linda KeysDB
518 lua_remove(_K, 2); // _K: key KeysDB 518 lua_remove(_K, 2); // _K: key KeysDB
519 lua_pushvalue(_K, 1); // _K: key KeysDB key 519 lua_pushvalue(_K, 1); // _K: key KeysDB key
520 lua_rawget(_K, 2); // _K: key KeysDB KeyUD 520 lua_rawget(_K, 2); // _K: key KeysDB KeyUD
521 lua_remove(_K, 2); // _K: key KeyUD 521 lua_remove(_K, 2); // _K: key KeyUD
522 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 522 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
523 if (_key == nullptr || _key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap 523 if (_key == nullptr || _key->pop(_K, _min_count, _max_count) == 0) { // _K: [key val...]|crap
524 // Lua will adjust the stack for us when we return 524 // Lua will adjust the stack for us when we return
525 return 0; 525 return 0;
@@ -538,7 +538,7 @@ int keepercall_send(lua_State* const L_)
538 KeeperState const _K{ L_ }; 538 KeeperState const _K{ L_ };
539 int const _n{ lua_gettop(_K) - 2 }; 539 int const _n{ lua_gettop(_K) - 2 };
540 STACK_CHECK_START_REL(_K, 0); // _K: linda key val... 540 STACK_CHECK_START_REL(_K, 0); // _K: linda key val...
541 PushKeysDB(_K, 1); // _K: linda key val... KeysDB 541 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB
542 // get the fifo associated to this key in this linda, create it if it doesn't exist 542 // get the fifo associated to this key in this linda, create it if it doesn't exist
543 lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key 543 lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key
544 lua_rawget(_K, -2); // _K: linda key val... KeysDB KeyUD|nil 544 lua_rawget(_K, -2); // _K: linda key val... KeysDB KeyUD|nil
@@ -553,7 +553,7 @@ int keepercall_send(lua_State* const L_)
553 lua_replace(_K, 2); // _K: linda KeyUD val... KeysDB 553 lua_replace(_K, 2); // _K: linda KeyUD val... KeysDB
554 lua_pop(_K, 1); // _K: linda KeyUD val... 554 lua_pop(_K, 1); // _K: linda KeyUD val...
555 STACK_CHECK(_K, 0); 555 STACK_CHECK(_K, 0);
556 KeyUD* const _key{ KeyUD::GetPtr(_K, 2) }; 556 KeyUD* const _key{ KeyUD::GetPtr(_K, StackIndex{ 2 }) };
557 if (_key && _key->push(_K, _n, true)) { // not enough room? 557 if (_key && _key->push(_K, _n, true)) { // not enough room?
558 lua_settop(_K, 0); // _K: 558 lua_settop(_K, 0); // _K:
559 lua_pushboolean(_K, 1); // _K: true 559 lua_pushboolean(_K, 1); // _K: true
@@ -576,11 +576,11 @@ int keepercall_set(lua_State* const L_)
576 STACK_GROW(_K, 6); 576 STACK_GROW(_K, 6);
577 577
578 // retrieve KeysDB associated with the linda 578 // retrieve KeysDB associated with the linda
579 PushKeysDB(_K, 1); // _K: linda key val... KeysDB 579 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB
580 lua_replace(_K, 1); // _K: KeysDB key val... 580 lua_replace(_K, 1); // _K: KeysDB key val...
581 lua_pushvalue(_K, 2); // _K: KeysDB key val... key 581 lua_pushvalue(_K, 2); // _K: KeysDB key val... key
582 lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil 582 lua_rawget(_K, 1); // _K: KeysDB key val KeyUD|nil
583 KeyUD* _key{ KeyUD::GetPtr(_K, -1) }; 583 KeyUD* _key{ KeyUD::GetPtr(_K, kIdxTop) };
584 584
585 if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil 585 if (lua_gettop(_K) == 3) { // no value to set // _K: KeysDB key KeyUD|nil
586 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged! 586 // empty the KeyUD for the specified key: replace uservalue with a virgin table, reset counters, but leave limit unchanged!
@@ -633,11 +633,11 @@ int keepercall_set(lua_State* const L_)
633 * 633 *
634 * Returns: number of return values (pushed to 'L'), unset in case of error 634 * Returns: number of return values (pushed to 'L'), unset in case of error
635 */ 635 */
636KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, int starting_index_) 636KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_)
637{ 637{
638 KeeperCallResult _result; 638 KeeperCallResult _result;
639 int const _args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; // L: ... args... K_: 639 StackIndex const _args{ starting_index_ ? (lua_gettop(L_) - starting_index_ + 1) : 0 }; // L: ... args... K_:
640 int const _top_K{ lua_gettop(K_) }; 640 StackIndex const _top_K{ lua_gettop(K_) };
641 // if we didn't do anything wrong, the keeper stack should be clean 641 // if we didn't do anything wrong, the keeper stack should be clean
642 LUA_ASSERT(L_, _top_K == 0); 642 LUA_ASSERT(L_, _top_K == 0);
643 643
@@ -743,8 +743,8 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
743 InterCopyContext _c{ linda_.U, L_, SourceState{ _K }, {}, {}, {}, LookupMode::FromKeeper, {} }; 743 InterCopyContext _c{ linda_.U, L_, SourceState{ _K }, {}, {}, {}, LookupMode::FromKeeper, {} };
744 lua_pushnil(_K); // _K: KeysDB nil L_: out 744 lua_pushnil(_K); // _K: KeysDB nil L_: out
745 while (lua_next(_K, -2)) { // _K: KeysDB key KeyUD L_: out 745 while (lua_next(_K, -2)) { // _K: KeysDB key KeyUD L_: out
746 KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; 746 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
747 _key->prepareAccess(_K, -1); // _K: KeysDB key fifo L_: out 747 _key->prepareAccess(_K, kIdxTop); // _K: KeysDB key fifo L_: out
748 lua_pushvalue(_K, -2); // _K: KeysDB key fifo key L_: out 748 lua_pushvalue(_K, -2); // _K: KeysDB key fifo key L_: out
749 if (_c.interMove(1) != InterCopyResult::Success) { // _K: KeysDB key fifo L_: out key 749 if (_c.interMove(1) != InterCopyResult::Success) { // _K: KeysDB key fifo L_: out key
750 raise_luaL_error(L_, "Internal error reading Keeper contents"); 750 raise_luaL_error(L_, "Internal error reading Keeper contents");
@@ -928,7 +928,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, int const nbKeepers_, int
928 // copy package.path and package.cpath from the source state 928 // copy package.path and package.cpath from the source state
929 if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: 929 if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K:
930 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately 930 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately
931 InterCopyContext _c{ U, DestState{ _K }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, -1) }, {}, LookupMode::ToKeeper, {} }; 931 InterCopyContext _c{ U, DestState{ _K }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop) }, {}, LookupMode::ToKeeper, {} };
932 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: 932 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K:
933 // if something went wrong, the error message is at the top of the stack 933 // if something went wrong, the error message is at the top of the stack
934 lua_remove(L, -2); // L_: settings error_msg 934 lua_remove(L, -2); // L_: settings error_msg
diff --git a/src/keeper.h b/src/keeper.h
index 04bf834..e505361 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -7,9 +7,9 @@ class Linda;
7enum class LookupMode; 7enum class LookupMode;
8class Universe; 8class Universe;
9 9
10using KeeperState = Unique<lua_State*>; 10DECLARE_UNIQUE_TYPE(KeeperState,lua_State*);
11using LindaLimit = Unique<int>; 11DECLARE_UNIQUE_TYPE(LindaLimit, int);
12using KeeperIndex = Unique<int>; 12DECLARE_UNIQUE_TYPE(KeeperIndex, int);
13 13
14// ################################################################################################# 14// #################################################################################################
15 15
@@ -86,5 +86,5 @@ using keeper_api_t = lua_CFunction;
86[[nodiscard]] int keepercall_send(lua_State* L_); 86[[nodiscard]] int keepercall_send(lua_State* L_);
87[[nodiscard]] int keepercall_set(lua_State* L_); 87[[nodiscard]] int keepercall_set(lua_State* L_);
88 88
89using KeeperCallResult = Unique<std::optional<int>>; 89DECLARE_UNIQUE_TYPE(KeeperCallResult, std::optional<int>);
90[[nodiscard]] KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, int starting_index_); 90[[nodiscard]] KeeperCallResult keeper_call(KeeperState K_, keeper_api_t func_, lua_State* L_, Linda* linda_, StackIndex starting_index_);
diff --git a/src/lane.cpp b/src/lane.cpp
index baba0fa..d4d409f 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -47,7 +47,7 @@ static constexpr UniqueKey kCachedTostring{ 0xAB5EA23BCEA0C35Cull };
47// lane:get_threadname() 47// lane:get_threadname()
48static LUAG_FUNC(get_threadname) 48static LUAG_FUNC(get_threadname)
49{ 49{
50 Lane* const _lane{ ToLane(L_, 1) }; 50 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) };
51 luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments"); 51 luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments");
52 luaG_pushstring(L_, _lane->getDebugName()); 52 luaG_pushstring(L_, _lane->getDebugName());
53 return 1; 53 return 1;
@@ -70,7 +70,7 @@ static LUAG_FUNC(set_finalizer)
70 // Get the current finalizer table (if any), create one if it doesn't exist 70 // Get the current finalizer table (if any), create one if it doesn't exist
71 std::ignore = kFinalizerRegKey.getSubTable(L_, 1, 0); // L_: finalizer {finalisers} 71 std::ignore = kFinalizerRegKey.getSubTable(L_, 1, 0); // L_: finalizer {finalisers}
72 // must cast to int, not lua_Integer, because LuaJIT signature of lua_rawseti is not the same as PUC-Lua. 72 // must cast to int, not lua_Integer, because LuaJIT signature of lua_rawseti is not the same as PUC-Lua.
73 int const _idx{ static_cast<int>(lua_rawlen(L_, -1) + 1) }; 73 int const _idx{ static_cast<int>(lua_rawlen(L_, kIdxTop) + 1) };
74 lua_pushvalue(L_, 1); // L_: finalizer {finalisers} finalizer 74 lua_pushvalue(L_, 1); // L_: finalizer {finalisers} finalizer
75 lua_rawseti(L_, -2, _idx); // L_: finalizer {finalisers} 75 lua_rawseti(L_, -2, _idx); // L_: finalizer {finalisers}
76 // no need to adjust the stack, Lua does this for us 76 // no need to adjust the stack, Lua does this for us
@@ -85,12 +85,12 @@ static LUAG_FUNC(set_finalizer)
85static LUAG_FUNC(lane_threadname) 85static LUAG_FUNC(lane_threadname)
86{ 86{
87 // C s_lane structure is a light userdata upvalue 87 // C s_lane structure is a light userdata upvalue
88 Lane* const _lane{ luaG_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; 88 Lane* const _lane{ luaG_tolightuserdata<Lane>(L_, StackIndex{ lua_upvalueindex(1) }) };
89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state 89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state
90 if (lua_gettop(L_) == 1) { 90 if (lua_gettop(L_) == 1) {
91 lua_settop(L_, 1); 91 lua_settop(L_, 1);
92 STACK_CHECK_START_REL(L_, 0); 92 STACK_CHECK_START_REL(L_, 0);
93 _lane->changeDebugName(-1); 93 _lane->changeDebugName(kIdxTop);
94 STACK_CHECK(L_, 0); 94 STACK_CHECK(L_, 0);
95 return 0; 95 return 0;
96 } else if (lua_gettop(L_) == 0) { 96 } else if (lua_gettop(L_) == 0) {
@@ -113,19 +113,19 @@ static LUAG_FUNC(lane_threadname)
113// 113//
114static LUAG_FUNC(thread_join) 114static LUAG_FUNC(thread_join)
115{ 115{
116 Lane* const _lane{ ToLane(L_, 1) }; 116 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) };
117 117
118 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 118 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
119 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 119 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
120 lua_Duration const duration{ lua_tonumber(L_, 2) }; 120 lua_Duration const duration{ lua_tonumber(L_, 2) };
121 if (duration.count() >= 0.0) { 121 if (duration.count() >= 0.0) {
122 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 122 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
123 } else { 123 } else {
124 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 124 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
125 } 125 }
126 126
127 } else if (!lua_isnoneornil(L_, 2)) { 127 } else if (!lua_isnoneornil(L_, 2)) {
128 raise_luaL_argerror(L_, 2, "incorrect duration type"); 128 raise_luaL_argerror(L_, StackIndex{ 2 }, "incorrect duration type");
129 } 129 }
130 130
131 lua_settop(L_, 1); // L_: lane 131 lua_settop(L_, 1); // L_: lane
@@ -150,7 +150,7 @@ static LUAG_FUNC(thread_join)
150 if (_stored == 0) { 150 if (_stored == 0) {
151 raise_luaL_error(L_, _lane->L ? "First return value must be non-nil when using join()" : "Can't join() more than once or after indexing"); 151 raise_luaL_error(L_, _lane->L ? "First return value must be non-nil when using join()" : "Can't join() more than once or after indexing");
152 } 152 }
153 lua_getiuservalue(L_, 1, 1); // L_: lane {uv} 153 lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv}
154 for (int _i = 2; _i <= _stored; ++_i) { 154 for (int _i = 2; _i <= _stored; ++_i) {
155 lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N 155 lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N
156 } 156 }
@@ -163,7 +163,7 @@ static LUAG_FUNC(thread_join)
163 case Lane::Error: 163 case Lane::Error:
164 { 164 {
165 LUA_ASSERT(L_, _stored == 2 || _stored == 3); 165 LUA_ASSERT(L_, _stored == 2 || _stored == 3);
166 lua_getiuservalue(L_, 1, 1); // L_: lane {uv} 166 lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv}
167 lua_rawgeti(L_, 2, 2); // L_: lane {uv} <error> 167 lua_rawgeti(L_, 2, 2); // L_: lane {uv} <error>
168 lua_rawgeti(L_, 2, 3); // L_: lane {uv} <error> <trace>|nil 168 lua_rawgeti(L_, 2, 3); // L_: lane {uv} <error> <trace>|nil
169 if (lua_isnil(L_, -1)) { 169 if (lua_isnil(L_, -1)) {
@@ -178,11 +178,11 @@ static LUAG_FUNC(thread_join)
178 178
179 case Lane::Cancelled: 179 case Lane::Cancelled:
180 LUA_ASSERT(L_, _stored == 2); 180 LUA_ASSERT(L_, _stored == 2);
181 lua_getiuservalue(L_, 1, 1); // L_: lane {uv} 181 lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane {uv}
182 lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error 182 lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error
183 lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil 183 lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil
184 lua_replace(L_, -3); // L_: lane nil cancel_error 184 lua_replace(L_, -3); // L_: lane nil cancel_error
185 LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, -1)); 185 LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop));
186 _ret = 2; 186 _ret = 2;
187 break; 187 break;
188 188
@@ -199,8 +199,8 @@ static LUAG_FUNC(thread_join)
199 199
200LUAG_FUNC(thread_resume) 200LUAG_FUNC(thread_resume)
201{ 201{
202 static constexpr int kSelf{ 1 }; 202 static constexpr StackIndex kIdxSelf{ 1 };
203 Lane* const _lane{ ToLane(L_, kSelf) }; 203 Lane* const _lane{ ToLane(L_, kIdxSelf) };
204 lua_State* const _L2{ _lane->L }; 204 lua_State* const _L2{ _lane->L };
205 205
206 // wait until the lane yields 206 // wait until the lane yields
@@ -225,7 +225,7 @@ LUAG_FUNC(thread_resume)
225 STACK_CHECK_START_ABS(_L2, _nresults); 225 STACK_CHECK_START_ABS(_L2, _nresults);
226 226
227 // clear any fetched returned values that we might have stored previously 227 // clear any fetched returned values that we might have stored previously
228 _lane->resetResultsStorage(L_, 1); 228 _lane->resetResultsStorage(L_, kIdxSelf);
229 229
230 // to retrieve the yielded value of the coroutine on our stack 230 // to retrieve the yielded value of the coroutine on our stack
231 InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} }; 231 InterCopyContext _cin{ _lane->U, DestState{ L_ }, SourceState{ _L2 }, {}, {}, {}, {}, {} };
@@ -254,9 +254,9 @@ LUAG_FUNC(thread_resume)
254// Else If key is found in the environment, return it 254// Else If key is found in the environment, return it
255static int thread_index_number(lua_State* L_) 255static int thread_index_number(lua_State* L_)
256{ 256{
257 static constexpr int kSelf{ 1 }; 257 static constexpr StackIndex kIdxSelf{ 1 };
258 258
259 Lane* const _lane{ ToLane(L_, kSelf) }; 259 Lane* const _lane{ ToLane(L_, kIdxSelf) };
260 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane n 260 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane n
261 int const _key{ static_cast<int>(lua_tointeger(L_, 2)) }; 261 int const _key{ static_cast<int>(lua_tointeger(L_, 2)) };
262 lua_pop(L_, 1); // L_: lane 262 lua_pop(L_, 1); // L_: lane
@@ -284,13 +284,13 @@ static int thread_index_number(lua_State* L_)
284// Else raise an error 284// Else raise an error
285static int thread_index_string(lua_State* L_) 285static int thread_index_string(lua_State* L_)
286{ 286{
287 static constexpr int kSelf{ 1 }; 287 static constexpr StackIndex kIdxSelf{ 1 };
288 static constexpr int kKey{ 2 }; 288 static constexpr StackIndex kIdxKey{ 2 };
289 289
290 Lane* const _lane{ ToLane(L_, kSelf) }; 290 Lane* const _lane{ ToLane(L_, kIdxSelf) };
291 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane "key" 291 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane "key"
292 292
293 std::string_view const _keystr{ luaG_tostring(L_, kKey) }; 293 std::string_view const _keystr{ luaG_tostring(L_, kIdxKey) };
294 lua_settop(L_, 2); // keep only our original arguments on the stack 294 lua_settop(L_, 2); // keep only our original arguments on the stack
295 if (_keystr == "status") { 295 if (_keystr == "status") {
296 _lane->pushStatusString(L_); // L_: lane "key" "<status>" 296 _lane->pushStatusString(L_); // L_: lane "key" "<status>"
@@ -301,7 +301,7 @@ static int thread_index_string(lua_State* L_)
301 return 1; 301 return 1;
302 } 302 }
303 // return self.metatable[key] 303 // return self.metatable[key]
304 lua_getmetatable(L_, kSelf); // L_: lane "key" mt 304 lua_getmetatable(L_, kIdxSelf); // L_: lane "key" mt
305 lua_replace(L_, -3); // L_: mt "key" 305 lua_replace(L_, -3); // L_: mt "key"
306 lua_rawget(L_, -2); // L_: mt value 306 lua_rawget(L_, -2); // L_: mt value
307 // only "cancel" and "join" are registered as functions, any other string will raise an error 307 // only "cancel" and "join" are registered as functions, any other string will raise an error
@@ -316,9 +316,9 @@ static int thread_index_string(lua_State* L_)
316// lane:__index(key,usr) -> value 316// lane:__index(key,usr) -> value
317static LUAG_FUNC(thread_index) 317static LUAG_FUNC(thread_index)
318{ 318{
319 static constexpr int kSelf{ 1 }; 319 static constexpr StackIndex kIdxSelf{ 1 };
320 static constexpr int kKey{ 2 }; 320 static constexpr StackIndex kKey{ 2 };
321 Lane* const _lane{ ToLane(L_, kSelf) }; 321 Lane* const _lane{ ToLane(L_, kIdxSelf) };
322 LUA_ASSERT(L_, lua_gettop(L_) == 2); 322 LUA_ASSERT(L_, lua_gettop(L_) == 2);
323 323
324 switch (luaG_type(L_, kKey)) { 324 switch (luaG_type(L_, kKey)) {
@@ -329,17 +329,17 @@ static LUAG_FUNC(thread_index)
329 return thread_index_string(L_); // stack modification is undefined, returned value is at the top 329 return thread_index_string(L_); // stack modification is undefined, returned value is at the top
330 330
331 default: // unknown key 331 default: // unknown key
332 lua_getmetatable(L_, kSelf); // L_: mt 332 lua_getmetatable(L_, kIdxSelf); // L_: mt
333 kCachedError.pushKey(L_); // L_: mt kCachedError 333 kCachedError.pushKey(L_); // L_: mt kCachedError
334 lua_rawget(L_, -2); // L_: mt error() 334 lua_rawget(L_, -2); // L_: mt error()
335 if (luaG_type(L_, -1) != LuaType::FUNCTION) { 335 if (luaG_type(L_, kIdxTop) != LuaType::FUNCTION) {
336 raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaG_typename(L_, -1).data()); 336 raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaG_typename(L_, kIdxTop).data());
337 } 337 }
338 luaG_pushstring(L_, "Unknown key: "); // L_: mt error() "Unknown key: " 338 luaG_pushstring(L_, "Unknown key: "); // L_: mt error() "Unknown key: "
339 kCachedTostring.pushKey(L_); // L_: mt error() "Unknown key: " kCachedTostring 339 kCachedTostring.pushKey(L_); // L_: mt error() "Unknown key: " kCachedTostring
340 lua_rawget(L_, -4); // L_: mt error() "Unknown key: " tostring() 340 lua_rawget(L_, -4); // L_: mt error() "Unknown key: " tostring()
341 if (luaG_type(L_, -1) != LuaType::FUNCTION) { 341 if (luaG_type(L_, kIdxTop) != LuaType::FUNCTION) {
342 raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaG_typename(L_, -1).data()); 342 raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaG_typename(L_, kIdxTop).data());
343 } 343 }
344 lua_pushvalue(L_, kKey); // L_: mt error() "Unknown key: " tostring() k 344 lua_pushvalue(L_, kKey); // L_: mt error() "Unknown key: " tostring() k
345 lua_call(L_, 1, 1); // L_: mt error() "Unknown key: " "k" 345 lua_call(L_, 1, 1); // L_: mt error() "Unknown key: " "k"
@@ -417,7 +417,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
417 417
418 // Don't do stack survey for cancelled lanes. 418 // Don't do stack survey for cancelled lanes.
419 // 419 //
420 if (kCancelError.equals(L_, 1)) { 420 if (kCancelError.equals(L_, StackIndex{ 1 })) {
421 return 1; // just pass on 421 return 1; // just pass on
422 } 422 }
423 423
@@ -436,6 +436,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
436 // table of { "sourcefile.lua:<line>", ... } 436 // table of { "sourcefile.lua:<line>", ... }
437 // 437 //
438 lua_newtable(L_); // L_: some_error {} 438 lua_newtable(L_); // L_: some_error {}
439 StackIndex const kIdxTraceTbl{ luaG_absindex(L_, kIdxTop) };
439 440
440 // Best to start from level 1, but in some cases it might be a C function 441 // Best to start from level 1, but in some cases it might be a C function
441 // and we don't get '.currentline' for that. It's okay - just keep level 442 // and we don't get '.currentline' for that. It's okay - just keep level
@@ -446,27 +447,27 @@ int Lane::LuaErrorHandler(lua_State* L_)
446 lua_getinfo(L_, _extended ? "Sln" : "Sl", &_ar); 447 lua_getinfo(L_, _extended ? "Sln" : "Sl", &_ar);
447 if (_extended) { 448 if (_extended) {
448 lua_newtable(L_); // L_: some_error {} {} 449 lua_newtable(L_); // L_: some_error {} {}
449 450 StackIndex const kIdxFrameTbl{ luaG_absindex(L_, kIdxTop) };
450 lua_pushstring(L_, _ar.source); // L_: some_error {} {} source 451 lua_pushstring(L_, _ar.source); // L_: some_error {} {} source
451 luaG_setfield(L_, -2, std::string_view{ "source" }); // L_: some_error {} {} 452 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "source" }); // L_: some_error {} {}
452 453
453 lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline 454 lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline
454 luaG_setfield(L_, -2, std::string_view{ "currentline" }); // L_: some_error {} {} 455 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "currentline" }); // L_: some_error {} {}
455 456
456 lua_pushstring(L_, _ar.name ? _ar.name : "<?>"); // L_: some_error {} {} name 457 lua_pushstring(L_, _ar.name ? _ar.name : "<?>"); // L_: some_error {} {} name
457 luaG_setfield(L_, -2, std::string_view{ "name" }); // L_: some_error {} {} 458 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "name" }); // L_: some_error {} {}
458 459
459 lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat 460 lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat
460 luaG_setfield(L_, -2, std::string_view{ "namewhat" }); // L_: some_error {} {} 461 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "namewhat" }); // L_: some_error {} {}
461 462
462 lua_pushstring(L_, _ar.what); // L_: some_error {} {} what 463 lua_pushstring(L_, _ar.what); // L_: some_error {} {} what
463 luaG_setfield(L_, -2, std::string_view{ "what" }); // L_: some_error {} {} 464 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "what" }); // L_: some_error {} {}
464 } else if (_ar.currentline > 0) { 465 } else if (_ar.currentline > 0) {
465 luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah" 466 luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah"
466 } else { 467 } else {
467 luaG_pushstring(L_, "%s:?", _ar.short_src); // L_: some_error {} "blah" 468 luaG_pushstring(L_, "%s:?", _ar.short_src); // L_: some_error {} "blah"
468 } 469 }
469 lua_rawseti(L_, -2, static_cast<lua_Integer>(_n)); // L_: some_error {} 470 lua_rawseti(L_, kIdxTraceTbl, static_cast<lua_Integer>(_n)); // L_: some_error {}
470 } 471 }
471 472
472 // store the stack trace table in the registry 473 // store the stack trace table in the registry
@@ -480,10 +481,10 @@ int Lane::LuaErrorHandler(lua_State* L_)
480// ########################################## Finalizer ############################################ 481// ########################################## Finalizer ############################################
481// ################################################################################################# 482// #################################################################################################
482 483
483[[nodiscard]] static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const errorTraceLevel_, LuaError const rc_, [[maybe_unused]] int const stk_base_) 484[[nodiscard]] static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const errorTraceLevel_, LuaError const rc_, [[maybe_unused]] StackIndex const stk_base_)
484{ 485{
485 // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry 486 // Lua 5.1 error handler is limited to one return value; it stored the stack trace in the registry
486 int const _top{ lua_gettop(L_) }; 487 StackIndex const _top{ lua_gettop(L_) };
487 switch (rc_) { 488 switch (rc_) {
488 case LuaError::OK: // no error, body return values are on the stack 489 case LuaError::OK: // no error, body return values are on the stack
489 break; 490 break;
@@ -499,7 +500,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
499 500
500 // For cancellation the error message is kCancelError, and a stack trace isn't placed 501 // For cancellation the error message is kCancelError, and a stack trace isn't placed
501 // For other errors, the message can be whatever was thrown, and we should have a stack trace table 502 // For other errors, the message can be whatever was thrown, and we should have a stack trace table
502 LUA_ASSERT(L_, luaG_type(L_, 1 + stk_base_) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE)); 503 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 + stk_base_ }) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE));
503 // Just leaving the stack trace table on the stack is enough to get it through to the master. 504 // Just leaving the stack trace table on the stack is enough to get it through to the master.
504 } else { 505 } else {
505 // any kind of error can be thrown with error(), or through a lane/linda cancellation 506 // any kind of error can be thrown with error(), or through a lane/linda cancellation
@@ -544,7 +545,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
544 545
545 STACK_GROW(_L, 5); 546 STACK_GROW(_L, 5);
546 547
547 int const _finalizers{ lua_gettop(_L) }; 548 StackIndex const _finalizers{ lua_gettop(_L) };
548 // always push something as error handler, to have the same stack structure 549 // always push something as error handler, to have the same stack structure
549 int const _error_handler{ (errorTraceLevel_ != Lane::Minimal) 550 int const _error_handler{ (errorTraceLevel_ != Lane::Minimal)
550 ? (lua_pushcfunction(_L, Lane::LuaErrorHandler), lua_gettop(_L)) 551 ? (lua_pushcfunction(_L, Lane::LuaErrorHandler), lua_gettop(_L))
@@ -581,7 +582,8 @@ int Lane::LuaErrorHandler(lua_State* L_)
581 // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace 582 // if no error from the main body, finalizer doesn't receive any argument, else it gets the error message and optional stack trace
582 _rc = ToLuaError(lua_pcall(_L, _args, 0, _error_handler)); // _L: ... finalizers error_handler() err_msg2? 583 _rc = ToLuaError(lua_pcall(_L, _args, 0, _error_handler)); // _L: ... finalizers error_handler() err_msg2?
583 if (_rc != LuaError::OK) { 584 if (_rc != LuaError::OK) {
584 _finalizer_pushed = 1 + PushStackTrace(_L, errorTraceLevel_, _rc, lua_gettop(_L)); // _L: ... finalizers error_handler() err_msg2? trace 585 StackIndex const _top{ lua_gettop(_L) };
586 _finalizer_pushed = 1 + PushStackTrace(_L, errorTraceLevel_, _rc, _top); // _L: ... finalizers error_handler() err_msg2? trace
585 // If one finalizer fails, don't run the others. Return this 587 // If one finalizer fails, don't run the others. Return this
586 // as the 'real' error, replacing what we could have had (or not) 588 // as the 'real' error, replacing what we could have had (or not)
587 // from the actual code. 589 // from the actual code.
@@ -610,7 +612,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
610 612
611 if (lane_->isCoroutine()) { 613 if (lane_->isCoroutine()) {
612 // only the coroutine thread should remain on the master state when we are done 614 // only the coroutine thread should remain on the master state when we are done
613 LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaG_type(_L, 1) == LuaType::THREAD); 615 LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaG_type(_L, StackIndex{ 1 }) == LuaType::THREAD);
614 } 616 }
615 617
616 return _rc; 618 return _rc;
@@ -670,7 +672,7 @@ static void PrepareLaneHelpers(Lane* const lane_)
670 lua_State* const _L{ lane_->L }; 672 lua_State* const _L{ lane_->L };
671 // Tie "set_finalizer()" to the state 673 // Tie "set_finalizer()" to the state
672 lua_pushcfunction(_L, LG_set_finalizer); 674 lua_pushcfunction(_L, LG_set_finalizer);
673 tools::PopulateFuncLookupTable(_L, -1, "set_finalizer"); 675 tools::PopulateFuncLookupTable(_L, kIdxTop, "set_finalizer");
674 lua_setglobal(_L, "set_finalizer"); 676 lua_setglobal(_L, "set_finalizer");
675 677
676 // Tie "lane_threadname()" to the state 678 // Tie "lane_threadname()" to the state
@@ -681,7 +683,7 @@ static void PrepareLaneHelpers(Lane* const lane_)
681 683
682 // Tie "cancel_test()" to the state 684 // Tie "cancel_test()" to the state
683 lua_pushcfunction(_L, LG_cancel_test); 685 lua_pushcfunction(_L, LG_cancel_test);
684 tools::PopulateFuncLookupTable(_L, -1, "cancel_test"); 686 tools::PopulateFuncLookupTable(_L, kIdxTop, "cancel_test");
685 lua_setglobal(_L, "cancel_test"); 687 lua_setglobal(_L, "cancel_test");
686} 688}
687 689
@@ -752,7 +754,7 @@ static void lane_main(Lane* const lane_)
752 } 754 }
753 755
754 // in case of error and if it exists, fetch stack trace from registry and push it 756 // in case of error and if it exists, fetch stack trace from registry and push it
755 lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, 1); // L: retvals|error [trace] 757 lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, StackIndex{ 1 }); // L: retvals|error [trace]
756 758
757 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : luaG_typename(_L, 1)) << ")" << std::endl); 759 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, 1) ? "cancelled" : luaG_typename(_L, 1)) << ")" << std::endl);
758 // Call finalizers, if the script has set them up. 760 // Call finalizers, if the script has set them up.
@@ -782,7 +784,7 @@ static void lane_main(Lane* const lane_)
782 } 784 }
783 785
784 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them 786 // leave results (1..top) or error message + stack trace (1..2) on the stack - master will copy them
785 Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, 1) ? Lane::Cancelled : Lane::Error }; 787 Lane::Status const _st{ (_rc == LuaError::OK) ? Lane::Done : kCancelError.equals(_L, StackIndex{ 1 }) ? Lane::Cancelled : Lane::Error };
786 // 'doneMutex' protects the -> Done|Error|Cancelled state change, and the Running|Suspended|Resuming state change too 788 // 'doneMutex' protects the -> Done|Error|Cancelled state change, and the Running|Suspended|Resuming state change too
787 std::lock_guard _guard{ lane_->doneMutex }; 789 std::lock_guard _guard{ lane_->doneMutex };
788 lane_->status = _st; 790 lane_->status = _st;
@@ -794,7 +796,7 @@ static void lane_main(Lane* const lane_)
794#if LUA_VERSION_NUM >= 504 796#if LUA_VERSION_NUM >= 504
795static LUAG_FUNC(lane_close) 797static LUAG_FUNC(lane_close)
796{ 798{
797 [[maybe_unused]] Lane* const _lane{ ToLane(L_, 1) }; // L_: lane err|nil 799 [[maybe_unused]] Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane err|nil
798 // drop the error if any 800 // drop the error if any
799 lua_settop(L_, 1); // L_: lane 801 lua_settop(L_, 1); // L_: lane
800 802
@@ -823,10 +825,10 @@ static LUAG_FUNC(lane_close)
823static LUAG_FUNC(lane_gc) 825static LUAG_FUNC(lane_gc)
824{ 826{
825 bool _have_gc_cb{ false }; 827 bool _have_gc_cb{ false };
826 Lane* const _lane{ ToLane(L_, 1) }; // L_: ud 828 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: ud
827 829
828 // if there a gc callback? 830 // if there a gc callback?
829 lua_getiuservalue(L_, 1, 1); // L_: ud uservalue 831 lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: ud uservalue
830 kLaneGC.pushKey(L_); // L_: ud uservalue __gc 832 kLaneGC.pushKey(L_); // L_: ud uservalue __gc
831 lua_rawget(L_, -2); // L_: ud uservalue gc_cb|nil 833 lua_rawget(L_, -2); // L_: ud uservalue gc_cb|nil
832 if (!lua_isnil(L_, -1)) { 834 if (!lua_isnil(L_, -1)) {
@@ -932,7 +934,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono:
932 934
933// ################################################################################################# 935// #################################################################################################
934 936
935[[nodiscard]] CancelResult Lane::cancelHard(std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_) 937[[nodiscard]] CancelResult Lane::cancelHard(std::chrono::time_point<std::chrono::steady_clock> const until_, bool const wakeLane_)
936{ 938{
937 cancelRequest = CancelRequest::Hard; // it's now signaled to stop 939 cancelRequest = CancelRequest::Hard; // it's now signaled to stop
938 // lane_->thread.get_stop_source().request_stop(); 940 // lane_->thread.get_stop_source().request_stop();
@@ -949,7 +951,7 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono:
949 951
950// ################################################################################################# 952// #################################################################################################
951 953
952[[nodiscard]] CancelResult Lane::cancelSoft(std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_) 954[[nodiscard]] CancelResult Lane::cancelSoft(std::chrono::time_point<std::chrono::steady_clock> const until_, bool const wakeLane_)
953{ 955{
954 cancelRequest = CancelRequest::Soft; // it's now signaled to stop 956 cancelRequest = CancelRequest::Soft; // it's now signaled to stop
955 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own 957 // negative timeout: we don't want to truly abort the lane, we just want it to react to cancel_test() on its own
@@ -966,9 +968,9 @@ CancelResult Lane::cancel(CancelOp const op_, int const hookCount_, std::chrono:
966 968
967// ################################################################################################# 969// #################################################################################################
968 970
969void Lane::changeDebugName(int const nameIdx_) 971void Lane::changeDebugName(StackIndex const nameIdx_)
970{ 972{
971 int const _nameIdx{ luaG_absindex(L, nameIdx_) }; 973 StackIndex const _nameIdx{ luaG_absindex(L, nameIdx_) };
972 luaL_checktype(L, _nameIdx, LUA_TSTRING); // L: ... "name" ... 974 luaL_checktype(L, _nameIdx, LUA_TSTRING); // L: ... "name" ...
973 STACK_CHECK_START_REL(L, 0); 975 STACK_CHECK_START_REL(L, 0);
974 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... 976 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global...
@@ -1064,11 +1066,11 @@ void Lane::pushStatusString(lua_State* L_) const
1064 1066
1065void Lane::pushIndexedResult(lua_State* const L_, int const key_) const 1067void Lane::pushIndexedResult(lua_State* const L_, int const key_) const
1066{ 1068{
1067 static constexpr int kSelf{ 1 }; 1069 static constexpr StackIndex kIdxSelf{ 1 };
1068 LUA_ASSERT(L_, ToLane(L_, kSelf) == this); // L_: lane ... 1070 LUA_ASSERT(L_, ToLane(L_, kIdxSelf) == this); // L_: lane ...
1069 STACK_GROW(L_, 3); 1071 STACK_GROW(L_, 3);
1070 1072
1071 lua_getiuservalue(L_, kSelf, 1); // L_: lane ... {uv} 1073 lua_getiuservalue(L_, kIdxSelf, 1); // L_: lane ... {uv}
1072 if (status != Lane::Error) { 1074 if (status != Lane::Error) {
1073 lua_rawgeti(L_, -1, key_); // L_: lane ... {uv} uv[i] 1075 lua_rawgeti(L_, -1, key_); // L_: lane ... {uv} uv[i]
1074 lua_remove(L_, -2); // L_: lane ... uv[i] 1076 lua_remove(L_, -2); // L_: lane ... uv[i]
@@ -1083,7 +1085,7 @@ void Lane::pushIndexedResult(lua_State* const L_, int const key_) const
1083 lua_remove(L_, -2); // L_: lane ... <error> 1085 lua_remove(L_, -2); // L_: lane ... <error>
1084 return; 1086 return;
1085 } 1087 }
1086 lua_getmetatable(L_, kSelf); // L_: lane ... {uv} <error> {mt} 1088 lua_getmetatable(L_, kIdxSelf); // L_: lane ... {uv} <error> {mt}
1087 lua_replace(L_, -3); // L_: lane ... {mt} <error> 1089 lua_replace(L_, -3); // L_: lane ... {mt} <error>
1088 // Note: Lua 5.1 interpreter is not prepared to show 1090 // Note: Lua 5.1 interpreter is not prepared to show
1089 // non-string errors, so we use 'tostring()' here 1091 // non-string errors, so we use 'tostring()' here
@@ -1127,11 +1129,11 @@ void Lane::pushIndexedResult(lua_State* const L_, int const key_) const
1127 1129
1128// replace the current uservalue (a table holding the returned values of the lane body) 1130// replace the current uservalue (a table holding the returned values of the lane body)
1129// by a new empty one, but transfer the gc_cb that is stored in there so that it is not lost 1131// by a new empty one, but transfer the gc_cb that is stored in there so that it is not lost
1130void Lane::resetResultsStorage(lua_State* const L_, int const self_idx_) 1132void Lane::resetResultsStorage(lua_State* const L_, StackIndex const self_idx_)
1131{ 1133{
1132 STACK_GROW(L_, 4); 1134 STACK_GROW(L_, 4);
1133 STACK_CHECK_START_REL(L_, 0); 1135 STACK_CHECK_START_REL(L_, 0);
1134 int const _self_idx{ luaG_absindex(L_, self_idx_) }; 1136 StackIndex const _self_idx{ luaG_absindex(L_, self_idx_) };
1135 LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ... 1137 LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ...
1136 // create the new table 1138 // create the new table
1137 lua_newtable(L_); // L_: ... self ... {} 1139 lua_newtable(L_); // L_: ... self ... {}
@@ -1154,12 +1156,12 @@ void Lane::resetResultsStorage(lua_State* const L_, int const self_idx_)
1154// ################################################################################################# 1156// #################################################################################################
1155 1157
1156// intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed 1158// intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed
1157void Lane::securizeDebugName(lua_State* L_) 1159void Lane::securizeDebugName(lua_State* const L_)
1158{ 1160{
1159 STACK_CHECK_START_REL(L_, 0); 1161 STACK_CHECK_START_REL(L_, 0);
1160 STACK_GROW(L_, 3); 1162 STACK_GROW(L_, 3);
1161 // a Lane's uservalue should be a table 1163 // a Lane's uservalue should be a table
1162 lua_getiuservalue(L_, 1, 1); // L_: lane ... {uv} 1164 lua_getiuservalue(L_, StackIndex{ 1 }, 1); // L_: lane ... {uv}
1163 LUA_ASSERT(L_, lua_istable(L_, -1)); 1165 LUA_ASSERT(L_, lua_istable(L_, -1));
1164 // we don't care about the actual key, so long as it's unique and can't collide with anything. 1166 // we don't care about the actual key, so long as it's unique and can't collide with anything.
1165 lua_newtable(L_); // L_: lane ... {uv} {} 1167 lua_newtable(L_); // L_: lane ... {uv} {}
@@ -1174,7 +1176,7 @@ void Lane::securizeDebugName(lua_State* L_)
1174 1176
1175// ################################################################################################# 1177// #################################################################################################
1176 1178
1177void Lane::startThread(int priority_) 1179void Lane::startThread(int const priority_)
1178{ 1180{
1179 thread = std::thread([this]() { lane_main(this); }); 1181 thread = std::thread([this]() { lane_main(this); });
1180 if (priority_ != kThreadPrioDefault) { 1182 if (priority_ != kThreadPrioDefault) {
@@ -1189,12 +1191,12 @@ void Lane::startThread(int priority_)
1189// t[i] = result #i 1191// t[i] = result #i
1190int Lane::storeResults(lua_State* const L_) 1192int Lane::storeResults(lua_State* const L_)
1191{ 1193{
1192 static constexpr int kSelf{ 1 }; 1194 static constexpr StackIndex kIdxSelf{ 1 };
1193 LUA_ASSERT(L_, ToLane(L_, kSelf) == this); 1195 LUA_ASSERT(L_, ToLane(L_, kIdxSelf) == this);
1194 1196
1195 STACK_CHECK_START_REL(L_, 0); 1197 STACK_CHECK_START_REL(L_, 0);
1196 lua_getiuservalue(L_, kSelf, 1); // L_: lane ... {uv} 1198 lua_getiuservalue(L_, kIdxSelf, 1); // L_: lane ... {uv}
1197 int const _tidx{ lua_gettop(L_) }; 1199 StackIndex const _tidx{ lua_gettop(L_) };
1198 1200
1199 int _stored{}; 1201 int _stored{};
1200 if (nresults == 0) { 1202 if (nresults == 0) {
@@ -1252,7 +1254,7 @@ int Lane::storeResults(lua_State* const L_)
1252 case Lane::Cancelled: 1254 case Lane::Cancelled:
1253 _stored = 2; 1255 _stored = 2;
1254 // we should have a single value, kCancelError, in the stack of L 1256 // we should have a single value, kCancelError, in the stack of L
1255 LUA_ASSERT(L_, nresults == 1 && lua_gettop(L) == 1 && kCancelError.equals(L, 1)); 1257 LUA_ASSERT(L_, nresults == 1 && lua_gettop(L) == 1 && kCancelError.equals(L, StackIndex{ 1 }));
1256 // store nil, cancel_error in the results 1258 // store nil, cancel_error in the results
1257 lua_pushnil(L_); // L_: lane ... {uv} nil 1259 lua_pushnil(L_); // L_: lane ... {uv} nil
1258 lua_rawseti(L_, _tidx, 1); // L_: lane ... {uv} 1260 lua_rawseti(L_, _tidx, 1); // L_: lane ... {uv}
diff --git a/src/lane.h b/src/lane.h
index 85994a0..388ac71 100644
--- a/src/lane.h
+++ b/src/lane.h
@@ -146,7 +146,7 @@ class Lane
146 public: 146 public:
147 147
148 CancelResult cancel(CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_); 148 CancelResult cancel(CancelOp op_, int hookCount_, std::chrono::time_point<std::chrono::steady_clock> until_, bool wakeLane_);
149 void changeDebugName(int const nameIdx_); 149 void changeDebugName(StackIndex nameIdx_);
150 void closeState() 150 void closeState()
151 { 151 {
152 lua_State* _L{ S }; 152 lua_State* _L{ S };
@@ -173,7 +173,7 @@ class Lane
173 static void PushMetatable(lua_State* L_); 173 static void PushMetatable(lua_State* L_);
174 void pushStatusString(lua_State* L_) const; 174 void pushStatusString(lua_State* L_) const;
175 void pushIndexedResult(lua_State* L_, int key_) const; 175 void pushIndexedResult(lua_State* L_, int key_) const;
176 void resetResultsStorage(lua_State* const L_, int gc_cb_idx_); 176 void resetResultsStorage(lua_State* L_, StackIndex self_idx_);
177 void selfdestructAdd(); 177 void selfdestructAdd();
178 [[nodiscard]] bool selfdestructRemove(); 178 [[nodiscard]] bool selfdestructRemove();
179 void securizeDebugName(lua_State* L_); 179 void securizeDebugName(lua_State* L_);
@@ -190,7 +190,7 @@ class Lane
190// 'Lane' are malloc/free'd and the handle only carries a pointer. 190// 'Lane' are malloc/free'd and the handle only carries a pointer.
191// This is not deep userdata since the handle is not portable among lanes. 191// This is not deep userdata since the handle is not portable among lanes.
192// 192//
193[[nodiscard]] inline Lane* ToLane(lua_State* L_, int i_) 193[[nodiscard]] inline Lane* ToLane(lua_State* const L_, StackIndex const i_)
194{ 194{
195 return *(static_cast<Lane**>(luaL_checkudata(L_, i_, kLaneMetatableName))); 195 return *(static_cast<Lane**>(luaL_checkudata(L_, i_, kLaneMetatableName)));
196} 196}
diff --git a/src/lanes.cpp b/src/lanes.cpp
index c820568..3aef572 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -169,12 +169,12 @@ LUAG_FUNC(sleep)
169 lua_pushcfunction(L_, LG_linda_receive); // L_: duration|nil receive() 169 lua_pushcfunction(L_, LG_linda_receive); // L_: duration|nil receive()
170 STACK_CHECK_START_REL(L_, 0); // we pushed the function we intend to call, now prepare the arguments 170 STACK_CHECK_START_REL(L_, 0); // we pushed the function we intend to call, now prepare the arguments
171 _U->timerLinda->push(L_); // L_: duration|nil receive() timerLinda 171 _U->timerLinda->push(L_); // L_: duration|nil receive() timerLinda
172 if (luaG_tostring(L_, 1) == "indefinitely") { 172 if (luaG_tostring(L_, StackIndex{ 1 }) == "indefinitely") {
173 lua_pushnil(L_); // L_: duration? receive() timerLinda nil 173 lua_pushnil(L_); // L_: duration? receive() timerLinda nil
174 } else if (lua_isnoneornil(L_, 1)) { 174 } else if (lua_isnoneornil(L_, 1)) {
175 lua_pushnumber(L_, 0); // L_: duration? receive() timerLinda 0 175 lua_pushnumber(L_, 0); // L_: duration? receive() timerLinda 0
176 } else if (!lua_isnumber(L_, 1)) { 176 } else if (!lua_isnumber(L_, 1)) {
177 raise_luaL_argerror(L_, 1, "invalid duration"); 177 raise_luaL_argerror(L_, StackIndex{ 1 }, "invalid duration");
178 } 178 }
179 else { 179 else {
180 lua_pushnumber(L_, lua_tonumber(L_, 1)); // L_: duration? receive() timerLinda duration 180 lua_pushnumber(L_, lua_tonumber(L_, 1)); // L_: duration? receive() timerLinda duration
@@ -193,7 +193,7 @@ LUAG_FUNC(sleep)
193// upvalue[1]: _G.require 193// upvalue[1]: _G.require
194LUAG_FUNC(require) 194LUAG_FUNC(require)
195{ 195{
196 std::string_view const _name{ luaG_tostring(L_, 1) }; // L_: "name" ... 196 std::string_view const _name{ luaG_tostring(L_, StackIndex{ 1 }) }; // L_: "name" ...
197 int const _nargs{ lua_gettop(L_) }; 197 int const _nargs{ lua_gettop(L_) };
198 DEBUGSPEW_CODE(Universe * _U{ Universe::Get(L_) }); 198 DEBUGSPEW_CODE(Universe * _U{ Universe::Get(L_) });
199 STACK_CHECK_START_REL(L_, 0); 199 STACK_CHECK_START_REL(L_, 0);
@@ -202,7 +202,7 @@ LUAG_FUNC(require)
202 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: "name" ... require 202 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: "name" ... require
203 lua_insert(L_, 1); // L_: require "name" ... 203 lua_insert(L_, 1); // L_: require "name" ...
204 lua_call(L_, _nargs, 1); // L_: module 204 lua_call(L_, _nargs, 1); // L_: module
205 tools::PopulateFuncLookupTable(L_, -1, _name); 205 tools::PopulateFuncLookupTable(L_, kIdxTop, _name);
206 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.require '" << _name << "' END" << std::endl); 206 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.require '" << _name << "' END" << std::endl);
207 STACK_CHECK(L_, 0); 207 STACK_CHECK(L_, 0);
208 return 1; 208 return 1;
@@ -215,8 +215,8 @@ LUAG_FUNC(require)
215// lanes.register( "modname", module) 215// lanes.register( "modname", module)
216LUAG_FUNC(register) 216LUAG_FUNC(register)
217{ 217{
218 std::string_view const _name{ luaG_checkstring(L_, 1) }; 218 std::string_view const _name{ luaG_checkstring(L_, StackIndex{ 1 }) };
219 LuaType const _mod_type{ luaG_type(L_, 2) }; 219 LuaType const _mod_type{ luaG_type(L_, StackIndex{ 2 }) };
220 // ignore extra arguments, just in case 220 // ignore extra arguments, just in case
221 lua_settop(L_, 2); 221 lua_settop(L_, 2);
222 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type"); 222 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type");
@@ -224,7 +224,7 @@ LUAG_FUNC(register)
224 STACK_CHECK_START_REL(L_, 0); // "name" mod_table 224 STACK_CHECK_START_REL(L_, 0); // "name" mod_table
225 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' BEGIN" << std::endl); 225 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' BEGIN" << std::endl);
226 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 226 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
227 tools::PopulateFuncLookupTable(L_, -1, _name); 227 tools::PopulateFuncLookupTable(L_, kIdxTop, _name);
228 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' END" << std::endl); 228 DEBUGSPEW_CODE(DebugSpew(_U) << "lanes.register '" << _name << "' END" << std::endl);
229 STACK_CHECK(L_, 0); 229 STACK_CHECK(L_, 0);
230 return 0; 230 return 0;
@@ -249,17 +249,17 @@ LUAG_FUNC(register)
249// 249//
250LUAG_FUNC(lane_new) 250LUAG_FUNC(lane_new)
251{ 251{
252 static constexpr int kFuncIdx{ 1 }; 252 static constexpr StackIndex kFuncIdx{ 1 };
253 static constexpr int kLibsIdx{ 2 }; 253 static constexpr StackIndex kLibsIdx{ 2 };
254 static constexpr int kPrioIdx{ 3 }; 254 static constexpr StackIndex kPrioIdx{ 3 };
255 static constexpr int kGlobIdx{ 4 }; 255 static constexpr StackIndex kGlobIdx{ 4 };
256 static constexpr int kPackIdx{ 5 }; 256 static constexpr StackIndex kPackIdx{ 5 };
257 static constexpr int kRequIdx{ 6 }; 257 static constexpr StackIndex kRequIdx{ 6 };
258 static constexpr int kGcCbIdx{ 7 }; 258 static constexpr StackIndex kGcCbIdx{ 7 };
259 static constexpr int kNameIdx{ 8 }; 259 static constexpr StackIndex kNameIdx{ 8 };
260 static constexpr int kErTlIdx{ 9 }; 260 static constexpr StackIndex kErTlIdx{ 9 };
261 static constexpr int kAsCoro{ 10 }; 261 static constexpr StackIndex kAsCoro{ 10 };
262 static constexpr int kFixedArgsIdx{ 10 }; 262 static constexpr StackIndex kFixedArgsIdx{ 10 };
263 263
264 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx }; 264 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx };
265 LUA_ASSERT(L_, _nargs >= 0); 265 LUA_ASSERT(L_, _nargs >= 0);
@@ -342,7 +342,7 @@ LUAG_FUNC(lane_new)
342 lua_newtable(L); // L: ... lane {uv} 342 lua_newtable(L); // L: ... lane {uv}
343 343
344 // Store the gc_cb callback in the uservalue 344 // Store the gc_cb callback in the uservalue
345 int const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? 0 : kGcCbIdx }; 345 StackIndex const _gc_cb_idx{ lua_isnoneornil(L, kGcCbIdx) ? 0 : kGcCbIdx };
346 if (_gc_cb_idx > 0) { 346 if (_gc_cb_idx > 0) {
347 kLaneGC.pushKey(L); // L: ... lane {uv} k 347 kLaneGC.pushKey(L); // L: ... lane {uv} k
348 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb 348 lua_pushvalue(L, _gc_cb_idx); // L: ... lane {uv} k gc_cb
@@ -350,11 +350,11 @@ LUAG_FUNC(lane_new)
350 } 350 }
351 STACK_CHECK(L, 2); 351 STACK_CHECK(L, 2);
352 // store the uservalue in the Lane full userdata 352 // store the uservalue in the Lane full userdata
353 lua_setiuservalue(L, -2, 1); // L: ... lane 353 lua_setiuservalue(L, StackIndex{ -2 }, 1); // L: ... lane
354 354
355 lua_State* const _L2{ lane->L }; 355 lua_State* const _L2{ lane->L };
356 STACK_CHECK_START_REL(_L2, 0); 356 STACK_CHECK_START_REL(_L2, 0);
357 int const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx }; 357 StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? 0 : kNameIdx };
358 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} }; 358 std::string_view const _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} };
359 if (!_debugName.empty()) 359 if (!_debugName.empty())
360 { 360 {
@@ -366,7 +366,7 @@ LUAG_FUNC(lane_new)
366 lua_getinfo(L, ">S", &_ar); // L: ... lane 366 lua_getinfo(L, ">S", &_ar); // L: ... lane
367 luaG_pushstring(_L2, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane L2: "<name>" 367 luaG_pushstring(_L2, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane L2: "<name>"
368 } 368 }
369 lane->changeDebugName(-1); 369 lane->changeDebugName(kIdxTop);
370 lua_pop(_L2, 1); // L: ... lane L2: 370 lua_pop(_L2, 1); // L: ... lane L2:
371 } 371 }
372 STACK_CHECK(_L2, 0); 372 STACK_CHECK(_L2, 0);
@@ -412,7 +412,7 @@ LUAG_FUNC(lane_new)
412 STACK_CHECK_START_REL(L_, 0); 412 STACK_CHECK_START_REL(L_, 0);
413 413
414 // package 414 // package
415 int const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx }; 415 StackIndex const _package_idx{ lua_isnoneornil(L_, kPackIdx) ? 0 : kPackIdx };
416 if (_package_idx != 0) { 416 if (_package_idx != 0) {
417 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl); 417 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: update 'package'" << std::endl);
418 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack 418 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack
@@ -424,7 +424,7 @@ LUAG_FUNC(lane_new)
424 STACK_CHECK(_L2, 0); 424 STACK_CHECK(_L2, 0);
425 425
426 // modules to require in the target lane *before* the function is transfered! 426 // modules to require in the target lane *before* the function is transfered!
427 int const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx }; 427 StackIndex const _required_idx{ lua_isnoneornil(L_, kRequIdx) ? 0 : kRequIdx };
428 if (_required_idx != 0) { 428 if (_required_idx != 0) {
429 int _nbRequired{ 1 }; 429 int _nbRequired{ 1 };
430 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl); 430 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl);
@@ -436,11 +436,11 @@ LUAG_FUNC(lane_new)
436 436
437 lua_pushnil(L_); // L_: [fixed] args... nil L2: 437 lua_pushnil(L_); // L_: [fixed] args... nil L2:
438 while (lua_next(L_, _required_idx) != 0) { // L_: [fixed] args... n "modname" L2: 438 while (lua_next(L_, _required_idx) != 0) { // L_: [fixed] args... n "modname" L2:
439 if (luaG_type(L_, -1) != LuaType::STRING || luaG_type(L_, -2) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) { 439 if (luaG_type(L_, kIdxTop) != LuaType::STRING || luaG_type(L_, StackIndex{ -2 }) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) {
440 raise_luaL_error(L_, "required module list should be a list of strings"); 440 raise_luaL_error(L_, "required module list should be a list of strings");
441 } else { 441 } else {
442 // require the module in the target state, and populate the lookup table there too 442 // require the module in the target state, and populate the lookup table there too
443 std::string_view const _name{ luaG_tostring(L_, -1) }; 443 std::string_view const _name{ luaG_tostring(L_, kIdxTop) };
444 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl); 444 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl);
445 445
446 // require the module in the target lane 446 // require the module in the target lane
@@ -459,7 +459,7 @@ LUAG_FUNC(lane_new)
459 } 459 }
460 // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret 460 // here the module was successfully required // L_: [fixed] args... n "modname" L2: ret
461 // after requiring the module, register the functions it exported in our name<->function database 461 // after requiring the module, register the functions it exported in our name<->function database
462 tools::PopulateFuncLookupTable(_L2, -1, _name); 462 tools::PopulateFuncLookupTable(_L2, kIdxTop, _name);
463 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: 463 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2:
464 } 464 }
465 } 465 }
@@ -473,7 +473,7 @@ LUAG_FUNC(lane_new)
473 // Appending the specified globals to the global environment 473 // Appending the specified globals to the global environment
474 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... 474 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
475 // 475 //
476 int const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx }; 476 StackIndex const _globals_idx{ lua_isnoneornil(L_, kGlobIdx) ? 0 : kGlobIdx };
477 if (_globals_idx != 0) { 477 if (_globals_idx != 0) {
478 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl); 478 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer globals" << std::endl);
479 if (!lua_istable(L_, _globals_idx)) { 479 if (!lua_istable(L_, _globals_idx)) {
@@ -603,7 +603,7 @@ LUAG_FUNC(wakeup_conv)
603 603
604 STACK_CHECK_START_REL(L_, 0); 604 STACK_CHECK_START_REL(L_, 0);
605 auto _readInteger = [L = L_](std::string_view const& name_) { 605 auto _readInteger = [L = L_](std::string_view const& name_) {
606 std::ignore = luaG_getfield(L, 1, name_); 606 std::ignore = luaG_getfield(L, StackIndex{ 1 }, name_);
607 lua_Integer const val{ lua_tointeger(L, -1) }; 607 lua_Integer const val{ lua_tointeger(L, -1) };
608 lua_pop(L, 1); 608 lua_pop(L, 1);
609 return static_cast<int>(val); 609 return static_cast<int>(val);
@@ -619,7 +619,7 @@ LUAG_FUNC(wakeup_conv)
619 // If Lua table has '.isdst' we trust that. If it does not, we'll let 619 // If Lua table has '.isdst' we trust that. If it does not, we'll let
620 // 'mktime' decide on whether the time is within DST or not (value -1). 620 // 'mktime' decide on whether the time is within DST or not (value -1).
621 // 621 //
622 int const _isdst{ (luaG_getfield(L_, 1, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 }; 622 int const _isdst{ (luaG_getfield(L_, StackIndex{ 1 }, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 };
623 lua_pop(L_, 1); 623 lua_pop(L_, 1);
624 STACK_CHECK(L_, 0); 624 STACK_CHECK(L_, 0);
625 625
@@ -682,8 +682,8 @@ LUAG_FUNC(configure)
682 682
683 Universe* _U{ Universe::Get(L_) }; 683 Universe* _U{ Universe::Get(L_) };
684 bool const _from_master_state{ _U == nullptr }; 684 bool const _from_master_state{ _U == nullptr };
685 std::string_view const _name{ luaG_checkstring(L_, lua_upvalueindex(1)) }; 685 std::string_view const _name{ luaG_checkstring(L_, StackIndex{ lua_upvalueindex(1) }) };
686 LUA_ASSERT(L_, luaG_type(L_, 1) == LuaType::TABLE); 686 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 }) == LuaType::TABLE);
687 687
688 STACK_GROW(L_, 4); 688 STACK_GROW(L_, 4);
689 STACK_CHECK_START_ABS(L_, 1); // L_: settings 689 STACK_CHECK_START_ABS(L_, 1); // L_: settings
@@ -759,7 +759,7 @@ LUAG_FUNC(configure)
759 // register all native functions found in that module in the transferable functions database 759 // register all native functions found in that module in the transferable functions database
760 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names) 760 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
761 // for example in package.loaded["lanes.core"].* 761 // for example in package.loaded["lanes.core"].*
762 tools::PopulateFuncLookupTable(L_, -1, _name); 762 tools::PopulateFuncLookupTable(L_, kIdxTop, _name);
763 STACK_CHECK(L_, 2); 763 STACK_CHECK(L_, 2);
764 764
765 // record all existing C/JIT-fast functions 765 // record all existing C/JIT-fast functions
@@ -769,7 +769,7 @@ LUAG_FUNC(configure)
769 // because we will do it after on_state_create() is called, 769 // because we will do it after on_state_create() is called,
770 // and we don't want to skip _G because of caching in case globals are created then 770 // and we don't want to skip _G because of caching in case globals are created then
771 luaG_pushglobaltable(L_); // L_: settings M _G 771 luaG_pushglobaltable(L_); // L_: settings M _G
772 tools::PopulateFuncLookupTable(L_, -1, {}); 772 tools::PopulateFuncLookupTable(L_, kIdxTop, {});
773 lua_pop(L_, 1); // L_: settings M 773 lua_pop(L_, 1); // L_: settings M
774 } 774 }
775 lua_pop(L_, 1); // L_: settings 775 lua_pop(L_, 1); // L_: settings
diff --git a/src/linda.cpp b/src/linda.cpp
index 3f5fd33..bd40f5e 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -280,7 +280,7 @@ void Linda::setName(std::string_view const& name_)
280LUAG_FUNC(linda_cancel) 280LUAG_FUNC(linda_cancel)
281{ 281{
282 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; 282 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
283 std::string_view const _who{ luaG_optstring(L_, 2, "both") }; 283 std::string_view const _who{ luaG_optstring(L_, StackIndex{ 2 }, "both") };
284 // make sure we got 2 arguments: the linda and the cancellation mode 284 // make sure we got 2 arguments: the linda and the cancellation mode
285 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); 285 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments");
286 286
@@ -371,7 +371,7 @@ LUAG_FUNC(linda_count)
371 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ lua_gettop(L_) }); 371 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ lua_gettop(L_) });
372 372
373 Keeper* const _keeper{ _linda->whichKeeper() }; 373 Keeper* const _keeper{ _linda->whichKeeper() };
374 KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, 2) }; 374 KeeperCallResult const _pushed{ keeper_call(_keeper->K, KEEPER_API(count), L_, _linda, StackIndex{ 2 }) };
375 return OptionalValue(_pushed, L_, "tried to count an invalid key"); 375 return OptionalValue(_pushed, L_, "tried to count an invalid key");
376 } 376 }
377 }; 377 };
@@ -435,7 +435,7 @@ LUAG_FUNC(linda_get)
435 KeeperCallResult _pushed; 435 KeeperCallResult _pushed;
436 if (_linda->cancelRequest == CancelRequest::None) { 436 if (_linda->cancelRequest == CancelRequest::None) {
437 Keeper* const _keeper{ _linda->whichKeeper() }; 437 Keeper* const _keeper{ _linda->whichKeeper() };
438 _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, 2); 438 _pushed = keeper_call(_keeper->K, KEEPER_API(get), L_, _linda, StackIndex{ 2 });
439 } else { // linda is cancelled 439 } else { // linda is cancelled
440 // do nothing and return nil,lanes.cancel_error 440 // do nothing and return nil,lanes.cancel_error
441 lua_pushnil(L_); 441 lua_pushnil(L_);
@@ -468,10 +468,10 @@ LUAG_FUNC(linda_limit)
468 int const _nargs{ lua_gettop(L_) }; 468 int const _nargs{ lua_gettop(L_) };
469 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); 469 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments");
470 // make sure we got a numeric limit, or "unlimited", (or nothing) 470 // make sure we got a numeric limit, or "unlimited", (or nothing)
471 bool const _unlimited{ luaG_tostring(L_, 3) == "unlimited" }; 471 bool const _unlimited{ luaG_tostring(L_, StackIndex{ 3 }) == "unlimited" };
472 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : LindaLimit{ static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) } }; 472 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : LindaLimit{ static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) } };
473 if (_val < 0) { 473 if (_val < 0) {
474 raise_luaL_argerror(L_, 3, "limit must be >= 0"); 474 raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0");
475 } 475 }
476 // make sure the key is of a valid type 476 // make sure the key is of a valid type
477 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 }); 477 CheckKeyTypes(L_, StackIndex{ 2 }, StackIndex{ 2 });
@@ -479,23 +479,23 @@ LUAG_FUNC(linda_limit)
479 KeeperCallResult _pushed; 479 KeeperCallResult _pushed;
480 if (_linda->cancelRequest == CancelRequest::None) { 480 if (_linda->cancelRequest == CancelRequest::None) {
481 if (_unlimited) { 481 if (_unlimited) {
482 LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, 3) == "unlimited"); 482 LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, StackIndex{ 3 }) == "unlimited");
483 // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) 483 // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!)
484 lua_pop(L_, 1); // L_: linda key 484 lua_pop(L_, 1); // L_: linda key
485 lua_pushinteger(L_, -1); // L_: linda key nil 485 lua_pushinteger(L_, -1); // L_: linda key nil
486 } 486 }
487 Keeper* const _keeper{ _linda->whichKeeper() }; 487 Keeper* const _keeper{ _linda->whichKeeper() };
488 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, 2); 488 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 });
489 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, -1) == LuaType::STRING); 489 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, kIdxTop) == LuaType::STRING);
490 if (_nargs == 3) { // 3 args: setting the limit 490 if (_nargs == 3) { // 3 args: setting the limit
491 // changing the limit: no error, boolean value saying if we should wake blocked writer threads 491 // changing the limit: no error, boolean value saying if we should wake blocked writer threads
492 LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::BOOLEAN); // L_: bool string 492 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); // L_: bool string
493 if (lua_toboolean(L_, -2)) { 493 if (lua_toboolean(L_, -2)) {
494 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area 494 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
495 } 495 }
496 } else { // 2 args: reading the limit 496 } else { // 2 args: reading the limit
497 // reading the limit: a number >=0 or "unlimited" 497 // reading the limit: a number >=0 or "unlimited"
498 LUA_ASSERT(L_, luaG_type(L_, -2) == LuaType::NUMBER || luaG_tostring(L_, -2) == "unlimited"); 498 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::NUMBER || luaG_tostring(L_, StackIndex{ -2 }) == "unlimited");
499 } 499 }
500 } else { // linda is cancelled 500 } else { // linda is cancelled
501 // do nothing and return nil,lanes.cancel_error 501 // do nothing and return nil,lanes.cancel_error
@@ -530,12 +530,12 @@ LUAG_FUNC(linda_receive)
530 StackIndex _key_i{ 2 }; // index of first key, if timeout not there 530 StackIndex _key_i{ 2 }; // index of first key, if timeout not there
531 531
532 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 532 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
533 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 533 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
534 lua_Duration const _duration{ lua_tonumber(L_, 2) }; 534 lua_Duration const _duration{ lua_tonumber(L_, 2) };
535 if (_duration.count() >= 0.0) { 535 if (_duration.count() >= 0.0) {
536 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration); 536 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
537 } else { 537 } else {
538 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 538 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
539 } 539 }
540 ++_key_i; 540 ++_key_i;
541 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key 541 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
@@ -555,14 +555,14 @@ LUAG_FUNC(linda_receive)
555 // we expect a user-defined amount of return value 555 // we expect a user-defined amount of return value
556 _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1); 556 _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1);
557 if (_expected_pushed_min < 1) { 557 if (_expected_pushed_min < 1) {
558 raise_luaL_argerror(L_, _key_i + 1, "bad min count"); 558 raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count");
559 } 559 }
560 _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min); 560 _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min);
561 // don't forget to count the key in addition to the values 561 // don't forget to count the key in addition to the values
562 ++_expected_pushed_min; 562 ++_expected_pushed_min;
563 ++_expected_pushed_max; 563 ++_expected_pushed_max;
564 if (_expected_pushed_min > _expected_pushed_max) { 564 if (_expected_pushed_min > _expected_pushed_max) {
565 raise_luaL_argerror(L_, _key_i + 2, "batched min/max error"); 565 raise_luaL_argerror(L_, StackIndex{ _key_i + 2 }, "batched min/max error");
566 } 566 }
567 } else { 567 } else {
568 // make sure the keys are of a valid type 568 // make sure the keys are of a valid type
@@ -686,12 +686,12 @@ LUAG_FUNC(linda_send)
686 StackIndex _key_i{ 2 }; // index of first key, if timeout not there 686 StackIndex _key_i{ 2 }; // index of first key, if timeout not there
687 687
688 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 688 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
689 if (luaG_type(L_, 2) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 689 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
690 lua_Duration const _duration{ lua_tonumber(L_, 2) }; 690 lua_Duration const _duration{ lua_tonumber(L_, 2) };
691 if (_duration.count() >= 0.0) { 691 if (_duration.count() >= 0.0) {
692 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration); 692 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
693 } else { 693 } else {
694 raise_luaL_argerror(L_, 2, "duration cannot be < 0"); 694 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
695 } 695 }
696 ++_key_i; 696 ++_key_i;
697 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key 697 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the key
@@ -828,9 +828,9 @@ LUAG_FUNC(linda_set)
828 KeeperCallResult _pushed; 828 KeeperCallResult _pushed;
829 if (_linda->cancelRequest == CancelRequest::None) { 829 if (_linda->cancelRequest == CancelRequest::None) {
830 Keeper* const _keeper{ _linda->whichKeeper() }; 830 Keeper* const _keeper{ _linda->whichKeeper() };
831 _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, 2); 831 _pushed = keeper_call(_keeper->K, KEEPER_API(set), L_, _linda, StackIndex{ 2 });
832 if (_pushed.has_value()) { // no error? 832 if (_pushed.has_value()) { // no error?
833 LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, -1) == LuaType::STRING && luaG_type(L_, -2) == LuaType::BOOLEAN); 833 LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, kIdxTop) == LuaType::STRING && luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN);
834 834
835 if (_has_data) { 835 if (_has_data) {
836 // we put some data in the slot, tell readers that they should wake 836 // we put some data in the slot, tell readers that they should wake
@@ -922,13 +922,13 @@ namespace {
922 */ 922 */
923LUAG_FUNC(linda) 923LUAG_FUNC(linda)
924{ 924{
925 static constexpr int kLastArg{ LUA_VERSION_NUM >= 504 ? 3 : 2}; 925 static constexpr StackIndex kLastArg{ LUA_VERSION_NUM >= 504 ? 3 : 2 };
926 int const _top{ lua_gettop(L_) }; 926 StackIndex const _top{ lua_gettop(L_) };
927 luaL_argcheck(L_, _top <= kLastArg, _top, "too many arguments"); 927 luaL_argcheck(L_, _top <= kLastArg, _top, "too many arguments");
928 int _closeHandlerIdx{}; 928 StackIndex _closeHandlerIdx{};
929 int _nameIdx{}; 929 StackIndex _nameIdx{};
930 int _groupIdx{}; 930 StackIndex _groupIdx{};
931 for (int const _i : std::ranges::iota_view{ 1, _top + 1 }) { 931 for (StackIndex const _i : std::ranges::iota_view{ StackIndex{ 1 }, StackIndex{ _top + 1 }}) {
932 switch (luaG_type(L_, _i)) { 932 switch (luaG_type(L_, _i)) {
933#if LUA_VERSION_NUM >= 504 // to-be-closed support starts with Lua 5.4 933#if LUA_VERSION_NUM >= 504 // to-be-closed support starts with Lua 5.4
934 case LuaType::FUNCTION: 934 case LuaType::FUNCTION:
@@ -985,11 +985,11 @@ LUAG_FUNC(linda)
985 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, _nuv); // L_: name group close_handler linda 985 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, _nuv); // L_: name group close_handler linda
986 if (_closeHandlerIdx != 0) { 986 if (_closeHandlerIdx != 0) {
987 lua_replace(L_, 2); // L_: name linda close_handler 987 lua_replace(L_, 2); // L_: name linda close_handler
988 lua_setiuservalue(L_, 2, 1); // L_: name linda 988 lua_setiuservalue(L_, StackIndex{ 2 }, 1); // L_: name linda
989 } 989 }
990 // depending on whether we have a handler or not, the stack is not in the same state at this point 990 // depending on whether we have a handler or not, the stack is not in the same state at this point
991 // just make sure we have our Linda at the top 991 // just make sure we have our Linda at the top
992 LUA_ASSERT(L_, ToLinda<true>(L_, StackIndex{ -1 })); 992 LUA_ASSERT(L_, ToLinda<true>(L_, kIdxTop));
993 return 1; 993 return 1;
994 } else { // no to-be-closed support 994 } else { // no to-be-closed support
995 // ensure we have name, group in that order on the stack 995 // ensure we have name, group in that order on the stack
diff --git a/src/linda.h b/src/linda.h
index 4551443..ea660d9 100644
--- a/src/linda.h
+++ b/src/linda.h
@@ -13,7 +13,7 @@ static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched"
13 13
14// ################################################################################################# 14// #################################################################################################
15 15
16using LindaGroup = Unique<int>; 16DECLARE_UNIQUE_TYPE(LindaGroup, int);
17 17
18class Linda 18class Linda
19: public DeepPrelude // Deep userdata MUST start with this header 19: public DeepPrelude // Deep userdata MUST start with this header
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp
index d5ebc9b..e5903fb 100644
--- a/src/lindafactory.cpp
+++ b/src/lindafactory.cpp
@@ -80,7 +80,7 @@ void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) cons
80 Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper }; 80 Keeper* const _keeper{ _need_acquire_release ? _linda->acquireKeeper() : _myKeeper };
81 LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same 81 LUA_ASSERT(L_, _keeper == _myKeeper); // should always be the same
82 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex... 82 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
83 [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, 0) }; 83 [[maybe_unused]] KeeperCallResult const result{ keeper_call(_keeper->K, KEEPER_API(destruct), L_, _linda, StackIndex{ 0 }) };
84 LUA_ASSERT(L_, result.has_value() && result.value() == 0); 84 LUA_ASSERT(L_, result.has_value() && result.value() == 0);
85 if (_need_acquire_release) { 85 if (_need_acquire_release) {
86 _linda->releaseKeeper(_keeper); 86 _linda->releaseKeeper(_keeper);
@@ -105,7 +105,7 @@ std::string_view LindaFactory::moduleName() const
105DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const 105DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const
106{ 106{
107 // we always expect name and group at the bottom of the stack (either can be nil). any extra stuff we ignore and keep unmodified 107 // we always expect name and group at the bottom of the stack (either can be nil). any extra stuff we ignore and keep unmodified
108 std::string_view _linda_name{ luaG_tostring(L_, 1) }; 108 std::string_view _linda_name{ luaG_tostring(L_, StackIndex{ 1 }) };
109 LindaGroup _linda_group{ static_cast<int>(lua_tointeger(L_, 2)) }; 109 LindaGroup _linda_group{ static_cast<int>(lua_tointeger(L_, 2)) };
110 110
111 // store in the linda the location of the script that created it 111 // store in the linda the location of the script that created it
@@ -118,7 +118,7 @@ DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const
118 _linda_name = luaG_pushstring(L_, "<unresolved>"); 118 _linda_name = luaG_pushstring(L_, "<unresolved>");
119 } 119 }
120 // since the name is not empty, it is at slot 1, and we can replace "auto" with the result, just in case 120 // since the name is not empty, it is at slot 1, and we can replace "auto" with the result, just in case
121 LUA_ASSERT(L_, luaG_tostring(L_, 1) == "auto"); 121 LUA_ASSERT(L_, luaG_tostring(L_, StackIndex{ 1 }) == "auto");
122 lua_replace(L_, 1); 122 lua_replace(L_, 1);
123 } 123 }
124 124
diff --git a/src/luaerrors.h b/src/luaerrors.h
index 7bc08da..cf04f6c 100644
--- a/src/luaerrors.h
+++ b/src/luaerrors.h
@@ -1,5 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "unique.hpp"
4
3// ################################################################################################# 5// #################################################################################################
4 6
5// use this instead of Lua's lua_error 7// use this instead of Lua's lua_error
@@ -23,7 +25,7 @@ template <typename... ARGS>
23 25
24// use this instead of Lua's luaL_argerror 26// use this instead of Lua's luaL_argerror
25template <typename... ARGS> 27template <typename... ARGS>
26[[noreturn]] static inline void raise_luaL_argerror(lua_State* const L_, int const arg_, std::string_view const& extramsg_) 28[[noreturn]] static inline void raise_luaL_argerror(lua_State* const L_, StackIndex const arg_, std::string_view const& extramsg_)
27{ 29{
28 std::ignore = luaL_argerror(L_, arg_, extramsg_.data()); // doesn't return 30 std::ignore = luaL_argerror(L_, arg_, extramsg_.data()); // doesn't return
29 assert(false); // we should never get here, but i'm paranoid 31 assert(false); // we should never get here, but i'm paranoid
@@ -34,7 +36,7 @@ template <typename... ARGS>
34#if LUA_VERSION_NUM >= 504 36#if LUA_VERSION_NUM >= 504
35// use this instead of Lua's luaL_typeerror 37// use this instead of Lua's luaL_typeerror
36template <typename... ARGS> 38template <typename... ARGS>
37[[noreturn]] static inline void raise_luaL_typeerror(lua_State* const L_, int const arg_, std::string_view const& tname_) 39[[noreturn]] static inline void raise_luaL_typeerror(lua_State* const L_, StackIndex const arg_, std::string_view const& tname_)
38{ 40{
39 std::ignore = luaL_typeerror(L_, arg_, tname_.data()); // doesn't return 41 std::ignore = luaL_typeerror(L_, arg_, tname_.data()); // doesn't return
40 assert(false); // we should never get here, but i'm paranoid 42 assert(false); // we should never get here, but i'm paranoid
diff --git a/src/macros_and_utils.h b/src/macros_and_utils.h
index e73abef..f22d124 100644
--- a/src/macros_and_utils.h
+++ b/src/macros_and_utils.h
@@ -25,9 +25,8 @@ using lua_Duration = std::chrono::template duration<lua_Number>;
25 25
26// ################################################################################################# 26// #################################################################################################
27 27
28using SourceState = Unique<lua_State*>; 28DECLARE_UNIQUE_TYPE(SourceState, lua_State*);
29using DestState = Unique<lua_State*>; 29DECLARE_UNIQUE_TYPE(DestState, lua_State*);
30using StackIndex = Unique<int>;
31 30
32// ################################################################################################# 31// #################################################################################################
33 32
diff --git a/src/nameof.cpp b/src/nameof.cpp
index 3c82603..fd31a28 100644
--- a/src/nameof.cpp
+++ b/src/nameof.cpp
@@ -34,10 +34,10 @@ THE SOFTWARE.
34// Return some name helping to identify an object 34// Return some name helping to identify an object
35[[nodiscard]] static int DiscoverObjectNameRecur(lua_State* L_, int shortest_, int depth_) 35[[nodiscard]] static int DiscoverObjectNameRecur(lua_State* L_, int shortest_, int depth_)
36{ 36{
37 static constexpr int kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?} 37 static constexpr StackIndex kWhat{ 1 }; // the object to investigate // L_: o "r" {c} {fqn} ... {?}
38 static constexpr int kResult{ 2 }; // where the result string is stored 38 static constexpr StackIndex kResult{ 2 }; // where the result string is stored
39 static constexpr int kCache{ 3 }; // a cache 39 static constexpr StackIndex kCache{ 3 }; // a cache
40 static constexpr int kFQN{ 4 }; // the name compositing stack 40 static constexpr StackIndex kFQN{ 4 }; // the name compositing stack
41 // no need to scan this table if the name we will discover is longer than one we already know 41 // no need to scan this table if the name we will discover is longer than one we already know
42 if (shortest_ <= depth_ + 1) { 42 if (shortest_ <= depth_ + 1) {
43 return shortest_; 43 return shortest_;
@@ -80,7 +80,7 @@ THE SOFTWARE.
80 STACK_CHECK(L_, 0); 80 STACK_CHECK(L_, 0);
81 break; 81 break;
82 } 82 }
83 switch (luaG_type(L_, -1)) { // L_: o "r" {c} {fqn} ... {?} k v 83 switch (luaG_type(L_, kIdxTop)) { // L_: o "r" {c} {fqn} ... {?} k v
84 default: // nil, boolean, light userdata, number and string aren't identifiable 84 default: // nil, boolean, light userdata, number and string aren't identifiable
85 break; 85 break;
86 86
@@ -126,7 +126,7 @@ THE SOFTWARE.
126 // search in the object's uservalues 126 // search in the object's uservalues
127 { 127 {
128 int _uvi{ 1 }; 128 int _uvi{ 1 };
129 while (lua_getiuservalue(L_, -1, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u} 129 while (lua_getiuservalue(L_, kIdxTop, _uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... {?} k U {u}
130 if (lua_istable(L_, -1)) { // if it is a table, look inside 130 if (lua_istable(L_, -1)) { // if it is a table, look inside
131 ++depth_; 131 ++depth_;
132 luaG_pushstring(L_, "uservalue"); // L_: o "r" {c} {fqn} ... {?} k v {u} "uservalue" 132 luaG_pushstring(L_, "uservalue"); // L_: o "r" {c} {fqn} ... {?} k v {u} "uservalue"
@@ -167,13 +167,13 @@ THE SOFTWARE.
167// "type", "name" = lanes.nameof(o) 167// "type", "name" = lanes.nameof(o)
168LUAG_FUNC(nameof) 168LUAG_FUNC(nameof)
169{ 169{
170 int const _what{ lua_gettop(L_) }; 170 StackIndex const _what{ lua_gettop(L_) };
171 if (_what > 1) { 171 if (_what > 1) {
172 raise_luaL_argerror(L_, _what, "too many arguments."); 172 raise_luaL_argerror(L_, _what, "too many arguments.");
173 } 173 }
174 174
175 // nil, boolean, light userdata, number and string aren't identifiable 175 // nil, boolean, light userdata, number and string aren't identifiable
176 if (luaG_type(L_, 1) < LuaType::TABLE) { 176 if (luaG_type(L_, StackIndex{ 1 }) < LuaType::TABLE) {
177 lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "type" 177 lua_pushstring(L_, luaL_typename(L_, 1)); // L_: o "type"
178 lua_insert(L_, -2); // L_: "type" o 178 lua_insert(L_, -2); // L_: "type" o
179 return 2; 179 return 2;
@@ -197,7 +197,7 @@ LUAG_FUNC(nameof)
197 lua_pop(L_, 1); // L_: o nil {c} {fqn} 197 lua_pop(L_, 1); // L_: o nil {c} {fqn}
198 luaG_pushstring(L_, "_R"); // L_: o nil {c} {fqn} "_R" 198 luaG_pushstring(L_, "_R"); // L_: o nil {c} {fqn} "_R"
199 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn} 199 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn}
200 lua_pushvalue(L_, LUA_REGISTRYINDEX); // L_: o nil {c} {fqn} _R 200 lua_pushvalue(L_, kIdxRegistry); // L_: o nil {c} {fqn} _R
201 std::ignore = DiscoverObjectNameRecur(L_, std::numeric_limits<int>::max(), 1); 201 std::ignore = DiscoverObjectNameRecur(L_, std::numeric_limits<int>::max(), 1);
202 } 202 }
203 lua_pop(L_, 3); // L_: o "result" 203 lua_pop(L_, 3); // L_: o "result"
diff --git a/src/state.cpp b/src/state.cpp
index aa6e6a9..4664486 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -103,7 +103,7 @@ namespace {
103 luaL_requiref(L_, _name.data(), _libfunc, !_isLanesCore); // L_: {lib} 103 luaL_requiref(L_, _name.data(), _libfunc, !_isLanesCore); // L_: {lib}
104 // lanes.core doesn't declare a global, so scan it here and now 104 // lanes.core doesn't declare a global, so scan it here and now
105 if (_isLanesCore) { 105 if (_isLanesCore) {
106 tools::PopulateFuncLookupTable(L_, -1, _name); 106 tools::PopulateFuncLookupTable(L_, kIdxTop, _name);
107 } 107 }
108 lua_pop(L_, 1); // L_: 108 lua_pop(L_, 1); // L_:
109 STACK_CHECK(L_, 0); 109 STACK_CHECK(L_, 0);
@@ -282,7 +282,7 @@ namespace state {
282 STACK_CHECK(_L, 0); 282 STACK_CHECK(_L, 0);
283 // after all this, register everything we find in our name<->function database 283 // after all this, register everything we find in our name<->function database
284 luaG_pushglobaltable(_L); // L: _G 284 luaG_pushglobaltable(_L); // L: _G
285 tools::PopulateFuncLookupTable(_L, -1, {}); 285 tools::PopulateFuncLookupTable(_L, kIdxTop, {});
286 lua_pop(_L, 1); // L: 286 lua_pop(_L, 1); // L:
287 STACK_CHECK(_L, 0); 287 STACK_CHECK(_L, 0);
288 288
@@ -324,7 +324,7 @@ namespace state {
324 lua_newtable(L_); // L_: out 324 lua_newtable(L_); // L_: out
325 for (luaL_Reg const& _entry : local::sLibs) { 325 for (luaL_Reg const& _entry : local::sLibs) {
326 lua_pushboolean(L_, 1); // L_: out true 326 lua_pushboolean(L_, 1); // L_: out true
327 luaG_setfield(L_, -2, std::string_view{ _entry.name }); // out[name] = true // L_: out 327 luaG_setfield(L_, StackIndex{ -2 }, std::string_view{ _entry.name }); // out[name] = true // L_: out
328 } 328 }
329 STACK_CHECK(L_, 1); 329 STACK_CHECK(L_, 1);
330 return 1; 330 return 1;
diff --git a/src/tools.cpp b/src/tools.cpp
index d580f67..d0204a6 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -66,7 +66,7 @@ static constexpr int kWriterReturnCode{ 666 };
66 * +-----------------+-------------------+------------+----------+ 66 * +-----------------+-------------------+------------+----------+
67 */ 67 */
68 68
69FuncSubType luaG_getfuncsubtype(lua_State* const L_, int const i_) 69FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_)
70{ 70{
71 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions 71 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions
72 return FuncSubType::Native; 72 return FuncSubType::Native;
@@ -92,7 +92,7 @@ FuncSubType luaG_getfuncsubtype(lua_State* const L_, int const i_)
92namespace tools { 92namespace tools {
93 93
94 // inspired from tconcat() in ltablib.c 94 // inspired from tconcat() in ltablib.c
95 std::string_view PushFQN(lua_State* const L_, int const t_, int const last_) 95 std::string_view PushFQN(lua_State* const L_, StackIndex const t_, int const last_)
96 { 96 {
97 STACK_CHECK_START_REL(L_, 0); 97 STACK_CHECK_START_REL(L_, 0);
98 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... 98 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it...
@@ -111,7 +111,7 @@ namespace tools {
111 // &b is popped at that point (-> replaced by the result) 111 // &b is popped at that point (-> replaced by the result)
112 luaL_pushresult(&_b); // L_: ... {} ... "<result>" 112 luaL_pushresult(&_b); // L_: ... {} ... "<result>"
113 STACK_CHECK(L_, 1); 113 STACK_CHECK(L_, 1);
114 return luaG_tostring(L_, -1); 114 return luaG_tostring(L_, kIdxTop);
115 } 115 }
116 116
117} // namespace tools 117} // namespace tools
@@ -126,12 +126,12 @@ namespace tools {
126 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter 126 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter
127 * pops the processed object from the stack 127 * pops the processed object from the stack
128 */ 128 */
129static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_) 129static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_, int const depth_)
130{ 130{
131 // slot 1 in the stack contains the table that receives everything we found 131 // slot 1 in the stack contains the table that receives everything we found
132 int const _dest{ ctxBase_ }; 132 StackIndex const _dest{ ctxBase_ };
133 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i 133 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i
134 int const _fqn{ ctxBase_ + 1 }; 134 StackIndex const _fqn{ ctxBase_ + 1 };
135 135
136 DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) }); 136 DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) });
137 DEBUGSPEW_CODE(DebugSpew(_U) << "update_lookup_entry()" << std::endl); 137 DEBUGSPEW_CODE(DebugSpew(_U) << "update_lookup_entry()" << std::endl);
@@ -141,14 +141,14 @@ static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_)
141 // first, raise an error if the function is already known 141 // first, raise an error if the function is already known
142 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o 142 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o
143 lua_rawget(L_, _dest); // L_: ... {bfc} k o name? 143 lua_rawget(L_, _dest); // L_: ... {bfc} k o name?
144 std::string_view const _prevName{ luaG_tostring(L_, -1) }; // nullptr if we got nil (first encounter of this object) 144 std::string_view const _prevName{ luaG_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object)
145 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 145 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
146 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k 146 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k
147 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::NUMBER || luaG_type(L_, -1) == LuaType::STRING); 147 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER || luaG_type(L_, kIdxTop) == LuaType::STRING);
148 ++depth_; 148 int const _deeper{ depth_ + 1 };
149 lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k o name? 149 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name?
150 // generate name 150 // generate name
151 std::string_view const _newName{ tools::PushFQN(L_, _fqn, depth_) }; // L_: ... {bfc} k o name? "f.q.n" 151 std::string_view const _newName{ tools::PushFQN(L_, _fqn, _deeper) }; // L_: ... {bfc} k o name? "f.q.n"
152 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order 152 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order
153 // on different VMs even when the tables are populated the exact same way. 153 // on different VMs even when the tables are populated the exact same way.
154 // Also, when Lua is built with compatibility options (such as LUA_COMPAT_ALL), some base libraries register functions under multiple names. 154 // Also, when Lua is built with compatibility options (such as LUA_COMPAT_ALL), some base libraries register functions under multiple names.
@@ -183,21 +183,20 @@ static void update_lookup_entry(lua_State* L_, int ctxBase_, int depth_)
183 lua_rawset(L_, _dest); // L_: ... {bfc} k 183 lua_rawset(L_, _dest); // L_: ... {bfc} k
184 // remove table name from fqn stack 184 // remove table name from fqn stack
185 lua_pushnil(L_); // L_: ... {bfc} k nil 185 lua_pushnil(L_); // L_: ... {bfc} k nil
186 lua_rawseti(L_, _fqn, depth_); // L_: ... {bfc} k 186 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k
187 } 187 }
188 --depth_;
189 STACK_CHECK(L_, -1); 188 STACK_CHECK(L_, -1);
190} 189}
191 190
192// ################################################################################################# 191// #################################################################################################
193 192
194static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_, int depth_) 193static void populate_func_lookup_table_recur(lua_State* const L_, StackIndex const dbIdx_, StackIndex const i_, int const depth_)
195{ 194{
196 // slot dbIdx_ contains the lookup database table 195 // slot dbIdx_ contains the lookup database table
197 // slot dbIdx_ + 1 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_ 196 // slot dbIdx_ + 1 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot i_
198 int const _fqn{ dbIdx_ + 1 }; 197 StackIndex const _fqn{ dbIdx_ + 1 };
199 // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops 198 // slot dbIdx_ + 2 contains a cache that stores all already visited tables to avoid infinite recursion loops
200 int const _cache{ dbIdx_ + 2 }; 199 StackIndex const _cache{ dbIdx_ + 2 };
201 DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) }); 200 DEBUGSPEW_CODE(Universe* const _U{ Universe::Get(L_) });
202 DEBUGSPEW_CODE(DebugSpew(_U) << "populate_func_lookup_table_recur()" << std::endl); 201 DEBUGSPEW_CODE(DebugSpew(_U) << "populate_func_lookup_table_recur()" << std::endl);
203 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 202 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
@@ -253,7 +252,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_,
253 lua_rawset(L_, breadthFirstCache); // L_: ... {i_} {bfc} k {} 252 lua_rawset(L_, breadthFirstCache); // L_: ... {i_} {bfc} k {}
254 // generate a name, and if we already had one name, keep whichever is the shorter 253 // generate a name, and if we already had one name, keep whichever is the shorter
255 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 254 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
256 } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, -1) != FuncSubType::Bytecode)) { 255 } else if (lua_isfunction(L_, -1) && (luaG_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) {
257 // generate a name, and if we already had one name, keep whichever is the shorter 256 // generate a name, and if we already had one name, keep whichever is the shorter
258 // this pops the function from the stack 257 // this pops the function from the stack
259 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 258 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
@@ -263,7 +262,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_,
263 STACK_CHECK(L_, 2); 262 STACK_CHECK(L_, 2);
264 } 263 }
265 // now process the tables we encountered at that depth 264 // now process the tables we encountered at that depth
266 ++depth_; 265 int const _deeper{ depth_ + 1 };
267 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 266 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
268 while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} 267 while (lua_next(L_, breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {}
269 DEBUGSPEW_CODE(std::string_view const _key{ (luaG_type(L_, -2) == LuaType::STRING) ? luaG_tostring(L_, -2) : std::string_view{ "<not a string>" } }); 268 DEBUGSPEW_CODE(std::string_view const _key{ (luaG_type(L_, -2) == LuaType::STRING) ? luaG_tostring(L_, -2) : std::string_view{ "<not a string>" } });
@@ -272,7 +271,7 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_,
272 // un-visit this table in case we do need to process it 271 // un-visit this table in case we do need to process it
273 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 272 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
274 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n 273 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n
275 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::NUMBER); 274 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER);
276 _visit_count = lua_tointeger(L_, -1) - 1; 275 _visit_count = lua_tointeger(L_, -1) - 1;
277 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {} 276 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {}
278 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 277 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
@@ -284,15 +283,14 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_,
284 lua_rawset(L_, _cache); // L_: ... {i_} {bfc} k {} 283 lua_rawset(L_, _cache); // L_: ... {i_} {bfc} k {}
285 // push table name in fqn stack (note that concatenation will crash if name is a not string!) 284 // push table name in fqn stack (note that concatenation will crash if name is a not string!)
286 lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k 285 lua_pushvalue(L_, -2); // L_: ... {i_} {bfc} k {} k
287 lua_rawseti(L_, _fqn, depth_); // L_: ... {i_} {bfc} k {} 286 lua_rawseti(L_, _fqn, _deeper); // L_: ... {i_} {bfc} k {}
288 populate_func_lookup_table_recur(L_, dbIdx_, lua_gettop(L_), depth_); 287 populate_func_lookup_table_recur(L_, dbIdx_, StackIndex{ lua_gettop(L_) }, _deeper);
289 lua_pop(L_, 1); // L_: ... {i_} {bfc} k 288 lua_pop(L_, 1); // L_: ... {i_} {bfc} k
290 STACK_CHECK(L_, 2); 289 STACK_CHECK(L_, 2);
291 } 290 }
292 // remove table name from fqn stack 291 // remove table name from fqn stack
293 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 292 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
294 lua_rawseti(L_, _fqn, depth_); // L_: ... {i_} {bfc} 293 lua_rawseti(L_, _fqn, _deeper); // L_: ... {i_} {bfc}
295 --depth_;
296 // we are done with our cache 294 // we are done with our cache
297 lua_pop(L_, 1); // L_: ... {i_} 295 lua_pop(L_, 1); // L_: ... {i_}
298 STACK_CHECK(L_, 0); 296 STACK_CHECK(L_, 0);
@@ -304,9 +302,9 @@ static void populate_func_lookup_table_recur(lua_State* L_, int dbIdx_, int i_,
304namespace tools { 302namespace tools {
305 303
306 // create a "fully.qualified.name" <-> function equivalence database 304 // create a "fully.qualified.name" <-> function equivalence database
307 void PopulateFuncLookupTable(lua_State* const L_, int const i_, std::string_view const& name_) 305 void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_)
308 { 306 {
309 int const _in_base{ luaG_absindex(L_, i_) }; 307 StackIndex const _in_base{ luaG_absindex(L_, i_) };
310 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_)); 308 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_));
311 std::string_view _name{ name_.empty() ? std::string_view{} : name_ }; 309 std::string_view _name{ name_.empty() ? std::string_view{} : name_ };
312 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl); 310 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl);
@@ -314,7 +312,7 @@ namespace tools {
314 STACK_GROW(L_, 3); 312 STACK_GROW(L_, 3);
315 STACK_CHECK_START_REL(L_, 0); 313 STACK_CHECK_START_REL(L_, 0);
316 kLookupRegKey.pushValue(L_); // L_: {} 314 kLookupRegKey.pushValue(L_); // L_: {}
317 int const _dbIdx{ lua_gettop(L_) }; 315 StackIndex const _dbIdx{ lua_gettop(L_) };
318 STACK_CHECK(L_, 1); 316 STACK_CHECK(L_, 1);
319 LUA_ASSERT(L_, lua_istable(L_, -1)); 317 LUA_ASSERT(L_, lua_istable(L_, -1));
320 if (luaG_type(L_, _in_base) == LuaType::FUNCTION) { // for example when a module is a simple function 318 if (luaG_type(L_, _in_base) == LuaType::FUNCTION) { // for example when a module is a simple function
diff --git a/src/tools.h b/src/tools.h
index 5127ea0..34cbb8f 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -18,7 +18,7 @@ enum class FuncSubType
18 FastJIT 18 FastJIT
19}; 19};
20 20
21[[nodiscard]] FuncSubType luaG_getfuncsubtype(lua_State* L_, int i_); 21[[nodiscard]] FuncSubType luaG_getfuncsubtype(lua_State* L_, StackIndex i_);
22 22
23// ################################################################################################# 23// #################################################################################################
24 24
@@ -31,7 +31,7 @@ static constexpr RegistryUniqueKey kLookupRegKey{ 0xBF1FC5CF3C6DD47Bull }; // re
31// ################################################################################################# 31// #################################################################################################
32 32
33namespace tools { 33namespace tools {
34 void PopulateFuncLookupTable(lua_State* const L_, int const i_, std::string_view const& name_); 34 void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_);
35 [[nodiscard]] std::string_view PushFQN(lua_State* L_, int t_, int last_); 35 [[nodiscard]] std::string_view PushFQN(lua_State* L_, StackIndex t_, int last_);
36 void SerializeRequire(lua_State* L_); 36 void SerializeRequire(lua_State* L_);
37} // namespace tools 37} // namespace tools
diff --git a/src/unique.hpp b/src/unique.hpp
index aeb7a67..846708e 100644
--- a/src/unique.hpp
+++ b/src/unique.hpp
@@ -3,7 +3,7 @@
3// ################################################################################################# 3// #################################################################################################
4 4
5// A unique type generator 5// A unique type generator
6template <typename T, auto = [] {}, typename specialization = void> 6template <typename T, typename TAG, typename specialization = void>
7class Unique 7class Unique
8{ 8{
9 private: 9 private:
@@ -11,13 +11,15 @@ class Unique
11 11
12 public: 12 public:
13 using type = T; 13 using type = T;
14 Unique() = default; 14 constexpr Unique() = default;
15 operator T() const { return val; } 15 operator T() const { return val; }
16 explicit Unique(T b_) 16 Unique& operator=(T const&) = delete;
17 Unique& operator=(T&&) = delete;
18 explicit constexpr Unique(T b_)
17 : val{ b_ } 19 : val{ b_ }
18 { 20 {
19 } 21 }
20 // pre-imcrement 22 // pre-increment
21 auto& operator++() 23 auto& operator++()
22 { 24 {
23 ++val; 25 ++val;
@@ -26,12 +28,12 @@ class Unique
26 // post-increment 28 // post-increment
27 auto operator++(int) 29 auto operator++(int)
28 { 30 {
29 return Unique<T>{ std::exchange(val, val + 1) }; 31 return Unique<T, TAG>{ std::exchange(val, val + 1) };
30 } 32 }
31}; 33};
32 34
33template <typename T, auto lambda> 35template <typename T, typename TAG>
34class Unique<T, lambda, std::enable_if_t<!std::is_scalar_v<T>>> 36class Unique<T, TAG, std::enable_if_t<!std::is_scalar_v<T>>>
35: public T 37: public T
36{ 38{
37 public: 39 public:
@@ -42,3 +44,9 @@ class Unique<T, lambda, std::enable_if_t<!std::is_scalar_v<T>>>
42 { 44 {
43 } 45 }
44}; 46};
47
48#define DECLARE_UNIQUE_TYPE(_name, _type) using _name = Unique<_type, class Unique_##_name##_Tag>
49
50// putting this here to break a header circular dependency until I find a better place
51DECLARE_UNIQUE_TYPE(StackIndex, int);
52static constexpr StackIndex kIdxTop{ -1 };
diff --git a/src/uniquekey.h b/src/uniquekey.h
index debfee4..14b6d84 100644
--- a/src/uniquekey.h
+++ b/src/uniquekey.h
@@ -27,7 +27,7 @@ class UniqueKey
27 inline constexpr std::weak_ordering operator<=>(UniqueKey const& rhs_) const { return storage <=> rhs_.storage; } 27 inline constexpr std::weak_ordering operator<=>(UniqueKey const& rhs_) const { return storage <=> rhs_.storage; }
28 inline constexpr auto operator==(UniqueKey const& rhs_) const { return storage == rhs_.storage; } 28 inline constexpr auto operator==(UniqueKey const& rhs_) const { return storage == rhs_.storage; }
29 // --------------------------------------------------------------------------------------------- 29 // ---------------------------------------------------------------------------------------------
30 bool equals(lua_State* const L_, int const i_) const 30 bool equals(lua_State* const L_, StackIndex const i_) const
31 { 31 {
32 return lua_touserdata(L_, i_) == std::bit_cast<void*>(storage); 32 return lua_touserdata(L_, i_) == std::bit_cast<void*>(storage);
33 } 33 }
@@ -50,8 +50,8 @@ class RegistryUniqueKey
50 void pushValue(lua_State* const L_) const 50 void pushValue(lua_State* const L_) const
51 { 51 {
52 STACK_CHECK_START_REL(L_, 0); 52 STACK_CHECK_START_REL(L_, 0);
53 pushKey(L_); 53 pushKey(L_); // L_: ... key
54 lua_rawget(L_, LUA_REGISTRYINDEX); 54 lua_rawget(L_, kIdxRegistry); // L_: ... value
55 STACK_CHECK(L_, 1); 55 STACK_CHECK(L_, 1);
56 } 56 }
57 // --------------------------------------------------------------------------------------------- 57 // ---------------------------------------------------------------------------------------------
@@ -59,9 +59,9 @@ class RegistryUniqueKey
59 void setValue(lua_State* const L_, OP operation_) const 59 void setValue(lua_State* const L_, OP operation_) const
60 { 60 {
61 // Note we can't check stack consistency because operation is not always a push (could be insert, replace, whatever) 61 // Note we can't check stack consistency because operation is not always a push (could be insert, replace, whatever)
62 pushKey(L_); // ... key 62 pushKey(L_); // L_: ... key
63 operation_(L_); // ... key value 63 operation_(L_); // L_: ... key value
64 lua_rawset(L_, LUA_REGISTRYINDEX); // ... 64 lua_rawset(L_, kIdxRegistry); // L_: ...
65 } 65 }
66 // --------------------------------------------------------------------------------------------- 66 // ---------------------------------------------------------------------------------------------
67 template <typename T> 67 template <typename T>
@@ -69,9 +69,9 @@ class RegistryUniqueKey
69 { 69 {
70 STACK_GROW(L_, 1); 70 STACK_GROW(L_, 1);
71 STACK_CHECK_START_REL(L_, 0); 71 STACK_CHECK_START_REL(L_, 0);
72 pushValue(L_); 72 pushValue(L_); // L_: ... {}|nil
73 T* const value{ luaG_tolightuserdata<T>(L_, -1) }; // lightuserdata/nil 73 T* const value{ luaG_tolightuserdata<T>(L_, kIdxTop) };
74 lua_pop(L_, 1); 74 lua_pop(L_, 1); // L_: ...
75 STACK_CHECK(L_, 0); 75 STACK_CHECK(L_, 0);
76 return value; 76 return value;
77 } 77 }
@@ -80,9 +80,9 @@ class RegistryUniqueKey
80 { 80 {
81 STACK_GROW(L_, 1); 81 STACK_GROW(L_, 1);
82 STACK_CHECK_START_REL(L_, 0); 82 STACK_CHECK_START_REL(L_, 0);
83 pushValue(L_); 83 pushValue(L_); // L_: ... bool|nil
84 bool const value{ lua_toboolean(L_, -1) ? true : false }; // bool/nil 84 bool const value{ lua_toboolean(L_, -1) ? true : false };
85 lua_pop(L_, 1); 85 lua_pop(L_, 1); // L_: ...
86 STACK_CHECK(L_, 0); 86 STACK_CHECK(L_, 0);
87 return value; 87 return value;
88 } 88 }
diff --git a/src/universe.cpp b/src/universe.cpp
index 3800dbb..c435dad 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -100,7 +100,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
100 } 100 }
101 kConfigRegKey.pushValue(L_); // L_: config 101 kConfigRegKey.pushValue(L_); // L_: config
102 STACK_CHECK(L_, 1); 102 STACK_CHECK(L_, 1);
103 LuaType const _funcType{ luaG_getfield(L_, -1, kOnStateCreate) }; // L_: config on_state_create() 103 LuaType const _funcType{ luaG_getfield(L_, kIdxTop, kOnStateCreate) }; // L_: config on_state_create()
104 if (_funcType != LuaType::FUNCTION) { 104 if (_funcType != LuaType::FUNCTION) {
105 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data()); 105 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data());
106 } 106 }
@@ -111,29 +111,28 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
111 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; 111 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" };
112 luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>" 112 luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>"
113 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { 113 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) {
114 raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, -1).data() : luaG_typename(L_, -1).data()); 114 raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, kIdxTop).data() : luaG_typename(L_, kIdxTop).data());
115 } 115 }
116 STACK_CHECK(L_, 0); 116 STACK_CHECK(L_, 0);
117} 117}
118 118
119
120
121// ################################################################################################# 119// #################################################################################################
122 120
123// only called from the master state 121// only called from the master state
124[[nodiscard]] Universe* Universe::Create(lua_State* const L_) 122[[nodiscard]] Universe* Universe::Create(lua_State* const L_)
125{ 123{
126 LUA_ASSERT(L_, Universe::Get(L_) == nullptr); 124 LUA_ASSERT(L_, Universe::Get(L_) == nullptr);
125 static constexpr StackIndex kIdxSettings{ 1 };
127 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1)); 126 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1));
128 STACK_CHECK_START_REL(L_, 0); // L_: settings 127 STACK_CHECK_START_REL(L_, 0); // L_: settings
129 std::ignore = luaG_getfield(L_, 1, "nb_user_keepers"); // L_: settings nb_user_keepers 128 std::ignore = luaG_getfield(L_, kIdxSettings, "nb_user_keepers"); // L_: settings nb_user_keepers
130 int const _nbUserKeepers{ static_cast<int>(lua_tointeger(L_, -1)) + 1}; 129 int const _nbUserKeepers{ static_cast<int>(lua_tointeger(L_, -1)) + 1};
131 lua_pop(L_, 1); // L_: settings 130 lua_pop(L_, 1); // L_: settings
132 if (_nbUserKeepers < 1) { 131 if (_nbUserKeepers < 1) {
133 raise_luaL_error(L_, "Bad number of additional keepers (%d)", _nbUserKeepers); 132 raise_luaL_error(L_, "Bad number of additional keepers (%d)", _nbUserKeepers);
134 } 133 }
135 STACK_CHECK(L_, 0); 134 STACK_CHECK(L_, 0);
136 std::ignore = luaG_getfield(L_, 1, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold 135 std::ignore = luaG_getfield(L_, kIdxSettings, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold
137 int const _keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) }; 136 int const _keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) };
138 lua_pop(L_, 1); // L_: settings 137 lua_pop(L_, 1); // L_: settings
139 STACK_CHECK(L_, 0); 138 STACK_CHECK(L_, 0);
@@ -146,22 +145,22 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
146 145
147 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 146 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
148 lua_createtable(L_, 0, 1); // L_: settings universe {mt} 147 lua_createtable(L_, 0, 1); // L_: settings universe {mt}
149 std::ignore = luaG_getfield(L_, 1, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout 148 std::ignore = luaG_getfield(L_, kIdxSettings, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout
150 lua_pushcclosure(L_, LG_universe_gc, 1); // L_: settings universe {mt} LG_universe_gc 149 lua_pushcclosure(L_, LG_universe_gc, 1); // L_: settings universe {mt} LG_universe_gc
151 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt} 150 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt}
152 lua_setmetatable(L_, -2); // L_: settings universe 151 lua_setmetatable(L_, -2); // L_: settings universe
153 lua_pop(L_, 1); // L_: settings 152 lua_pop(L_, 1); // L_: settings
154 153
155 std::ignore = luaG_getfield(L_, 1, "strip_functions"); // L_: settings strip_functions 154 std::ignore = luaG_getfield(L_, kIdxSettings, "strip_functions"); // L_: settings strip_functions
156 _U->stripFunctions = lua_toboolean(L_, -1) ? true : false; 155 _U->stripFunctions = lua_toboolean(L_, -1) ? true : false;
157 lua_pop(L_, 1); // L_: settings 156 lua_pop(L_, 1); // L_: settings
158 157
159 std::ignore = luaG_getfield(L_, 1, "verbose_errors"); // L_: settings verbose_errors 158 std::ignore = luaG_getfield(L_, kIdxSettings, "verbose_errors"); // L_: settings verbose_errors
160 _U->verboseErrors = lua_toboolean(L_, -1) ? true : false; 159 _U->verboseErrors = lua_toboolean(L_, -1) ? true : false;
161 lua_pop(L_, 1); // L_: settings 160 lua_pop(L_, 1); // L_: settings
162 161
163 // tracking 162 // tracking
164 std::ignore = luaG_getfield(L_, 1, "track_lanes"); // L_: settings track_lanes 163 std::ignore = luaG_getfield(L_, kIdxSettings, "track_lanes"); // L_: settings track_lanes
165 if (lua_toboolean(L_, -1)) { 164 if (lua_toboolean(L_, -1)) {
166 _U->tracker.activate(); 165 _U->tracker.activate();
167 } 166 }
@@ -182,7 +181,7 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
182 STACK_CHECK(L_, 1); 181 STACK_CHECK(L_, 1);
183 182
184 // Proxy userdata contents is only a 'DeepPrelude*' pointer 183 // Proxy userdata contents is only a 'DeepPrelude*' pointer
185 _U->timerLinda = *luaG_tofulluserdata<DeepPrelude*>(L_, -1); 184 _U->timerLinda = *luaG_tofulluserdata<DeepPrelude*>(L_, kIdxTop);
186 // increment refcount so that this linda remains alive as long as the universe exists. 185 // increment refcount so that this linda remains alive as long as the universe exists.
187 _U->timerLinda->refcount.fetch_add(1, std::memory_order_relaxed); 186 _U->timerLinda->refcount.fetch_add(1, std::memory_order_relaxed);
188 lua_pop(L_, 1); // L_: settings 187 lua_pop(L_, 1); // L_: settings
@@ -224,13 +223,13 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
224 // start by just grabbing whatever allocator was provided to the master state 223 // start by just grabbing whatever allocator was provided to the master state
225 protectedAllocator.initFrom(L_); 224 protectedAllocator.initFrom(L_);
226 STACK_CHECK_START_REL(L_, 1); // L_: settings 225 STACK_CHECK_START_REL(L_, 1); // L_: settings
227 switch (luaG_getfield(L_, -1, "allocator")) { // L_: settings allocator|nil|"protected" 226 switch (luaG_getfield(L_, kIdxTop, "allocator")) { // L_: settings allocator|nil|"protected"
228 case LuaType::NIL: 227 case LuaType::NIL:
229 // nothing else to do 228 // nothing else to do
230 break; 229 break;
231 230
232 case LuaType::STRING: 231 case LuaType::STRING:
233 LUA_ASSERT(L_, luaG_tostring(L_, -1) == "protected"); 232 LUA_ASSERT(L_, luaG_tostring(L_, kIdxTop) == "protected");
234 // set the original allocator to call from inside protection by the mutex 233 // set the original allocator to call from inside protection by the mutex
235 protectedAllocator.installIn(L_); 234 protectedAllocator.installIn(L_);
236 // before a state is created, this function will be called to obtain the allocator 235 // before a state is created, this function will be called to obtain the allocator
@@ -255,14 +254,14 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
255 break; 254 break;
256 255
257 default: // should be filtered out in lanes.lua 256 default: // should be filtered out in lanes.lua
258 raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, -1).data()); 257 raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, kIdxTop).data());
259 } 258 }
260 lua_pop(L_, 1); // L_: settings 259 lua_pop(L_, 1); // L_: settings
261 STACK_CHECK(L_, 1); 260 STACK_CHECK(L_, 1);
262 261
263 std::ignore = luaG_getfield(L_, -1, "internal_allocator"); // L_: settings "libc"|"allocator" 262 std::ignore = luaG_getfield(L_, kIdxTop, "internal_allocator"); // L_: settings "libc"|"allocator"
264 LUA_ASSERT(L_, lua_isstring(L_, -1)); // should be the case due to lanes.lua parameter validation 263 LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation
265 std::string_view const _allocator{ luaG_tostring(L_, -1) }; 264 std::string_view const _allocator{ luaG_tostring(L_, kIdxTop) };
266 if (_allocator == "libc") { 265 if (_allocator == "libc") {
267 internalAllocator = lanes::AllocatorDefinition{ lanes::AllocatorDefinition::kAllocatorVersion, libc_lua_Alloc, nullptr }; 266 internalAllocator = lanes::AllocatorDefinition{ lanes::AllocatorDefinition::kAllocatorVersion, libc_lua_Alloc, nullptr };
268 } else { 267 } else {
@@ -284,7 +283,7 @@ int Universe::InitializeFinalizer(lua_State* const L_)
284 283
285 // make sure we are only called from the Master Lua State! 284 // make sure we are only called from the Master Lua State!
286 kUniverseFullRegKey.pushValue(L_); // L_: f U 285 kUniverseFullRegKey.pushValue(L_); // L_: f U
287 if (luaG_type(L_, -1) != LuaType::USERDATA) { 286 if (luaG_type(L_, kIdxTop) != LuaType::USERDATA) {
288 raise_luaL_error(L_, "lanes.%s called from inside a lane", kFinally); 287 raise_luaL_error(L_, "lanes.%s called from inside a lane", kFinally);
289 } 288 }
290 lua_pop(L_, 1); // L_: f 289 lua_pop(L_, 1); // L_: f
@@ -300,8 +299,8 @@ int Universe::InitializeFinalizer(lua_State* const L_)
300void Universe::initializeOnStateCreate(lua_State* const L_) 299void Universe::initializeOnStateCreate(lua_State* const L_)
301{ 300{
302 STACK_CHECK_START_REL(L_, 0); // L_: settings 301 STACK_CHECK_START_REL(L_, 0); // L_: settings
303 if (luaG_getfield(L_, -1, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil 302 if (luaG_getfield(L_, kIdxTop, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil
304 LUA_ASSERT(L_, luaG_type(L_, -1) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation 303 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation
305 // store C function pointer in an internal variable 304 // store C function pointer in an internal variable
306 lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create 305 lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create
307 if (_func) { 306 if (_func) {
@@ -314,7 +313,7 @@ void Universe::initializeOnStateCreate(lua_State* const L_)
314 // remove this C function from the config table so that it doesn't cause problems 313 // remove this C function from the config table so that it doesn't cause problems
315 // when we transfer the config table in newly created Lua states 314 // when we transfer the config table in newly created Lua states
316 lua_pushnil(L_); // L_: settings on_state_create nil 315 lua_pushnil(L_); // L_: settings on_state_create nil
317 luaG_setfield(L_, -3, kOnStateCreate); // L_: settings on_state_create 316 luaG_setfield(L_, StackIndex{ -3 }, kOnStateCreate); // L_: settings on_state_create
318 } else { 317 } else {
319 // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant) 318 // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant)
320 onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data())); 319 onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data()));
@@ -339,7 +338,7 @@ lanes::AllocatorDefinition Universe::resolveAllocator(lua_State* const L_, std::
339 lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator() 338 lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator()
340 luaG_pushstring(L_, hint_); // L_: provideAllocator() "<hint>" 339 luaG_pushstring(L_, hint_); // L_: provideAllocator() "<hint>"
341 lua_call(L_, 1, 1); // L_: result 340 lua_call(L_, 1, 1); // L_: result
342 lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata<lanes::AllocatorDefinition>(L_, -1) }; 341 lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata<lanes::AllocatorDefinition>(L_, kIdxTop) };
343 if (!_def || _def->version != lanes::AllocatorDefinition::kAllocatorVersion) { 342 if (!_def || _def->version != lanes::AllocatorDefinition::kAllocatorVersion) {
344 raise_luaL_error(L_, "Bad config.allocator function, must provide a valid AllocatorDefinition"); 343 raise_luaL_error(L_, "Bad config.allocator function, must provide a valid AllocatorDefinition");
345 } 344 }
@@ -414,7 +413,7 @@ LUAG_FUNC(universe_gc)
414{ 413{
415 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; 414 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) };
416 STACK_CHECK_START_ABS(L_, 1); 415 STACK_CHECK_START_ABS(L_, 1);
417 Universe* const _U{ luaG_tofulluserdata<Universe>(L_, 1) }; // L_: U 416 Universe* const _U{ luaG_tofulluserdata<Universe>(L_, StackIndex{ 1 }) }; // L_: U
418 417
419 // attempt to terminate all lanes with increasingly stronger cancel methods 418 // attempt to terminate all lanes with increasingly stronger cancel methods
420 bool const _allLanesTerminated{ 419 bool const _allLanesTerminated{
@@ -433,7 +432,7 @@ LUAG_FUNC(universe_gc)
433 STACK_CHECK(L_, 2); 432 STACK_CHECK(L_, 2);
434 433
435 // if some lanes are still running here, we have no other choice than crashing or freezing and let the client figure out what's wrong 434 // if some lanes are still running here, we have no other choice than crashing or freezing and let the client figure out what's wrong
436 bool const _throw{ luaG_tostring(L_, -1) == "throw" }; 435 bool const _throw{ luaG_tostring(L_, kIdxTop) == "throw" };
437 lua_pop(L_, 1); // L_: U 436 lua_pop(L_, 1); // L_: U
438 437
439 while (_U->selfdestructFirst != SELFDESTRUCT_END) { 438 while (_U->selfdestructFirst != SELFDESTRUCT_END) {