diff options
Diffstat (limited to 'src/state.cpp')
-rw-r--r-- | src/state.cpp | 327 |
1 files changed, 147 insertions, 180 deletions
diff --git a/src/state.cpp b/src/state.cpp index e71865d..ebb24dd 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
@@ -40,7 +40,7 @@ THE SOFTWARE. | |||
40 | // ################################################################################################# | 40 | // ################################################################################################# |
41 | 41 | ||
42 | /*---=== Serialize require ===--- | 42 | /*---=== Serialize require ===--- |
43 | */ | 43 | */ |
44 | 44 | ||
45 | //--- | 45 | //--- |
46 | // [val,...]= new_require( ... ) | 46 | // [val,...]= new_require( ... ) |
@@ -52,55 +52,51 @@ THE SOFTWARE. | |||
52 | [[nodiscard]] static int luaG_new_require(lua_State* L_) | 52 | [[nodiscard]] static int luaG_new_require(lua_State* L_) |
53 | { | 53 | { |
54 | int rc; | 54 | int rc; |
55 | int const args = lua_gettop(L_); // args | 55 | int const args = lua_gettop(L_); // L_: args |
56 | Universe* U = universe_get(L_); | 56 | Universe* U = universe_get(L_); |
57 | //char const* modname = luaL_checkstring(L_, 1); | 57 | // char const* modname = luaL_checkstring(L_, 1); |
58 | 58 | ||
59 | STACK_GROW(L_, 1); | 59 | STACK_GROW(L_, 1); |
60 | 60 | ||
61 | lua_pushvalue(L_, lua_upvalueindex( 1)); // args require | 61 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: args require |
62 | lua_insert(L_, 1); // require args | 62 | lua_insert(L_, 1); // L_: require args |
63 | 63 | ||
64 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | 64 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would |
65 | // leave us locked, blocking any future 'require' calls from other lanes. | 65 | // leave us locked, blocking any future 'require' calls from other lanes. |
66 | 66 | ||
67 | U->require_cs.lock(); | 67 | U->require_cs.lock(); |
68 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET | 68 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET |
69 | rc = lua_pcall(L_, args, LUA_MULTRET, 0 /*errfunc*/ ); // err|result(s) | 69 | rc = lua_pcall(L_, args, LUA_MULTRET, 0 /*errfunc*/); // L_: err|result(s) |
70 | U->require_cs.unlock(); | 70 | U->require_cs.unlock(); |
71 | 71 | ||
72 | // the required module (or an error message) is left on the stack as returned value by original require function | 72 | // the required module (or an error message) is left on the stack as returned value by original require function |
73 | 73 | ||
74 | if (rc != LUA_OK) // LUA_ERRRUN / LUA_ERRMEM ? | 74 | if (rc != LUA_OK) { // LUA_ERRRUN / LUA_ERRMEM ? |
75 | { | ||
76 | raise_lua_error(L_); | 75 | raise_lua_error(L_); |
77 | } | 76 | } |
78 | // should be 1 for Lua <= 5.3, 1 or 2 starting with Lua 5.4 | 77 | // should be 1 for Lua <= 5.3, 1 or 2 starting with Lua 5.4 |
79 | return lua_gettop(L_); // result(s) | 78 | return lua_gettop(L_); // L_: result(s) |
80 | } | 79 | } |
81 | 80 | ||
82 | // ################################################################################################# | 81 | // ################################################################################################# |
83 | 82 | ||
84 | /* | 83 | /* |
85 | * Serialize calls to 'require', if it exists | 84 | * Serialize calls to 'require', if it exists |
86 | */ | 85 | */ |
87 | void serialize_require(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L_) | 86 | void serialize_require(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_) |
88 | { | 87 | { |
89 | STACK_GROW(L_, 1); | 88 | STACK_GROW(L_, 1); |
90 | STACK_CHECK_START_REL(L_, 0); | 89 | STACK_CHECK_START_REL(L_, 0); |
91 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "serializing require()\n" INDENT_END)); | 90 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "serializing require()\n" INDENT_END(U_))); |
92 | 91 | ||
93 | // Check 'require' is there and not already wrapped; if not, do nothing | 92 | // Check 'require' is there and not already wrapped; if not, do nothing |
94 | // | 93 | // |
95 | lua_getglobal(L_, "require"); | 94 | lua_getglobal(L_, "require"); |
96 | if (lua_isfunction(L_, -1) && lua_tocfunction(L_, -1) != luaG_new_require) | 95 | if (lua_isfunction(L_, -1) && lua_tocfunction(L_, -1) != luaG_new_require) { |
97 | { | ||
98 | // [-1]: original 'require' function | 96 | // [-1]: original 'require' function |
99 | lua_pushcclosure(L_, luaG_new_require, 1 /*upvalues*/); | 97 | lua_pushcclosure(L_, luaG_new_require, 1 /*upvalues*/); |
100 | lua_setglobal(L_, "require"); | 98 | lua_setglobal(L_, "require"); |
101 | } | 99 | } else { |
102 | else | ||
103 | { | ||
104 | // [-1]: nil | 100 | // [-1]: nil |
105 | lua_pop(L_, 1); | 101 | lua_pop(L_, 1); |
106 | } | 102 | } |
@@ -115,72 +111,67 @@ void serialize_require(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L_) | |||
115 | [[nodiscard]] static int require_lanes_core(lua_State* L_) | 111 | [[nodiscard]] static int require_lanes_core(lua_State* L_) |
116 | { | 112 | { |
117 | // leaves a copy of 'lanes.core' module table on the stack | 113 | // leaves a copy of 'lanes.core' module table on the stack |
118 | luaL_requiref( L_, "lanes.core", luaopen_lanes_core, 0); | 114 | luaL_requiref(L_, "lanes.core", luaopen_lanes_core, 0); |
119 | return 1; | 115 | return 1; |
120 | } | 116 | } |
121 | 117 | ||
122 | // ################################################################################################# | 118 | // ################################################################################################# |
123 | 119 | ||
124 | static luaL_Reg const libs[] = | 120 | static luaL_Reg const libs[] = { |
125 | { | 121 | { LUA_LOADLIBNAME, luaopen_package }, |
126 | { LUA_LOADLIBNAME, luaopen_package}, | 122 | { LUA_TABLIBNAME, luaopen_table }, |
127 | { LUA_TABLIBNAME, luaopen_table}, | 123 | { LUA_STRLIBNAME, luaopen_string }, |
128 | { LUA_STRLIBNAME, luaopen_string}, | 124 | { LUA_MATHLIBNAME, luaopen_math }, |
129 | { LUA_MATHLIBNAME, luaopen_math}, | ||
130 | #ifndef PLATFORM_XBOX // no os/io libs on xbox | 125 | #ifndef PLATFORM_XBOX // no os/io libs on xbox |
131 | { LUA_OSLIBNAME, luaopen_os}, | 126 | { LUA_OSLIBNAME, luaopen_os }, |
132 | { LUA_IOLIBNAME, luaopen_io}, | 127 | { LUA_IOLIBNAME, luaopen_io }, |
133 | #endif // PLATFORM_XBOX | 128 | #endif // PLATFORM_XBOX |
134 | #if LUA_VERSION_NUM >= 503 | 129 | #if LUA_VERSION_NUM >= 503 |
135 | { LUA_UTF8LIBNAME, luaopen_utf8}, | 130 | { LUA_UTF8LIBNAME, luaopen_utf8 }, |
136 | #endif | 131 | #endif |
137 | #if LUA_VERSION_NUM >= 502 | 132 | #if LUA_VERSION_NUM >= 502 |
138 | #ifdef luaopen_bit32 | 133 | #ifdef luaopen_bit32 |
139 | { LUA_BITLIBNAME, luaopen_bit32}, | 134 | { LUA_BITLIBNAME, luaopen_bit32 }, |
140 | #endif | 135 | #endif |
141 | { LUA_COLIBNAME, luaopen_coroutine}, // Lua 5.2: coroutine is no longer a part of base! | 136 | { LUA_COLIBNAME, luaopen_coroutine }, // Lua 5.2: coroutine is no longer a part of base! |
142 | #else // LUA_VERSION_NUM | 137 | #else // LUA_VERSION_NUM |
143 | { LUA_COLIBNAME, nullptr }, // Lua 5.1: part of base package | 138 | { LUA_COLIBNAME, nullptr }, // Lua 5.1: part of base package |
144 | #endif // LUA_VERSION_NUM | 139 | #endif // LUA_VERSION_NUM |
145 | { LUA_DBLIBNAME, luaopen_debug}, | 140 | { LUA_DBLIBNAME, luaopen_debug }, |
146 | #if LUAJIT_FLAVOR() != 0 // building against LuaJIT headers, add some LuaJIT-specific libs | 141 | #if LUAJIT_FLAVOR() != 0 // building against LuaJIT headers, add some LuaJIT-specific libs |
147 | //#pragma message( "supporting JIT base libs") | 142 | // #pragma message( "supporting JIT base libs") |
148 | { LUA_BITLIBNAME, luaopen_bit}, | 143 | { LUA_BITLIBNAME, luaopen_bit }, |
149 | { LUA_JITLIBNAME, luaopen_jit}, | 144 | { LUA_JITLIBNAME, luaopen_jit }, |
150 | { LUA_FFILIBNAME, luaopen_ffi}, | 145 | { LUA_FFILIBNAME, luaopen_ffi }, |
151 | #endif // LUAJIT_FLAVOR() | 146 | #endif // LUAJIT_FLAVOR() |
152 | 147 | ||
153 | { LUA_DBLIBNAME, luaopen_debug}, | 148 | { LUA_DBLIBNAME, luaopen_debug }, |
154 | { "lanes.core", require_lanes_core}, // So that we can open it like any base library (possible since we have access to the init function) | 149 | { "lanes.core", require_lanes_core }, // So that we can open it like any base library (possible since we have access to the init function) |
155 | // | 150 | // |
156 | { "base", nullptr }, // ignore "base" (already acquired it) | 151 | { "base", nullptr }, // ignore "base" (already acquired it) |
157 | { nullptr, nullptr } | 152 | { nullptr, nullptr } |
158 | }; | 153 | }; |
159 | 154 | ||
160 | // ################################################################################################# | 155 | // ################################################################################################# |
161 | 156 | ||
162 | static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_, char const* name_, size_t len_) | 157 | static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U_) lua_State* L_, char const* name_, size_t len_) |
163 | { | 158 | { |
164 | for (int i{ 0 }; libs[i].name; ++i) | 159 | for (int i{ 0 }; libs[i].name; ++i) { |
165 | { | 160 | if (strncmp(name_, libs[i].name, len_) == 0) { |
166 | if (strncmp( name_, libs[i].name, len_) == 0) | ||
167 | { | ||
168 | lua_CFunction libfunc = libs[i].func; | 161 | lua_CFunction libfunc = libs[i].func; |
169 | name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ | 162 | name_ = libs[i].name; // note that the provided name_ doesn't necessarily ends with '\0', hence len_ |
170 | if (libfunc != nullptr) | 163 | if (libfunc != nullptr) { |
171 | { | ||
172 | bool const isLanesCore{ libfunc == require_lanes_core }; // don't want to create a global for "lanes.core" | 164 | bool const isLanesCore{ libfunc == require_lanes_core }; // don't want to create a global for "lanes.core" |
173 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END, (int) len_, name_)); | 165 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening %.*s library\n" INDENT_END(U_), (int) len_, name_)); |
174 | STACK_CHECK_START_REL(L_, 0); | 166 | STACK_CHECK_START_REL(L_, 0); |
175 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) | 167 | // open the library as if through require(), and create a global as well if necessary (the library table is left on the stack) |
176 | luaL_requiref( L_, name_, libfunc, !isLanesCore); | 168 | luaL_requiref(L_, name_, libfunc, !isLanesCore); |
177 | // lanes.core doesn't declare a global, so scan it here and now | 169 | // lanes.core doesn't declare a global, so scan it here and now |
178 | if (isLanesCore == true) | 170 | if (isLanesCore == true) { |
179 | { | 171 | populate_func_lookup_table(L_, -1, name_); |
180 | populate_func_lookup_table( L_, -1, name_); | ||
181 | } | 172 | } |
182 | lua_pop( L_, 1); | 173 | lua_pop(L_, 1); |
183 | STACK_CHECK( L_, 0); | 174 | STACK_CHECK(L_, 0); |
184 | } | 175 | } |
185 | break; | 176 | break; |
186 | } | 177 | } |
@@ -190,90 +181,80 @@ static void open1lib(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L_, char cons | |||
190 | // ################################################################################################# | 181 | // ################################################################################################# |
191 | 182 | ||
192 | // just like lua_xmove, args are (from, to) | 183 | // just like lua_xmove, args are (from, to) |
193 | static void copy_one_time_settings(Universe* U, SourceState L1, DestState L2) | 184 | static void copy_one_time_settings(Universe* U_, SourceState L1_, DestState L2_) |
194 | { | 185 | { |
195 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 186 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); |
196 | 187 | ||
197 | STACK_GROW(L1, 2); | 188 | STACK_GROW(L1_, 2); |
198 | STACK_CHECK_START_REL(L1, 0); | 189 | STACK_CHECK_START_REL(L1_, 0); |
199 | STACK_CHECK_START_REL(L2, 0); | 190 | STACK_CHECK_START_REL(L2_, 0); |
200 | 191 | ||
201 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END)); | 192 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "copy_one_time_settings()\n" INDENT_END(U_))); |
202 | 193 | ||
203 | kConfigRegKey.pushValue(L1); // config | 194 | kConfigRegKey.pushValue(L1_); // L1_: config |
204 | // copy settings from from source to destination registry | 195 | // copy settings from from source to destination registry |
205 | InterCopyContext c{ U, L2, L1, {}, {}, {}, {}, {} }; | 196 | InterCopyContext c{ U_, L2_, L1_, {}, {}, {}, {}, {} }; |
206 | if (c.inter_move(1) != InterCopyResult::Success) // // config | 197 | if (c.inter_move(1) != InterCopyResult::Success) { // L1_: L2_: config |
207 | { | 198 | raise_luaL_error(L1_, "failed to copy settings when loading lanes.core"); |
208 | raise_luaL_error(L1, "failed to copy settings when loading lanes.core"); | ||
209 | } | 199 | } |
210 | // set L2:_R[kConfigRegKey] = settings | 200 | // set L2:_R[kConfigRegKey] = settings |
211 | kConfigRegKey.setValue(L2, [](lua_State* L_) { lua_insert(L_, -2); }); // config | 201 | kConfigRegKey.setValue(L2_, [](lua_State* L_) { lua_insert(L_, -2); }); // L1_: L2_: config |
212 | STACK_CHECK(L2, 0); | 202 | STACK_CHECK(L2_, 0); |
213 | STACK_CHECK(L1, 0); | 203 | STACK_CHECK(L1_, 0); |
214 | } | 204 | } |
215 | 205 | ||
216 | // ################################################################################################# | 206 | // ################################################################################################# |
217 | 207 | ||
218 | void initialize_on_state_create( Universe* U, lua_State* L_) | 208 | void initialize_on_state_create(Universe* U_, lua_State* L_) |
219 | { | 209 | { |
220 | STACK_CHECK_START_REL(L_, 1); // settings | 210 | STACK_CHECK_START_REL(L_, 1); // L_: settings |
221 | lua_getfield(L_, -1, "on_state_create"); // settings on_state_create|nil | 211 | lua_getfield(L_, -1, "on_state_create"); // L_: settings on_state_create|nil |
222 | if (!lua_isnil(L_, -1)) | 212 | if (!lua_isnil(L_, -1)) { |
223 | { | ||
224 | // store C function pointer in an internal variable | 213 | // store C function pointer in an internal variable |
225 | U->on_state_create_func = lua_tocfunction(L_, -1); // settings on_state_create | 214 | U_->on_state_create_func = lua_tocfunction(L_, -1); // L_: settings on_state_create |
226 | if (U->on_state_create_func != nullptr) | 215 | if (U_->on_state_create_func != nullptr) { |
227 | { | ||
228 | // make sure the function doesn't have upvalues | 216 | // make sure the function doesn't have upvalues |
229 | char const* upname = lua_getupvalue(L_, -1, 1); // settings on_state_create upval? | 217 | char const* upname = lua_getupvalue(L_, -1, 1); // L_: settings on_state_create upval? |
230 | if (upname != nullptr) // should be "" for C functions with upvalues if any | 218 | if (upname != nullptr) { // should be "" for C functions with upvalues if any |
231 | { | ||
232 | raise_luaL_error(L_, "on_state_create shouldn't have upvalues"); | 219 | raise_luaL_error(L_, "on_state_create shouldn't have upvalues"); |
233 | } | 220 | } |
234 | // remove this C function from the config table so that it doesn't cause problems | 221 | // remove this C function from the config table so that it doesn't cause problems |
235 | // when we transfer the config table in newly created Lua states | 222 | // when we transfer the config table in newly created Lua states |
236 | lua_pushnil(L_); // settings on_state_create nil | 223 | lua_pushnil(L_); // L_: settings on_state_create nil |
237 | lua_setfield(L_, -3, "on_state_create"); // settings on_state_create | 224 | lua_setfield(L_, -3, "on_state_create"); // L_: settings on_state_create |
238 | } | 225 | } else { |
239 | else | ||
240 | { | ||
241 | // optim: store marker saying we have such a function in the config table | 226 | // optim: store marker saying we have such a function in the config table |
242 | U->on_state_create_func = (lua_CFunction) initialize_on_state_create; | 227 | U_->on_state_create_func = (lua_CFunction) initialize_on_state_create; |
243 | } | 228 | } |
244 | } | 229 | } |
245 | lua_pop(L_, 1); // settings | 230 | lua_pop(L_, 1); // L_: settings |
246 | STACK_CHECK(L_, 1); | 231 | STACK_CHECK(L_, 1); |
247 | } | 232 | } |
248 | 233 | ||
249 | // ################################################################################################# | 234 | // ################################################################################################# |
250 | 235 | ||
251 | lua_State* create_state(Universe* U, lua_State* from_) | 236 | lua_State* create_state(Universe* U_, lua_State* from_) |
252 | { | 237 | { |
253 | lua_State* L; | 238 | lua_State* L; |
254 | #if LUAJIT_FLAVOR() == 64 | 239 | #if LUAJIT_FLAVOR() == 64 |
255 | // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... | 240 | // for some reason, LuaJIT 64 bits does not support creating a state with lua_newstate... |
256 | L = luaL_newstate(); | 241 | L = luaL_newstate(); |
257 | #else // LUAJIT_FLAVOR() == 64 | 242 | #else // LUAJIT_FLAVOR() == 64 |
258 | if (U->provide_allocator != nullptr) // we have a function we can call to obtain an allocator | 243 | if (U_->provide_allocator != nullptr) { // we have a function we can call to obtain an allocator |
259 | { | 244 | lua_pushcclosure(from_, U_->provide_allocator, 0); |
260 | lua_pushcclosure( from_, U->provide_allocator, 0); | 245 | lua_call(from_, 0, 1); |
261 | lua_call( from_, 0, 1); | ||
262 | { | 246 | { |
263 | AllocatorDefinition* const def{ lua_tofulluserdata<AllocatorDefinition>(from_, -1) }; | 247 | AllocatorDefinition* const def{ lua_tofulluserdata<AllocatorDefinition>(from_, -1) }; |
264 | L = lua_newstate( def->m_allocF, def->m_allocUD); | 248 | L = lua_newstate(def->m_allocF, def->m_allocUD); |
265 | } | 249 | } |
266 | lua_pop( from_, 1); | 250 | lua_pop(from_, 1); |
267 | } | 251 | } else { |
268 | else | ||
269 | { | ||
270 | // reuse the allocator provided when the master state was created | 252 | // reuse the allocator provided when the master state was created |
271 | L = lua_newstate(U->protected_allocator.m_allocF, U->protected_allocator.m_allocUD); | 253 | L = lua_newstate(U_->protected_allocator.m_allocF, U_->protected_allocator.m_allocUD); |
272 | } | 254 | } |
273 | #endif // LUAJIT_FLAVOR() == 64 | 255 | #endif // LUAJIT_FLAVOR() == 64 |
274 | 256 | ||
275 | if (L == nullptr) | 257 | if (L == nullptr) { |
276 | { | ||
277 | raise_luaL_error(from_, "luaG_newstate() failed while creating state; out of memory"); | 258 | raise_luaL_error(from_, "luaG_newstate() failed while creating state; out of memory"); |
278 | } | 259 | } |
279 | return L; | 260 | return L; |
@@ -281,35 +262,29 @@ lua_State* create_state(Universe* U, lua_State* from_) | |||
281 | 262 | ||
282 | // ################################################################################################# | 263 | // ################################################################################################# |
283 | 264 | ||
284 | void call_on_state_create(Universe* U, lua_State* L_, lua_State* from_, LookupMode mode_) | 265 | void call_on_state_create(Universe* U_, lua_State* L_, lua_State* from_, LookupMode mode_) |
285 | { | 266 | { |
286 | if (U->on_state_create_func != nullptr) | 267 | if (U_->on_state_create_func != nullptr) { |
287 | { | ||
288 | STACK_CHECK_START_REL(L_, 0); | 268 | STACK_CHECK_START_REL(L_, 0); |
289 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END)); | 269 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "calling on_state_create()\n" INDENT_END(U_))); |
290 | if (U->on_state_create_func != (lua_CFunction) initialize_on_state_create) | 270 | if (U_->on_state_create_func != (lua_CFunction) initialize_on_state_create) { |
291 | { | ||
292 | // C function: recreate a closure in the new state, bypassing the lookup scheme | 271 | // C function: recreate a closure in the new state, bypassing the lookup scheme |
293 | lua_pushcfunction(L_, U->on_state_create_func); // on_state_create() | 272 | lua_pushcfunction(L_, U_->on_state_create_func); // on_state_create() |
294 | } | 273 | } else { // Lua function located in the config table, copied when we opened "lanes.core" |
295 | else // Lua function located in the config table, copied when we opened "lanes.core" | 274 | if (mode_ != LookupMode::LaneBody) { |
296 | { | ||
297 | if (mode_ != LookupMode::LaneBody) | ||
298 | { | ||
299 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there | 275 | // if attempting to call in a keeper state, do nothing because the function doesn't exist there |
300 | // this doesn't count as an error though | 276 | // this doesn't count as an error though |
301 | STACK_CHECK(L_, 0); | 277 | STACK_CHECK(L_, 0); |
302 | return; | 278 | return; |
303 | } | 279 | } |
304 | kConfigRegKey.pushValue(L_); // {} | 280 | kConfigRegKey.pushValue(L_); // L_: {} |
305 | STACK_CHECK(L_, 1); | 281 | STACK_CHECK(L_, 1); |
306 | lua_getfield(L_, -1, "on_state_create"); // {} on_state_create() | 282 | lua_getfield(L_, -1, "on_state_create"); // L_: {} on_state_create() |
307 | lua_remove(L_, -2); // on_state_create() | 283 | lua_remove(L_, -2); // L_: on_state_create() |
308 | } | 284 | } |
309 | STACK_CHECK(L_, 1); | 285 | STACK_CHECK(L_, 1); |
310 | // capture error and raise it in caller state | 286 | // capture error and raise it in caller state |
311 | if (lua_pcall(L_, 0, 0, 0) != LUA_OK) | 287 | if (lua_pcall(L_, 0, 0, 0) != LUA_OK) { |
312 | { | ||
313 | raise_luaL_error(from_, "on_state_create failed: \"%s\"", lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1))); | 288 | raise_luaL_error(from_, "on_state_create failed: \"%s\"", lua_isstring(L_, -1) ? lua_tostring(L_, -1) : lua_typename(L_, lua_type(L_, -1))); |
314 | } | 289 | } |
315 | STACK_CHECK(L_, 0); | 290 | STACK_CHECK(L_, 0); |
@@ -319,28 +294,28 @@ void call_on_state_create(Universe* U, lua_State* L_, lua_State* from_, LookupMo | |||
319 | // ################################################################################################# | 294 | // ################################################################################################# |
320 | 295 | ||
321 | /* | 296 | /* |
322 | * Like 'luaL_openlibs()' but allows the set of libraries be selected | 297 | * Like 'luaL_openlibs()' but allows the set of libraries be selected |
323 | * | 298 | * |
324 | * nullptr no libraries, not even base | 299 | * nullptr no libraries, not even base |
325 | * "" base library only | 300 | * "" base library only |
326 | * "io,string" named libraries | 301 | * "io,string" named libraries |
327 | * "*" all libraries | 302 | * "*" all libraries |
328 | * | 303 | * |
329 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is nullptr. | 304 | * Base ("unpack", "print" etc.) is always added, unless 'libs' is nullptr. |
330 | * | 305 | * |
331 | * *NOT* called for keeper states! | 306 | * *NOT* called for keeper states! |
332 | * | 307 | * |
333 | */ | 308 | */ |
334 | lua_State* luaG_newstate(Universe* U, SourceState from_, char const* libs_) | 309 | lua_State* luaG_newstate(Universe* U_, SourceState from_, char const* libs_) |
335 | { | 310 | { |
336 | DestState const L{ create_state(U, from_) }; | 311 | DestState const L{ create_state(U_, from_) }; |
337 | 312 | ||
338 | STACK_GROW(L, 2); | 313 | STACK_GROW(L, 2); |
339 | STACK_CHECK_START_ABS(L, 0); | 314 | STACK_CHECK_START_ABS(L, 0); |
340 | 315 | ||
341 | // copy the universe as a light userdata (only the master state holds the full userdata) | 316 | // copy the universe as a light userdata (only the master state holds the full userdata) |
342 | // that way, if Lanes is required in this new state, we'll know we are part of this universe | 317 | // that way, if Lanes is required in this new state, we'll know we are part of this universe |
343 | universe_store( L, U); | 318 | universe_store(L, U_); |
344 | STACK_CHECK(L, 0); | 319 | STACK_CHECK(L, 0); |
345 | 320 | ||
346 | // we'll need this every time we transfer some C function from/to this state | 321 | // we'll need this every time we transfer some C function from/to this state |
@@ -348,76 +323,68 @@ lua_State* luaG_newstate(Universe* U, SourceState from_, char const* libs_) | |||
348 | STACK_CHECK(L, 0); | 323 | STACK_CHECK(L, 0); |
349 | 324 | ||
350 | // neither libs (not even 'base') nor special init func: we are done | 325 | // neither libs (not even 'base') nor special init func: we are done |
351 | if (libs_ == nullptr && U->on_state_create_func == nullptr) | 326 | if (libs_ == nullptr && U_->on_state_create_func == nullptr) { |
352 | { | 327 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "luaG_newstate(nullptr)\n" INDENT_END(U_))); |
353 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "luaG_newstate(nullptr)\n" INDENT_END)); | ||
354 | return L; | 328 | return L; |
355 | } | 329 | } |
356 | 330 | ||
357 | DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END)); | 331 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "luaG_newstate()\n" INDENT_END(U_))); |
358 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 332 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U_ }); |
359 | 333 | ||
360 | // copy settings (for example because it may contain a Lua on_state_create function) | 334 | // copy settings (for example because it may contain a Lua on_state_create function) |
361 | copy_one_time_settings( U, from_, L); | 335 | copy_one_time_settings(U_, from_, L); |
362 | 336 | ||
363 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) | 337 | // 'lua.c' stops GC during initialization so perhaps its a good idea. :) |
364 | lua_gc(L, LUA_GCSTOP, 0); | 338 | lua_gc(L, LUA_GCSTOP, 0); |
365 | 339 | ||
366 | |||
367 | // Anything causes 'base' to be taken in | 340 | // Anything causes 'base' to be taken in |
368 | // | 341 | // |
369 | if (libs_ != nullptr) | 342 | if (libs_ != nullptr) { |
370 | { | ||
371 | // special "*" case (mainly to help with LuaJIT compatibility) | 343 | // special "*" case (mainly to help with LuaJIT compatibility) |
372 | // as we are called from luaopen_lanes_core() already, and that would deadlock | 344 | // as we are called from luaopen_lanes_core() already, and that would deadlock |
373 | if (libs_[0] == '*' && libs_[1] == 0) | 345 | if (libs_[0] == '*' && libs_[1] == 0) { |
374 | { | 346 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END(U_))); |
375 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening ALL standard libraries\n" INDENT_END)); | 347 | luaL_openlibs(L); |
376 | luaL_openlibs( L); | ||
377 | // don't forget lanes.core for regular lane states | 348 | // don't forget lanes.core for regular lane states |
378 | open1lib( DEBUGSPEW_PARAM_COMMA( U) L, "lanes.core", 10); | 349 | open1lib(DEBUGSPEW_PARAM_COMMA(U_) L, "lanes.core", 10); |
379 | libs_ = nullptr; // done with libs | 350 | libs_ = nullptr; // done with libs |
380 | } | 351 | } else { |
381 | else | 352 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "opening base library\n" INDENT_END(U_))); |
382 | { | ||
383 | DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "opening base library\n" INDENT_END)); | ||
384 | #if LUA_VERSION_NUM >= 502 | 353 | #if LUA_VERSION_NUM >= 502 |
385 | // open base library the same way as in luaL_openlibs() | 354 | // open base library the same way as in luaL_openlibs() |
386 | luaL_requiref( L, "_G", luaopen_base, 1); | 355 | luaL_requiref(L, "_G", luaopen_base, 1); |
387 | lua_pop( L, 1); | 356 | lua_pop(L, 1); |
388 | #else // LUA_VERSION_NUM | 357 | #else // LUA_VERSION_NUM |
389 | lua_pushcfunction( L, luaopen_base); | 358 | lua_pushcfunction(L, luaopen_base); |
390 | lua_pushstring( L, ""); | 359 | lua_pushstring(L, ""); |
391 | lua_call( L, 1, 0); | 360 | lua_call(L, 1, 0); |
392 | #endif // LUA_VERSION_NUM | 361 | #endif // LUA_VERSION_NUM |
393 | } | 362 | } |
394 | } | 363 | } |
395 | STACK_CHECK(L, 0); | 364 | STACK_CHECK(L, 0); |
396 | 365 | ||
397 | // scan all libraries, open them one by one | 366 | // scan all libraries, open them one by one |
398 | if (libs_) | 367 | if (libs_) { |
399 | { | ||
400 | unsigned int len{ 0 }; | 368 | unsigned int len{ 0 }; |
401 | for (char const* p{ libs_ }; *p; p += len) | 369 | for (char const* p{ libs_ }; *p; p += len) { |
402 | { | ||
403 | // skip delimiters ('.' can be part of name for "lanes.core") | 370 | // skip delimiters ('.' can be part of name for "lanes.core") |
404 | while( *p && !isalnum(*p) && *p != '.') | 371 | while (*p && !isalnum(*p) && *p != '.') |
405 | ++ p; | 372 | ++p; |
406 | // skip name | 373 | // skip name |
407 | len = 0; | 374 | len = 0; |
408 | while( isalnum(p[len]) || p[len] == '.') | 375 | while (isalnum(p[len]) || p[len] == '.') |
409 | ++ len; | 376 | ++len; |
410 | // open library | 377 | // open library |
411 | open1lib(DEBUGSPEW_PARAM_COMMA( U) L, p, len); | 378 | open1lib(DEBUGSPEW_PARAM_COMMA(U_) L, p, len); |
412 | } | 379 | } |
413 | } | 380 | } |
414 | lua_gc(L, LUA_GCRESTART, 0); | 381 | lua_gc(L, LUA_GCRESTART, 0); |
415 | 382 | ||
416 | serialize_require(DEBUGSPEW_PARAM_COMMA( U) L); | 383 | serialize_require(DEBUGSPEW_PARAM_COMMA(U_) L); |
417 | 384 | ||
418 | // call this after the base libraries are loaded and GC is restarted | 385 | // call this after the base libraries are loaded and GC is restarted |
419 | // will raise an error in from_ in case of problem | 386 | // will raise an error in from_ in case of problem |
420 | call_on_state_create(U, L, from_, LookupMode::LaneBody); | 387 | call_on_state_create(U_, L, from_, LookupMode::LaneBody); |
421 | 388 | ||
422 | STACK_CHECK(L, 0); | 389 | STACK_CHECK(L, 0); |
423 | // after all this, register everything we find in our name<->function database | 390 | // after all this, register everything we find in our name<->function database |
@@ -427,18 +394,18 @@ lua_State* luaG_newstate(Universe* U, SourceState from_, char const* libs_) | |||
427 | 394 | ||
428 | #if 1 && USE_DEBUG_SPEW() | 395 | #if 1 && USE_DEBUG_SPEW() |
429 | // dump the lookup database contents | 396 | // dump the lookup database contents |
430 | kLookupRegKey.pushValue(L); // {} | 397 | kLookupRegKey.pushValue(L); // L: {} |
431 | lua_pushnil(L); // {} nil | 398 | lua_pushnil(L); // L: {} nil |
432 | while (lua_next(L, -2)) // {} k v | 399 | while (lua_next(L, -2)) { // L: {} k v |
433 | { | 400 | lua_getglobal(L, "print"); // L: {} k v print |
434 | lua_getglobal(L, "print"); // {} k v print | 401 | int const indent{ U_->debugspew_indent_depth.load(std::memory_order_relaxed) }; |
435 | lua_pushlstring(L, DebugSpewIndentScope::debugspew_indent, U->debugspew_indent_depth.load(std::memory_order_relaxed)); // {} k v print " " | 402 | lua_pushlstring(L, DebugSpewIndentScope::debugspew_indent, indent); // L: {} k v print " " |
436 | lua_pushvalue(L, -4); // {} k v print " " k | 403 | lua_pushvalue(L, -4); // L: {} k v print " " k |
437 | lua_pushvalue(L, -4); // {} k v print " " k v | 404 | lua_pushvalue(L, -4); // L: {} k v print " " k v |
438 | lua_call(L, 3, 0); // {} k v | 405 | lua_call(L, 3, 0); // L: {} k v |
439 | lua_pop(L, 1); // {} k | 406 | lua_pop(L, 1); // L: {} k |
440 | } | 407 | } |
441 | lua_pop(L, 1); // {} | 408 | lua_pop(L, 1); // L: {} |
442 | #endif // USE_DEBUG_SPEW() | 409 | #endif // USE_DEBUG_SPEW() |
443 | 410 | ||
444 | lua_pop(L, 1); | 411 | lua_pop(L, 1); |