aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp669
1 files changed, 298 insertions, 371 deletions
diff --git a/src/tools.cpp b/src/tools.cpp
index ad706be..cd25eda 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -35,13 +35,12 @@ THE SOFTWARE.
35 35
36#include "universe.h" 36#include "universe.h"
37 37
38// functions implemented in deep.c
39extern void push_registry_subtable( lua_State* L, UniqueKey key_);
40
41DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+"); 38DEBUGSPEW_CODE(char const* const DebugSpewIndentScope::debugspew_indent = "----+----!----+----!----+----!----+----!----+----!----+----!----+----!----+");
42 39
40// crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/
41static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull };
43 42
44// ################################################################################################ 43// #################################################################################################
45 44
46/* 45/*
47 * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it 46 * Does what the original 'push_registry_subtable' function did, but adds an optional mode argument to it
@@ -76,7 +75,7 @@ void push_registry_subtable_mode( lua_State* L, UniqueKey key_, const char* mode
76 ASSERT_L(lua_istable(L, -1)); 75 ASSERT_L(lua_istable(L, -1));
77} 76}
78 77
79// ################################################################################################ 78// #################################################################################################
80 79
81/* 80/*
82 * Push a registry subtable (keyed by unique 'key_') onto the stack. 81 * Push a registry subtable (keyed by unique 'key_') onto the stack.
@@ -87,60 +86,7 @@ void push_registry_subtable( lua_State* L, UniqueKey key_)
87 push_registry_subtable_mode(L, key_, nullptr); 86 push_registry_subtable_mode(L, key_, nullptr);
88} 87}
89 88
90// ################################################################################################ 89// #################################################################################################
91
92/*---=== luaG_dump ===---*/
93#ifdef _DEBUG
94void luaG_dump( lua_State* L)
95{
96 int top = lua_gettop( L);
97 int i;
98
99 fprintf( stderr, "\n\tDEBUG STACK:\n");
100
101 if( top == 0)
102 fprintf( stderr, "\t(none)\n");
103
104 for( i = 1; i <= top; ++ i)
105 {
106 LuaType type{ lua_type_as_enum(L, i) };
107
108 fprintf( stderr, "\t[%d]= (%s) ", i, lua_typename( L, type));
109
110 // Print item contents here...
111 //
112 // Note: this requires 'tostring()' to be defined. If it is NOT,
113 // enable it for more debugging.
114 //
115 STACK_CHECK_START_REL(L, 0);
116 STACK_GROW( L, 2);
117
118 lua_getglobal( L, "tostring");
119 //
120 // [-1]: tostring function, or nil
121
122 if( !lua_isfunction( L, -1))
123 {
124 fprintf( stderr, "('tostring' not available)");
125 }
126 else
127 {
128 lua_pushvalue( L, i);
129 lua_call( L, 1 /*args*/, 1 /*retvals*/);
130
131 // Don't trust the string contents
132 //
133 fprintf( stderr, "%s", lua_tostring( L, -1));
134 }
135 lua_pop( L, 1);
136 STACK_CHECK( L, 0);
137 fprintf( stderr, "\n");
138 }
139 fprintf( stderr, "\n");
140}
141#endif // _DEBUG
142
143// ################################################################################################
144 90
145// same as PUC-Lua l_alloc 91// same as PUC-Lua l_alloc
146extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_) 92extern "C" [[nodiscard]] static void* libc_lua_Alloc([[maybe_unused]] void* ud, [[maybe_unused]] void* ptr_, [[maybe_unused]] size_t osize_, size_t nsize_)
@@ -231,7 +177,7 @@ void initialize_allocator_function(Universe* U, lua_State* L)
231 STACK_CHECK(L, 1); 177 STACK_CHECK(L, 1);
232} 178}
233 179
234// ################################################################################################ 180// #################################################################################################
235 181
236[[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud) 182[[nodiscard]] static int dummy_writer(lua_State* L, void const* p, size_t sz, void* ud)
237{ 183{
@@ -239,7 +185,6 @@ void initialize_allocator_function(Universe* U, lua_State* L)
239 return 666; 185 return 666;
240} 186}
241 187
242
243/* 188/*
244 * differentiation between C, bytecode and JIT-fast functions 189 * differentiation between C, bytecode and JIT-fast functions
245 * 190 *
@@ -262,25 +207,25 @@ enum FuncSubType
262 FST_FastJIT 207 FST_FastJIT
263} ; 208} ;
264 209
265FuncSubType luaG_getfuncsubtype( lua_State *L, int _i) 210FuncSubType luaG_getfuncsubtype(lua_State* L, int _i)
266{ 211{
267 if( lua_tocfunction( L, _i)) 212 if (lua_tocfunction(L, _i)) // nullptr for LuaJIT-fast && bytecode functions
268 { 213 {
269 return FST_Native; 214 return FST_Native;
270 } 215 }
271 { 216 {
272 int mustpush = 0, dumpres; 217 int mustpush{ 0 };
273 if( lua_absindex( L, _i) != lua_gettop( L)) 218 if (lua_absindex(L, _i) != lua_gettop(L))
274 { 219 {
275 lua_pushvalue( L, _i); 220 lua_pushvalue(L, _i);
276 mustpush = 1; 221 mustpush = 1;
277 } 222 }
278 // the provided writer fails with code 666 223 // the provided writer fails with code 666
279 // therefore, anytime we get 666, this means that lua_dump() attempted a dump 224 // therefore, anytime we get 666, this means that lua_dump() attempted a dump
280 // all other cases mean this is either a C or LuaJIT-fast function 225 // all other cases mean this is either a C or LuaJIT-fast function
281 dumpres = lua504_dump(L, dummy_writer, nullptr, 0); 226 int const dumpres{ lua504_dump(L, dummy_writer, nullptr, 0) };
282 lua_pop( L, mustpush); 227 lua_pop(L, mustpush);
283 if( dumpres == 666) 228 if (dumpres == 666)
284 { 229 {
285 return FST_Bytecode; 230 return FST_Bytecode;
286 } 231 }
@@ -290,40 +235,28 @@ FuncSubType luaG_getfuncsubtype( lua_State *L, int _i)
290 235
291// ################################################################################################# 236// #################################################################################################
292 237
293[[nodiscard]] static lua_CFunction luaG_tocfunction(lua_State* L, int _i, FuncSubType* _out)
294{
295 lua_CFunction p = lua_tocfunction( L, _i);
296 *_out = luaG_getfuncsubtype( L, _i);
297 return p;
298}
299
300// crc64/we of string "LOOKUPCACHE_REGKEY" generated at http://www.nitrxgen.net/hashgen/
301static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull };
302
303// #################################################################################################
304
305// inspired from tconcat() in ltablib.c 238// inspired from tconcat() in ltablib.c
306[[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length) 239[[nodiscard]] static char const* luaG_pushFQN(lua_State* L, int t, int last, size_t* length)
307{ 240{
308 int i = 1;
309 luaL_Buffer b; 241 luaL_Buffer b;
310 STACK_CHECK_START_REL(L, 0); 242 STACK_CHECK_START_REL(L, 0);
311 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it... 243 // Lua 5.4 pushes &b as light userdata on the stack. be aware of it...
312 luaL_buffinit( L, &b); // ... {} ... &b? 244 luaL_buffinit(L, &b); // ... {} ... &b?
313 for( ; i < last; ++ i) 245 int i = 1;
246 for (; i < last; ++i)
314 { 247 {
315 lua_rawgeti( L, t, i); 248 lua_rawgeti( L, t, i);
316 luaL_addvalue( &b); 249 luaL_addvalue( &b);
317 luaL_addlstring(&b, "/", 1); 250 luaL_addlstring(&b, "/", 1);
318 } 251 }
319 if( i == last) // add last value (if interval was not empty) 252 if (i == last) // add last value (if interval was not empty)
320 { 253 {
321 lua_rawgeti( L, t, i); 254 lua_rawgeti(L, t, i);
322 luaL_addvalue( &b); 255 luaL_addvalue(&b);
323 } 256 }
324 // &b is popped at that point (-> replaced by the result) 257 // &b is popped at that point (-> replaced by the result)
325 luaL_pushresult( &b); // ... {} ... "<result>" 258 luaL_pushresult(&b); // ... {} ... "<result>"
326 STACK_CHECK( L, 1); 259 STACK_CHECK(L, 1);
327 return lua_tolstring( L, -1, length); 260 return lua_tolstring( L, -1, length);
328} 261}
329 262
@@ -337,12 +270,12 @@ static constexpr UniqueKey LOOKUPCACHE_REGKEY{ 0x837a68dfc6fcb716ull };
337 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter 270 * if we already had an entry of type [o] = ..., replace the name if the new one is shorter
338 * pops the processed object from the stack 271 * pops the processed object from the stack
339 */ 272 */
340static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L, int _ctx_base, int _depth) 273static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _depth)
341{ 274{
342 // slot 1 in the stack contains the table that receives everything we found 275 // slot 1 in the stack contains the table that receives everything we found
343 int const dest = _ctx_base; 276 int const dest{ _ctx_base };
344 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i 277 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i
345 int const fqn = _ctx_base + 1; 278 int const fqn{ _ctx_base + 1 };
346 279
347 size_t prevNameLength, newNameLength; 280 size_t prevNameLength, newNameLength;
348 char const* prevName; 281 char const* prevName;
@@ -352,16 +285,16 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L
352 285
353 STACK_CHECK_START_REL(L, 0); 286 STACK_CHECK_START_REL(L, 0);
354 // first, raise an error if the function is already known 287 // first, raise an error if the function is already known
355 lua_pushvalue( L, -1); // ... {bfc} k o o 288 lua_pushvalue(L, -1); // ... {bfc} k o o
356 lua_rawget( L, dest); // ... {bfc} k o name? 289 lua_rawget(L, dest); // ... {bfc} k o name?
357 prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object) 290 prevName = lua_tolstring( L, -1, &prevNameLength); // nullptr if we got nil (first encounter of this object)
358 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 291 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
359 lua_pushvalue( L, -3); // ... {bfc} k o name? k 292 lua_pushvalue(L, -3); // ... {bfc} k o name? k
360 ASSERT_L( lua_type( L, -1) == LUA_TNUMBER || lua_type( L, -1) == LUA_TSTRING); 293 ASSERT_L(lua_type(L, -1) == LUA_TNUMBER || lua_type(L, -1) == LUA_TSTRING);
361 ++ _depth; 294 ++_depth;
362 lua_rawseti( L, fqn, _depth); // ... {bfc} k o name? 295 lua_rawseti(L, fqn, _depth); // ... {bfc} k o name?
363 // generate name 296 // generate name
364 DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength);// ... {bfc} k o name? "f.q.n" 297 DEBUGSPEW_OR_NOT(newName, std::ignore) = luaG_pushFQN(L, fqn, _depth, &newNameLength); // ... {bfc} k o name? "f.q.n"
365 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order 298 // Lua 5.2 introduced a hash randomizer seed which causes table iteration to yield a different key order
366 // on different VMs even when the tables are populated the exact same way. 299 // on different VMs even when the tables are populated the exact same way.
367 // When Lua is built with compatibility options (such as LUA_COMPAT_ALL), 300 // When Lua is built with compatibility options (such as LUA_COMPAT_ALL),
@@ -375,36 +308,36 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L
375 { 308 {
376 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName)); 309 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s' remained named '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -3)), newName, prevName));
377 // the previous name is 'smaller' than the one we just generated: keep it! 310 // the previous name is 'smaller' than the one we just generated: keep it!
378 lua_pop( L, 3); // ... {bfc} k 311 lua_pop(L, 3); // ... {bfc} k
379 } 312 }
380 else 313 else
381 { 314 {
382 // the name we generated is either the first one, or a better fit for our purposes 315 // the name we generated is either the first one, or a better fit for our purposes
383 if( prevName) 316 if (prevName)
384 { 317 {
385 // clear the previous name for the database to avoid clutter 318 // clear the previous name for the database to avoid clutter
386 lua_insert( L, -2); // ... {bfc} k o "f.q.n" prevName 319 lua_insert(L, -2); // ... {bfc} k o "f.q.n" prevName
387 // t[prevName] = nil 320 // t[prevName] = nil
388 lua_pushnil( L); // ... {bfc} k o "f.q.n" prevName nil 321 lua_pushnil(L); // ... {bfc} k o "f.q.n" prevName nil
389 lua_rawset( L, dest); // ... {bfc} k o "f.q.n" 322 lua_rawset(L, dest); // ... {bfc} k o "f.q.n"
390 } 323 }
391 else 324 else
392 { 325 {
393 lua_remove( L, -2); // ... {bfc} k o "f.q.n" 326 lua_remove(L, -2); // ... {bfc} k o "f.q.n"
394 } 327 }
395 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename( L, lua_type( L, -2)), newName)); 328 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%s '%s'\n" INDENT_END, lua_typename(L, lua_type( L, -2)), newName));
396 // prepare the stack for database feed 329 // prepare the stack for database feed
397 lua_pushvalue( L, -1); // ... {bfc} k o "f.q.n" "f.q.n" 330 lua_pushvalue(L, -1); // ... {bfc} k o "f.q.n" "f.q.n"
398 lua_pushvalue( L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o 331 lua_pushvalue(L, -3); // ... {bfc} k o "f.q.n" "f.q.n" o
399 ASSERT_L( lua_rawequal( L, -1, -4)); 332 ASSERT_L(lua_rawequal(L, -1, -4));
400 ASSERT_L( lua_rawequal( L, -2, -3)); 333 ASSERT_L(lua_rawequal(L, -2, -3));
401 // t["f.q.n"] = o 334 // t["f.q.n"] = o
402 lua_rawset( L, dest); // ... {bfc} k o "f.q.n" 335 lua_rawset(L, dest); // ... {bfc} k o "f.q.n"
403 // t[o] = "f.q.n" 336 // t[o] = "f.q.n"
404 lua_rawset( L, dest); // ... {bfc} k 337 lua_rawset(L, dest); // ... {bfc} k
405 // remove table name from fqn stack 338 // remove table name from fqn stack
406 lua_pushnil( L); // ... {bfc} k nil 339 lua_pushnil(L); // ... {bfc} k nil
407 lua_rawseti( L, fqn, _depth); // ... {bfc} k 340 lua_rawseti(L, fqn, _depth); // ... {bfc} k
408 } 341 }
409 -- _depth; 342 -- _depth;
410 STACK_CHECK(L, -1); 343 STACK_CHECK(L, -1);
@@ -414,122 +347,121 @@ static void update_lookup_entry(DEBUGSPEW_PARAM_COMMA( Universe* U) lua_State* L
414 347
415static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth) 348static void populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(Universe* U) lua_State* L, int _ctx_base, int _i, int _depth)
416{ 349{
417 lua_Integer visit_count;
418 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i 350 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i
419 int const fqn = _ctx_base + 1; 351 int const fqn = _ctx_base + 1;
420 // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops 352 // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops
421 int const cache = _ctx_base + 2; 353 int const cache = _ctx_base + 2;
422 // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search) 354 // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search)
423 int const breadth_first_cache = lua_gettop( L) + 1; 355 int const breadth_first_cache = lua_gettop(L) + 1;
424 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END)); 356 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "populate_func_lookup_table_recur()\n" INDENT_END));
425 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 357 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
426 358
427 STACK_GROW( L, 6); 359 STACK_GROW(L, 6);
428 // slot _i contains a table where we search for functions (or a full userdata with a metatable) 360 // slot _i contains a table where we search for functions (or a full userdata with a metatable)
429 STACK_CHECK_START_REL(L, 0); // ... {_i} 361 STACK_CHECK_START_REL(L, 0); // ... {_i}
430 362
431 // if object is a userdata, replace it by its metatable 363 // if object is a userdata, replace it by its metatable
432 if( lua_type( L, _i) == LUA_TUSERDATA) 364 if (lua_type(L, _i) == LUA_TUSERDATA)
433 { 365 {
434 lua_getmetatable( L, _i); // ... {_i} mt 366 lua_getmetatable(L, _i); // ... {_i} mt
435 lua_replace( L, _i); // ... {_i} 367 lua_replace(L, _i); // ... {_i}
436 } 368 }
437 369
438 // if table is already visited, we are done 370 // if table is already visited, we are done
439 lua_pushvalue( L, _i); // ... {_i} {} 371 lua_pushvalue(L, _i); // ... {_i} {}
440 lua_rawget( L, cache); // ... {_i} nil|n 372 lua_rawget(L, cache); // ... {_i} nil|n
441 visit_count = lua_tointeger( L, -1); // 0 if nil, else n 373 lua_Integer visit_count{ lua_tointeger(L, -1) }; // 0 if nil, else n
442 lua_pop( L, 1); // ... {_i} 374 lua_pop(L, 1); // ... {_i}
443 STACK_CHECK( L, 0); 375 STACK_CHECK(L, 0);
444 if( visit_count > 0) 376 if (visit_count > 0)
445 { 377 {
446 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END)); 378 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "already visited\n" INDENT_END));
447 return; 379 return;
448 } 380 }
449 381
450 // remember we visited this table (1-visit count) 382 // remember we visited this table (1-visit count)
451 lua_pushvalue( L, _i); // ... {_i} {} 383 lua_pushvalue(L, _i); // ... {_i} {}
452 lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1 384 lua_pushinteger(L, visit_count + 1); // ... {_i} {} 1
453 lua_rawset( L, cache); // ... {_i} 385 lua_rawset(L, cache); // ... {_i}
454 STACK_CHECK( L, 0); 386 STACK_CHECK(L, 0);
455 387
456 // this table is at breadth_first_cache index 388 // this table is at breadth_first_cache index
457 lua_newtable( L); // ... {_i} {bfc} 389 lua_newtable(L); // ... {_i} {bfc}
458 ASSERT_L( lua_gettop( L) == breadth_first_cache); 390 ASSERT_L( lua_gettop(L) == breadth_first_cache);
459 // iterate over all entries in the processed table 391 // iterate over all entries in the processed table
460 lua_pushnil( L); // ... {_i} {bfc} nil 392 lua_pushnil(L); // ... {_i} {bfc} nil
461 while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v 393 while( lua_next(L, _i) != 0) // ... {_i} {bfc} k v
462 { 394 {
463 // just for debug, not actually needed 395 // just for debug, not actually needed
464 //char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"; 396 //char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string";
465 // subtable: process it recursively 397 // subtable: process it recursively
466 if( lua_istable( L, -1)) // ... {_i} {bfc} k {} 398 if (lua_istable(L, -1)) // ... {_i} {bfc} k {}
467 { 399 {
468 // increment visit count to make sure we will actually scan it at this recursive level 400 // increment visit count to make sure we will actually scan it at this recursive level
469 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} 401 lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {}
470 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {} 402 lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {} {}
471 lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n? 403 lua_rawget(L, cache); // ... {_i} {bfc} k {} {} n?
472 visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1 404 visit_count = lua_tointeger(L, -1) + 1; // 1 if we got nil, else n+1
473 lua_pop( L, 1); // ... {_i} {bfc} k {} {} 405 lua_pop(L, 1); // ... {_i} {bfc} k {} {}
474 lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n 406 lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n
475 lua_rawset( L, cache); // ... {_i} {bfc} k {} 407 lua_rawset(L, cache); // ... {_i} {bfc} k {}
476 // store the table in the breadth-first cache 408 // store the table in the breadth-first cache
477 lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k 409 lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k
478 lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k {} 410 lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k {}
479 lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k {} 411 lua_rawset(L, breadth_first_cache); // ... {_i} {bfc} k {}
480 // generate a name, and if we already had one name, keep whichever is the shorter 412 // generate a name, and if we already had one name, keep whichever is the shorter
481 update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k 413 update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k
482 } 414 }
483 else if( lua_isfunction( L, -1) && (luaG_getfuncsubtype( L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func 415 else if (lua_isfunction(L, -1) && (luaG_getfuncsubtype(L, -1) != FST_Bytecode)) // ... {_i} {bfc} k func
484 { 416 {
485 // generate a name, and if we already had one name, keep whichever is the shorter 417 // generate a name, and if we already had one name, keep whichever is the shorter
486 update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, _depth); // ... {_i} {bfc} k 418 update_lookup_entry( DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, _depth); // ... {_i} {bfc} k
487 } 419 }
488 else 420 else
489 { 421 {
490 lua_pop( L, 1); // ... {_i} {bfc} k 422 lua_pop(L, 1); // ... {_i} {bfc} k
491 } 423 }
492 STACK_CHECK( L, 2); 424 STACK_CHECK(L, 2);
493 } 425 }
494 // now process the tables we encountered at that depth 426 // now process the tables we encountered at that depth
495 ++ _depth; 427 ++ _depth;
496 lua_pushnil( L); // ... {_i} {bfc} nil 428 lua_pushnil(L); // ... {_i} {bfc} nil
497 while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {} 429 while (lua_next(L, breadth_first_cache) != 0) // ... {_i} {bfc} k {}
498 { 430 {
499 DEBUGSPEW_CODE( char const* key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string"); 431 DEBUGSPEW_CODE(char const* key = (lua_type(L, -2) == LUA_TSTRING) ? lua_tostring(L, -2) : "not a string");
500 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key)); 432 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "table '%s'\n" INDENT_END, key));
501 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 433 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
502 // un-visit this table in case we do need to process it 434 // un-visit this table in case we do need to process it
503 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} 435 lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {}
504 lua_rawget( L, cache); // ... {_i} {bfc} k {} n 436 lua_rawget(L, cache); // ... {_i} {bfc} k {} n
505 ASSERT_L( lua_type( L, -1) == LUA_TNUMBER); 437 ASSERT_L(lua_type(L, -1) == LUA_TNUMBER);
506 visit_count = lua_tointeger( L, -1) - 1; 438 visit_count = lua_tointeger(L, -1) - 1;
507 lua_pop( L, 1); // ... {_i} {bfc} k {} 439 lua_pop(L, 1); // ... {_i} {bfc} k {}
508 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} 440 lua_pushvalue(L, -1); // ... {_i} {bfc} k {} {}
509 if( visit_count > 0) 441 if (visit_count > 0)
510 { 442 {
511 lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n 443 lua_pushinteger(L, visit_count); // ... {_i} {bfc} k {} {} n
512 } 444 }
513 else 445 else
514 { 446 {
515 lua_pushnil( L); // ... {_i} {bfc} k {} {} nil 447 lua_pushnil(L); // ... {_i} {bfc} k {} {} nil
516 } 448 }
517 lua_rawset( L, cache); // ... {_i} {bfc} k {} 449 lua_rawset(L, cache); // ... {_i} {bfc} k {}
518 // push table name in fqn stack (note that concatenation will crash if name is a not string!) 450 // push table name in fqn stack (note that concatenation will crash if name is a not string!)
519 lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k 451 lua_pushvalue(L, -2); // ... {_i} {bfc} k {} k
520 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {} 452 lua_rawseti(L, fqn, _depth); // ... {_i} {bfc} k {}
521 populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, _ctx_base, lua_gettop( L), _depth); 453 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, _ctx_base, lua_gettop(L), _depth);
522 lua_pop( L, 1); // ... {_i} {bfc} k 454 lua_pop(L, 1); // ... {_i} {bfc} k
523 STACK_CHECK( L, 2); 455 STACK_CHECK(L, 2);
524 } 456 }
525 // remove table name from fqn stack 457 // remove table name from fqn stack
526 lua_pushnil( L); // ... {_i} {bfc} nil 458 lua_pushnil(L); // ... {_i} {bfc} nil
527 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} 459 lua_rawseti(L, fqn, _depth); // ... {_i} {bfc}
528 -- _depth; 460 -- _depth;
529 // we are done with our cache 461 // we are done with our cache
530 lua_pop( L, 1); // ... {_i} 462 lua_pop(L, 1); // ... {_i}
531 STACK_CHECK( L, 0); 463 STACK_CHECK(L, 0);
532 // we are done // ... {_i} {bfc} 464 // we are done // ... {_i} {bfc}
533} 465}
534 466
535// ################################################################################################# 467// #################################################################################################
@@ -542,59 +474,59 @@ void populate_func_lookup_table(lua_State* L, int i_, char const* name_)
542 int const ctx_base = lua_gettop(L) + 1; 474 int const ctx_base = lua_gettop(L) + 1;
543 int const in_base = lua_absindex(L, i_); 475 int const in_base = lua_absindex(L, i_);
544 int start_depth = 0; 476 int start_depth = 0;
545 DEBUGSPEW_CODE( Universe* U = universe_get( L)); 477 DEBUGSPEW_CODE(Universe* U = universe_get(L));
546 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr")); 478 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "%p: populate_func_lookup_table('%s')\n" INDENT_END, L, name_ ? name_ : "nullptr"));
547 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); 479 DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U });
548 STACK_GROW(L, 3); 480 STACK_GROW(L, 3);
549 STACK_CHECK_START_REL(L, 0); 481 STACK_CHECK_START_REL(L, 0);
550 LOOKUP_REGKEY.pushValue(L); // {} 482 LOOKUP_REGKEY.pushValue(L); // {}
551 STACK_CHECK( L, 1); 483 STACK_CHECK(L, 1);
552 ASSERT_L( lua_istable( L, -1)); 484 ASSERT_L(lua_istable(L, -1));
553 if( lua_type( L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function 485 if (lua_type(L, in_base) == LUA_TFUNCTION) // for example when a module is a simple function
554 { 486 {
555 name_ = name_ ? name_ : "nullptr"; 487 name_ = name_ ? name_ : "nullptr";
556 lua_pushvalue( L, in_base); // {} f 488 lua_pushvalue(L, in_base); // {} f
557 lua_pushstring( L, name_); // {} f _name 489 lua_pushstring(L, name_); // {} f _name
558 lua_rawset( L, -3); // {} 490 lua_rawset(L, -3); // {}
559 lua_pushstring( L, name_); // {} _name 491 lua_pushstring(L, name_); // {} _name
560 lua_pushvalue( L, in_base); // {} _name f 492 lua_pushvalue(L, in_base); // {} _name f
561 lua_rawset( L, -3); // {} 493 lua_rawset(L, -3); // {}
562 lua_pop( L, 1); // 494 lua_pop(L, 1); //
563 } 495 }
564 else if( lua_type( L, in_base) == LUA_TTABLE) 496 else if (lua_type(L, in_base) == LUA_TTABLE)
565 { 497 {
566 lua_newtable(L); // {} {fqn} 498 lua_newtable(L); // {} {fqn}
567 if( name_) 499 if (name_)
568 { 500 {
569 STACK_CHECK( L, 2); 501 STACK_CHECK(L, 2);
570 lua_pushstring( L, name_); // {} {fqn} "name" 502 lua_pushstring(L, name_); // {} {fqn} "name"
571 // generate a name, and if we already had one name, keep whichever is the shorter 503 // generate a name, and if we already had one name, keep whichever is the shorter
572 lua_pushvalue( L, in_base); // {} {fqn} "name" t 504 lua_pushvalue(L, in_base); // {} {fqn} "name" t
573 update_lookup_entry( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, start_depth); // {} {fqn} "name" 505 update_lookup_entry(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, start_depth); // {} {fqn} "name"
574 // don't forget to store the name at the bottom of the fqn stack 506 // don't forget to store the name at the bottom of the fqn stack
575 ++ start_depth; 507 ++ start_depth;
576 lua_rawseti( L, -2, start_depth); // {} {fqn} 508 lua_rawseti(L, -2, start_depth); // {} {fqn}
577 STACK_CHECK( L, 2); 509 STACK_CHECK(L, 2);
578 } 510 }
579 // retrieve the cache, create it if we haven't done it yet 511 // retrieve the cache, create it if we haven't done it yet
580 LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}? 512 LOOKUPCACHE_REGKEY.pushValue(L); // {} {fqn} {cache}?
581 if( lua_isnil( L, -1)) 513 if (lua_isnil(L, -1))
582 { 514 {
583 lua_pop( L, 1); // {} {fqn} 515 lua_pop(L, 1); // {} {fqn}
584 lua_newtable( L); // {} {fqn} {cache} 516 lua_newtable(L); // {} {fqn} {cache}
585 LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); }); 517 LOOKUPCACHE_REGKEY.setValue(L, [](lua_State* L) { lua_pushvalue(L, -2); });
586 STACK_CHECK( L, 3); 518 STACK_CHECK(L, 3);
587 } 519 }
588 // process everything we find in that table, filling in lookup data for all functions and tables we see there 520 // process everything we find in that table, filling in lookup data for all functions and tables we see there
589 populate_func_lookup_table_recur( DEBUGSPEW_PARAM_COMMA( U) L, ctx_base, in_base, start_depth); 521 populate_func_lookup_table_recur(DEBUGSPEW_PARAM_COMMA(U) L, ctx_base, in_base, start_depth);
590 lua_pop( L, 3); 522 lua_pop(L, 3);
591 } 523 }
592 else 524 else
593 { 525 {
594 lua_pop( L, 1); // 526 lua_pop(L, 1); //
595 (void) luaL_error( L, "unsupported module type %s", lua_typename( L, lua_type( L, in_base))); 527 luaL_error(L, "unsupported module type %s", lua_typename(L, lua_type(L, in_base))); // doesn't return
596 } 528 }
597 STACK_CHECK( L, 0); 529 STACK_CHECK(L, 0);
598} 530}
599 531
600// ################################################################################################# 532// #################################################################################################
@@ -609,38 +541,34 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
609*/ 541*/
610[[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i) 542[[nodiscard]] static lua_Integer get_mt_id(Universe* U, lua_State* L, int i)
611{ 543{
612 lua_Integer id; 544 i = lua_absindex(L, i);
613 545
614 i = lua_absindex( L, i); 546 STACK_GROW(L, 3);
615
616 STACK_GROW( L, 3);
617 547
618 STACK_CHECK_START_REL(L, 0); 548 STACK_CHECK_START_REL(L, 0);
619 push_registry_subtable( L, REG_MTID); // ... _R[REG_MTID] 549 push_registry_subtable(L, REG_MTID); // ... _R[REG_MTID]
620 lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} 550 lua_pushvalue(L, i); // ... _R[REG_MTID] {mt}
621 lua_rawget( L, -2); // ... _R[REG_MTID] mtk? 551 lua_rawget(L, -2); // ... _R[REG_MTID] mtk?
622 552
623 id = lua_tointeger( L, -1); // 0 for nil 553 lua_Integer id{ lua_tointeger(L, -1) }; // 0 for nil
624 lua_pop( L, 1); // ... _R[REG_MTID] 554 lua_pop(L, 1); // ... _R[REG_MTID]
625 STACK_CHECK( L, 1); 555 STACK_CHECK(L, 1);
626 556
627 if( id == 0) 557 if (id == 0)
628 { 558 {
629 id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed); 559 id = U->next_mt_id.fetch_add(1, std::memory_order_relaxed);
630 560
631 /* Create two-way references: id_uint <-> table 561 // Create two-way references: id_uint <-> table
632 */ 562 lua_pushvalue(L, i); // ... _R[REG_MTID] {mt}
633 lua_pushvalue( L, i); // ... _R[REG_MTID] {mt} 563 lua_pushinteger(L, id); // ... _R[REG_MTID] {mt} id
634 lua_pushinteger( L, id); // ... _R[REG_MTID] {mt} id 564 lua_rawset(L, -3); // ... _R[REG_MTID]
635 lua_rawset( L, -3); // ... _R[REG_MTID]
636 565
637 lua_pushinteger( L, id); // ... _R[REG_MTID] id 566 lua_pushinteger(L, id); // ... _R[REG_MTID] id
638 lua_pushvalue( L, i); // ... _R[REG_MTID] id {mt} 567 lua_pushvalue(L, i); // ... _R[REG_MTID] id {mt}
639 lua_rawset( L, -3); // ... _R[REG_MTID] 568 lua_rawset(L, -3); // ... _R[REG_MTID]
640 } 569 }
641 lua_pop( L, 1); // ... 570 lua_pop(L, 1); // ...
642 571 STACK_CHECK(L, 0);
643 STACK_CHECK( L, 0);
644 572
645 return id; 573 return id;
646} 574}
@@ -684,7 +612,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
684 if (mode_ == LookupMode::FromKeeper) 612 if (mode_ == LookupMode::FromKeeper)
685 { 613 {
686 lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel! 614 lua_CFunction f = lua_tocfunction( L, i); // should *always* be func_lookup_sentinel or table_lookup_sentinel!
687 if( f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel) 615 if (f == func_lookup_sentinel || f == table_lookup_sentinel || f == userdata_clone_sentinel)
688 { 616 {
689 lua_getupvalue( L, i, 1); // ... v ... "f.q.n" 617 lua_getupvalue( L, i, 1); // ... v ... "f.q.n"
690 } 618 }
@@ -722,7 +650,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
722 typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2); 650 typewhat = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : luaL_typename( L, -2);
723 // second return value can be nil if the table was not found 651 // second return value can be nil if the table was not found
724 // probable reason: the function was removed from the source Lua state before Lanes was required. 652 // probable reason: the function was removed from the source Lua state before Lanes was required.
725 if( lua_isnil( L, -1)) 653 if (lua_isnil( L, -1))
726 { 654 {
727 gotchaA = " referenced by"; 655 gotchaA = " referenced by";
728 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)"; 656 gotchaB = "\n(did you remove it from the source Lua state before requiring Lanes?)";
@@ -744,22 +672,20 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
744 672
745// ################################################################################################# 673// #################################################################################################
746 674
747/* 675// Push a looked-up table, or nothing if we found nothing
748 * Push a looked-up table, or nothing if we found nothing 676[[nodiscard]] bool InterCopyContext::lookup_table() const
749 */
750[[nodiscard]] static bool lookup_table(Dest L2, Source L1, SourceIndex i_, LookupMode mode_, char const* upName_)
751{ 677{
752 // get the name of the table we want to send 678 // get the name of the table we want to send
753 size_t len; 679 size_t len;
754 char const* fqn = find_lookup_name(L1, i_, mode_, upName_, &len); 680 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len);
755 if (nullptr == fqn) // name not found, it is some user-created table 681 if (nullptr == fqn) // name not found, it is some user-created table
756 { 682 {
757 return false; 683 return false;
758 } 684 }
759 // push the equivalent table in the destination's stack, retrieved from the lookup table 685 // push the equivalent table in the destination's stack, retrieved from the lookup table
760 STACK_CHECK_START_REL(L2, 0); // L // L2 686 STACK_CHECK_START_REL(L2, 0); // L // L2
761 STACK_GROW( L2, 3); // up to 3 slots are necessary on error 687 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
762 switch( mode_) 688 switch (mode)
763 { 689 {
764 default: // shouldn't happen, in theory... 690 default: // shouldn't happen, in theory...
765 luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return 691 luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return
@@ -780,7 +706,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
780 lua_rawget(L2, -2); // {} t 706 lua_rawget(L2, -2); // {} t
781 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) 707 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
782 // but not when we extract something out of a keeper, as there is nothing to clone! 708 // but not when we extract something out of a keeper, as there is nothing to clone!
783 if (lua_isnil(L2, -1) && mode_ == LookupMode::LaneBody) 709 if (lua_isnil(L2, -1) && mode == LookupMode::LaneBody)
784 { 710 {
785 lua_pop(L2, 2); // 711 lua_pop(L2, 2); //
786 STACK_CHECK(L2, 0); 712 STACK_CHECK(L2, 0);
@@ -797,7 +723,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
797 lua_pop(L2, 1); // {} t 723 lua_pop(L2, 1); // {} t
798 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 724 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
799 luaL_error( 725 luaL_error(
800 (mode_ == LookupMode::FromKeeper) ? L2 : L1 726 (mode == LookupMode::FromKeeper) ? L2 : L1
801 , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database." 727 , "INTERNAL ERROR IN %s: table '%s' not found in %s destination transfer database."
802 , from ? from : "main" 728 , from ? from : "main"
803 , fqn 729 , fqn
@@ -808,7 +734,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
808 lua_remove(L2, -2); // t 734 lua_remove(L2, -2); // t
809 break; 735 break;
810 } 736 }
811 STACK_CHECK( L2, 1); 737 STACK_CHECK(L2, 1);
812 return true; 738 return true;
813} 739}
814 740
@@ -877,7 +803,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
877 lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?} 803 lua_pushvalue(L, -1); // o "r" {c} {fqn} ... {?} {?}
878 lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1 804 lua_rawget(L, cache); // o "r" {c} {fqn} ... {?} nil/1
879 // if table is already visited, we are done 805 // if table is already visited, we are done
880 if( !lua_isnil(L, -1)) 806 if (!lua_isnil(L, -1))
881 { 807 {
882 lua_pop(L, 1); // o "r" {c} {fqn} ... {?} 808 lua_pop(L, 1); // o "r" {c} {fqn} ... {?}
883 return shortest_; 809 return shortest_;
@@ -902,7 +828,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
902 { 828 {
903 STACK_CHECK(L, 2); 829 STACK_CHECK(L, 2);
904 // update shortest name 830 // update shortest name
905 if( depth_ < shortest_) 831 if (depth_ < shortest_)
906 { 832 {
907 shortest_ = depth_; 833 shortest_ = depth_;
908 std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn" 834 std::ignore = luaG_pushFQN(L, fqn, depth_, nullptr); // o "r" {c} {fqn} ... {?} k v "fqn"
@@ -924,7 +850,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
924 // search in the table's metatable too 850 // search in the table's metatable too
925 if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt} 851 if (lua_getmetatable(L, -1)) // o "r" {c} {fqn} ... {?} k {} {mt}
926 { 852 {
927 if( lua_istable(L, -1)) 853 if (lua_istable(L, -1))
928 { 854 {
929 ++ depth_; 855 ++ depth_;
930 lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable" 856 lua_pushliteral(L, "__metatable"); // o "r" {c} {fqn} ... {?} k {} {mt} "__metatable"
@@ -966,7 +892,7 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
966 int uvi = 1; 892 int uvi = 1;
967 while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u} 893 while (lua_getiuservalue(L, -1, uvi) != LUA_TNONE) // o "r" {c} {fqn} ... {?} k U {u}
968 { 894 {
969 if( lua_istable(L, -1)) // if it is a table, look inside 895 if (lua_istable(L, -1)) // if it is a table, look inside
970 { 896 {
971 ++ depth_; 897 ++ depth_;
972 lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue" 898 lua_pushliteral(L, "uservalue"); // o "r" {c} {fqn} ... {?} k v {u} "uservalue"
@@ -1010,13 +936,13 @@ static constexpr UniqueKey REG_MTID{ 0x2e68f9b4751584dcull };
1010int luaG_nameof( lua_State* L) 936int luaG_nameof( lua_State* L)
1011{ 937{
1012 int what = lua_gettop( L); 938 int what = lua_gettop( L);
1013 if( what > 1) 939 if (what > 1)
1014 { 940 {
1015 luaL_argerror( L, what, "too many arguments."); 941 luaL_argerror( L, what, "too many arguments.");
1016 } 942 }
1017 943
1018 // nil, boolean, light userdata, number and string aren't identifiable 944 // nil, boolean, light userdata, number and string aren't identifiable
1019 if( lua_type( L, 1) < LUA_TTABLE) 945 if (lua_type( L, 1) < LUA_TTABLE)
1020 { 946 {
1021 lua_pushstring( L, luaL_typename( L, 1)); // o "type" 947 lua_pushstring( L, luaL_typename( L, 1)); // o "type"
1022 lua_insert( L, -2); // "type" o 948 lua_insert( L, -2); // "type" o
@@ -1036,7 +962,7 @@ int luaG_nameof( lua_State* L)
1036 // this is where we start the search 962 // this is where we start the search
1037 lua_pushglobaltable( L); // o nil {c} {fqn} _G 963 lua_pushglobaltable( L); // o nil {c} {fqn} _G
1038 (void) discover_object_name_recur( L, 6666, 1); 964 (void) discover_object_name_recur( L, 6666, 1);
1039 if( lua_isnil( L, 2)) // try again with registry, just in case... 965 if (lua_isnil( L, 2)) // try again with registry, just in case...
1040 { 966 {
1041 lua_pop( L, 1); // o nil {c} {fqn} 967 lua_pop( L, 1); // o nil {c} {fqn}
1042 lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R" 968 lua_pushliteral( L, "_R"); // o nil {c} {fqn} "_R"
@@ -1056,56 +982,56 @@ int luaG_nameof( lua_State* L)
1056/* 982/*
1057 * Push a looked-up native/LuaJIT function. 983 * Push a looked-up native/LuaJIT function.
1058 */ 984 */
1059static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mode_, char const* upName_) 985void InterCopyContext::lookup_native_func() const
1060{ 986{
1061 // get the name of the function we want to send 987 // get the name of the function we want to send
1062 size_t len; 988 size_t len;
1063 char const* fqn = find_lookup_name( L, i, mode_, upName_, &len); 989 char const* fqn = find_lookup_name(L1, L1_i, mode, name, &len);
1064 // push the equivalent function in the destination's stack, retrieved from the lookup table 990 // push the equivalent function in the destination's stack, retrieved from the lookup table
1065 STACK_CHECK_START_REL(L2, 0); // L // L2 991 STACK_CHECK_START_REL(L2, 0); // L1 // L2
1066 STACK_GROW( L2, 3); // up to 3 slots are necessary on error 992 STACK_GROW(L2, 3); // up to 3 slots are necessary on error
1067 switch( mode_) 993 switch (mode)
1068 { 994 {
1069 default: // shouldn't happen, in theory... 995 default: // shouldn't happen, in theory...
1070 (void) luaL_error( L, "internal error: unknown lookup mode"); 996 luaL_error(L1, "internal error: unknown lookup mode"); // doesn't return
1071 return; 997 break;
1072 998
1073 case LookupMode::ToKeeper: 999 case LookupMode::ToKeeper:
1074 // push a sentinel closure that holds the lookup name as upvalue 1000 // push a sentinel closure that holds the lookup name as upvalue
1075 lua_pushlstring( L2, fqn, len); // "f.q.n" 1001 lua_pushlstring(L2, fqn, len); // "f.q.n"
1076 lua_pushcclosure( L2, func_lookup_sentinel, 1); // f 1002 lua_pushcclosure(L2, func_lookup_sentinel, 1); // f
1077 break; 1003 break;
1078 1004
1079 case LookupMode::LaneBody: 1005 case LookupMode::LaneBody:
1080 case LookupMode::FromKeeper: 1006 case LookupMode::FromKeeper:
1081 LOOKUP_REGKEY.pushValue(L2); // {} 1007 LOOKUP_REGKEY.pushValue(L2); // {}
1082 STACK_CHECK( L2, 1); 1008 STACK_CHECK(L2, 1);
1083 ASSERT_L( lua_istable( L2, -1)); 1009 _ASSERT_L(L1, lua_istable(L2, -1));
1084 lua_pushlstring( L2, fqn, len); // {} "f.q.n" 1010 lua_pushlstring(L2, fqn, len); // {} "f.q.n"
1085 lua_rawget( L2, -2); // {} f 1011 lua_rawget(L2, -2); // {} f
1086 // nil means we don't know how to transfer stuff: user should do something 1012 // nil means we don't know how to transfer stuff: user should do something
1087 // anything other than function or table should not happen! 1013 // anything other than function or table should not happen!
1088 if( !lua_isfunction( L2, -1) && !lua_istable( L2, -1)) 1014 if (!lua_isfunction( L2, -1) && !lua_istable( L2, -1))
1089 { 1015 {
1090 char const* from, * to; 1016 char const* from, * to;
1091 lua_getglobal( L, "decoda_name"); // ... f ... decoda_name 1017 lua_getglobal(L1, "decoda_name"); // ... f ... decoda_name
1092 from = lua_tostring( L, -1); 1018 from = lua_tostring(L1, -1);
1093 lua_pop( L, 1); // ... f ... 1019 lua_pop(L1, 1); // ... f ...
1094 lua_getglobal( L2, "decoda_name"); // {} f decoda_name 1020 lua_getglobal(L2, "decoda_name"); // {} f decoda_name
1095 to = lua_tostring( L2, -1); 1021 to = lua_tostring(L2, -1);
1096 lua_pop( L2, 1); // {} f 1022 lua_pop(L2, 1); // {} f
1097 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 1023 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
1098 (void) luaL_error( 1024 (void) luaL_error(
1099 (mode_ == LookupMode::FromKeeper) ? L2 : L 1025 (mode == LookupMode::FromKeeper) ? L2 : L1
1100 , "%s%s: function '%s' not found in %s destination transfer database." 1026 , "%s%s: function '%s' not found in %s destination transfer database."
1101 , lua_isnil( L2, -1) ? "" : "INTERNAL ERROR IN " 1027 , lua_isnil(L2, -1) ? "" : "INTERNAL ERROR IN "
1102 , from ? from : "main" 1028 , from ? from : "main"
1103 , fqn 1029 , fqn
1104 , to ? to : "main" 1030 , to ? to : "main"
1105 ); 1031 );
1106 return; 1032 return;
1107 } 1033 }
1108 lua_remove( L2, -2); // f 1034 lua_remove(L2, -2); // f
1109 break; 1035 break;
1110 1036
1111 /* keep it in case I need it someday, who knows... 1037 /* keep it in case I need it someday, who knows...
@@ -1115,7 +1041,7 @@ static void lookup_native_func(lua_State* L2, lua_State* L, int i, LookupMode mo
1115 char const* upname; 1041 char const* upname;
1116 lua_CFunction f = lua_tocfunction( L, i); 1042 lua_CFunction f = lua_tocfunction( L, i);
1117 // copy upvalues 1043 // copy upvalues
1118 for( n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n) 1044 for (n = 0; (upname = lua_getupvalue( L, i, 1 + n)) != nullptr; ++ n)
1119 { 1045 {
1120 luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]] 1046 luaG_inter_move( U, L, L2, 1, mode_); // [up[,up ...]]
1121 } 1047 }
@@ -1166,7 +1092,7 @@ static char const* vt_names[] =
1166[[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud) 1092[[nodiscard]] static int buf_writer(lua_State* L, void const* b, size_t size, void* ud)
1167{ 1093{
1168 luaL_Buffer* B = (luaL_Buffer*) ud; 1094 luaL_Buffer* B = (luaL_Buffer*) ud;
1169 if( !B->L) 1095 if (!B->L)
1170 { 1096 {
1171 luaL_buffinit( L, B); 1097 luaL_buffinit( L, B);
1172 } 1098 }
@@ -1278,7 +1204,7 @@ void InterCopyContext::copy_func() const
1278 { // ... _G up[n] 1204 { // ... _G up[n]
1279 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name)); 1205 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "UPNAME[%d]: %s -> " INDENT_END, n, c.name));
1280#if LUA_VERSION_NUM >= 502 1206#if LUA_VERSION_NUM >= 502
1281 if( lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table? 1207 if (lua_rawequal(L1, -1, -2)) // is the upvalue equal to the global table?
1282 { 1208 {
1283 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n")); 1209 DEBUGSPEW_CODE(fprintf(stderr, "pushing destination global scope\n"));
1284 lua_pushglobaltable(L2); // ... {cache} ... function <upvalues> 1210 lua_pushglobaltable(L2); // ... {cache} ... function <upvalues>
@@ -1331,8 +1257,7 @@ void InterCopyContext::copy_func() const
1331 */ 1257 */
1332void InterCopyContext::copy_cached_func() const 1258void InterCopyContext::copy_cached_func() const
1333{ 1259{
1334 FuncSubType funcSubType; 1260 FuncSubType const funcSubType{ luaG_getfuncsubtype(L1, L1_i) };
1335 std::ignore = luaG_tocfunction(L1, L1_i, &funcSubType); // nullptr for LuaJIT-fast && bytecode functions
1336 if (funcSubType == FST_Bytecode) 1261 if (funcSubType == FST_Bytecode)
1337 { 1262 {
1338 void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i)); 1263 void* const aspointer = const_cast<void*>(lua_topointer(L1, L1_i));
@@ -1376,7 +1301,7 @@ void InterCopyContext::copy_cached_func() const
1376 } 1301 }
1377 else // function is native/LuaJIT: no need to cache 1302 else // function is native/LuaJIT: no need to cache
1378 { 1303 {
1379 lookup_native_func(L2, L1, L1_i, mode, name); // ... {cache} ... function 1304 lookup_native_func(); // ... {cache} ... function
1380 // if the function was in fact a lookup sentinel, we can either get a function or a table here 1305 // if the function was in fact a lookup sentinel, we can either get a function or a table here
1381 _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1)); 1306 _ASSERT_L(L1, lua_isfunction(L2, -1) || lua_istable(L2, -1));
1382 } 1307 }
@@ -1440,7 +1365,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1440 SourceIndex const val_i{ lua_gettop(L1) }; 1365 SourceIndex const val_i{ lua_gettop(L1) };
1441 SourceIndex const key_i{ val_i - 1 }; 1366 SourceIndex const key_i{ val_i - 1 };
1442 1367
1443 // Only basic key types are copied over; others ignored 1368 // For the key, only basic key types are copied over. others ignored
1444 InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name }; 1369 InterCopyContext c{ U, L2, L1, L2_cache_i, key_i, VT::KEY, mode, name };
1445 if (!c.inter_copy_one()) 1370 if (!c.inter_copy_one())
1446 { 1371 {
@@ -1451,7 +1376,7 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1451 } 1376 }
1452 1377
1453 char* valPath{ nullptr }; 1378 char* valPath{ nullptr };
1454 if( U->verboseErrors) 1379 if (U->verboseErrors)
1455 { 1380 {
1456 // for debug purposes, let's try to build a useful name 1381 // for debug purposes, let's try to build a useful name
1457 if (lua_type(L1, key_i) == LUA_TSTRING) 1382 if (lua_type(L1, key_i) == LUA_TSTRING)
@@ -1483,20 +1408,17 @@ void InterCopyContext::inter_copy_keyvaluepair() const
1483 valPath = (char*) alloca(strlen(name) + 16 + 5); 1408 valPath = (char*) alloca(strlen(name) + 16 + 5);
1484 sprintf(valPath, "%s[U:%p]", name, key); 1409 sprintf(valPath, "%s[U:%p]", name, key);
1485 } 1410 }
1486 else if( lua_type( L1, key_i) == LUA_TBOOLEAN) 1411 else if (lua_type( L1, key_i) == LUA_TBOOLEAN)
1487 { 1412 {
1488 int const key{ lua_toboolean(L1, key_i) }; 1413 int const key{ lua_toboolean(L1, key_i) };
1489 valPath = (char*) alloca(strlen(name) + 8); 1414 valPath = (char*) alloca(strlen(name) + 8);
1490 sprintf(valPath, "%s[%s]", name, key ? "true" : "false"); 1415 sprintf(valPath, "%s[%s]", name, key ? "true" : "false");
1491 } 1416 }
1492 } 1417 }
1493 /*
1494 * Contents of metatables are copied with cache checking;
1495 * important to detect loops.
1496 */
1497 c.L1_i = SourceIndex{ val_i }; 1418 c.L1_i = SourceIndex{ val_i };
1498 c.name = valPath ? valPath : name; 1419 // Contents of metatables are copied with cache checking. important to detect loops.
1499 c.vt = VT::NORMAL; 1420 c.vt = VT::NORMAL;
1421 c.name = valPath ? valPath : name;
1500 if (c.inter_copy_one()) 1422 if (c.inter_copy_one())
1501 { 1423 {
1502 _ASSERT_L(L1, lua_istable( L2, -3)); 1424 _ASSERT_L(L1, lua_istable( L2, -3));
@@ -1539,7 +1461,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1539 STACK_CHECK(L2, 0); 1461 STACK_CHECK(L2, 0);
1540 1462
1541 // no metatable? -> not clonable 1463 // no metatable? -> not clonable
1542 if( !lua_getmetatable(L1, L1_i)) // ... mt? 1464 if (!lua_getmetatable(L1, L1_i)) // ... mt?
1543 { 1465 {
1544 STACK_CHECK(L1, 0); 1466 STACK_CHECK(L1, 0);
1545 return false; 1467 return false;
@@ -1547,7 +1469,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1547 1469
1548 // no __lanesclone? -> not clonable 1470 // no __lanesclone? -> not clonable
1549 lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone? 1471 lua_getfield(L1, -1, "__lanesclone"); // ... mt __lanesclone?
1550 if( lua_isnil(L1, -1)) 1472 if (lua_isnil(L1, -1))
1551 { 1473 {
1552 lua_pop(L1, 2); // ... 1474 lua_pop(L1, 2); // ...
1553 STACK_CHECK(L1, 0); 1475 STACK_CHECK(L1, 0);
@@ -1565,12 +1487,12 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1565 lua_pop(L1, 1); // ... mt __lanesclone [uv]+ 1487 lua_pop(L1, 1); // ... mt __lanesclone [uv]+
1566 -- uvi; 1488 -- uvi;
1567 // create the clone userdata with the required number of uservalue slots 1489 // create the clone userdata with the required number of uservalue slots
1568 void* clone = lua_newuserdatauv(L2, userdata_size, uvi); // ... u 1490 void* const clone{ lua_newuserdatauv(L2, userdata_size, uvi) }; // ... u
1569 // copy the metatable in the target state, and give it to the clone we put there 1491 // copy the metatable in the target state, and give it to the clone we put there
1570 InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name }; 1492 InterCopyContext c{ U, L2, L1, L2_cache_i, SourceIndex{ mt }, VT::NORMAL, mode, name };
1571 if (c.inter_copy_one()) // ... u mt|sentinel 1493 if (c.inter_copy_one()) // ... u mt|sentinel
1572 { 1494 {
1573 if( LookupMode::ToKeeper == mode) // ... u sentinel 1495 if (LookupMode::ToKeeper == mode) // ... u sentinel
1574 { 1496 {
1575 _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel); 1497 _ASSERT_L(L1, lua_tocfunction(L2, -1) == table_lookup_sentinel);
1576 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn 1498 // we want to create a new closure with a 'clone sentinel' function, where the upvalues are the userdata and the metatable fqn
@@ -1645,7 +1567,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1645 } 1567 }
1646 1568
1647 // try clonable userdata first 1569 // try clonable userdata first
1648 if( copyclone()) 1570 if (copyclone())
1649 { 1571 {
1650 STACK_CHECK(L1, 0); 1572 STACK_CHECK(L1, 0);
1651 STACK_CHECK(L2, 1); 1573 STACK_CHECK(L2, 1);
@@ -1714,8 +1636,8 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1714 } 1636 }
1715 lua_pop(L2, 1); // ... 1637 lua_pop(L2, 1); // ...
1716 1638
1717 // this function has 2 upvalues: the fqn of its metatable, and the userdata itself 1639 // userdata_clone_sentinel has 2 upvalues: the fqn of its metatable, and the userdata itself
1718 bool const found{ lookup_table(L2, L1, L1_i, mode, name) }; // ... mt? 1640 bool const found{ lookup_table() }; // ... mt?
1719 if (!found) 1641 if (!found)
1720 { 1642 {
1721 STACK_CHECK(L2, 0); 1643 STACK_CHECK(L2, 0);
@@ -1802,7 +1724,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1802 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?) 1724 * First, let's try to see if this table is special (aka is it some table that we registered in our lookup databases during module registration?)
1803 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism 1725 * Note that this table CAN be a module table, but we just didn't register it, in which case we'll send it through the table cloning mechanism
1804 */ 1726 */
1805 if (lookup_table(L2, L1, L1_i, mode, name)) 1727 if (lookup_table())
1806 { 1728 {
1807 _ASSERT_L(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know 1729 _ASSERT_L(L1, lua_istable(L2, -1) || (lua_tocfunction(L2, -1) == table_lookup_sentinel)); // from lookup data. can also be table_lookup_sentinel if this is a table we know
1808 return true; 1730 return true;
@@ -1849,6 +1771,71 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1849 1771
1850// ################################################################################################# 1772// #################################################################################################
1851 1773
1774[[nodiscard]] bool InterCopyContext::inter_copy_boolean() const
1775{
1776 int const v{ lua_toboolean(L1, L1_i) };
1777 DEBUGSPEW_CODE(fprintf(stderr, "%s\n", v ? "true" : "false"));
1778 lua_pushboolean(L2, v);
1779 return true;
1780}
1781
1782// #################################################################################################
1783
1784[[nodiscard]] bool InterCopyContext::inter_copy_lightuserdata() const
1785{
1786 void* const p{ lua_touserdata(L1, L1_i) };
1787 DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p));
1788 lua_pushlightuserdata(L2, p);
1789 return true;
1790}
1791
1792// #################################################################################################
1793
1794[[nodiscard]] bool InterCopyContext::inter_copy_nil() const
1795{
1796 if (vt == VT::KEY)
1797 {
1798 return false;
1799 }
1800 lua_pushnil(L2);
1801 return true;
1802}
1803
1804// #################################################################################################
1805
1806[[nodiscard]] bool InterCopyContext::inter_copy_number() const
1807{
1808 /* LNUM patch support (keeping integer accuracy) */
1809#if defined LUA_LNUM || LUA_VERSION_NUM >= 503
1810 if (lua_isinteger(L1, L1_i))
1811 {
1812 lua_Integer const v{ lua_tointeger(L1, L1_i) };
1813 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v));
1814 lua_pushinteger(L2, v);
1815 }
1816 else
1817#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1818 {
1819 lua_Number const v{ lua_tonumber(L1, L1_i) };
1820 DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v));
1821 lua_pushnumber(L2, v);
1822 }
1823 return true;
1824}
1825
1826// #################################################################################################
1827
1828[[nodiscard]] bool InterCopyContext::inter_copy_string() const
1829{
1830 size_t len;
1831 char const* const s{ lua_tolstring(L1, L1_i, &len) };
1832 DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s));
1833 lua_pushlstring(L2, s, len);
1834 return true;
1835}
1836
1837// #################################################################################################
1838
1852/* 1839/*
1853* Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove 1840* Copies a value from 'L1' state (at index 'i') to 'L2' state. Does not remove
1854* the original value. 1841* the original value.
@@ -1878,7 +1865,7 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1878 if (lua_getmetatable(L1, L1_i)) // ... mt 1865 if (lua_getmetatable(L1, L1_i)) // ... mt
1879 { 1866 {
1880 lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore? 1867 lua_getfield(L1, -1, "__lanesignore"); // ... mt ignore?
1881 if( lua_isboolean(L1, -1) && lua_toboolean(L1, -1)) 1868 if (lua_isboolean(L1, -1) && lua_toboolean(L1, -1))
1882 { 1869 {
1883 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END)); 1870 DEBUGSPEW_CODE(fprintf( stderr, INDENT_BEGIN "__lanesignore -> LUA_TNIL\n" INDENT_END));
1884 val_type = LuaType::NIL; 1871 val_type = LuaType::NIL;
@@ -1892,81 +1879,21 @@ static constexpr UniqueKey CLONABLES_CACHE_KEY{ 0xD04EE018B3DEE8F5ull };
1892 bool ret{ true }; 1879 bool ret{ true };
1893 switch (val_type) 1880 switch (val_type)
1894 { 1881 {
1895 /* Basic types allowed both as values, and as table keys */ 1882 // Basic types allowed both as values, and as table keys
1896 1883 case LuaType::BOOLEAN: ret = inter_copy_boolean(); break;
1897 case LuaType::BOOLEAN: 1884 case LuaType::NUMBER: ret = inter_copy_number(); break;
1898 { 1885 case LuaType::STRING: ret = inter_copy_string(); break;
1899 int const v{ lua_toboolean(L1, L1_i) }; 1886 case LuaType::LIGHTUSERDATA: ret = inter_copy_lightuserdata();break;
1900 DEBUGSPEW_CODE( fprintf(stderr, "%s\n", v ? "true" : "false")); 1887
1901 lua_pushboolean(L2, v); 1888 // The following types are not allowed as table keys
1902 } 1889 case LuaType::USERDATA: ret = inter_copy_userdata(); break;
1903 break; 1890 case LuaType::NIL: ret = inter_copy_nil(); break;
1904 1891 case LuaType::FUNCTION: ret = inter_copy_function(); break;
1905 case LuaType::NUMBER: 1892 case LuaType::TABLE: ret = inter_copy_table(); break;
1906 /* LNUM patch support (keeping integer accuracy) */ 1893
1907#if defined LUA_LNUM || LUA_VERSION_NUM >= 503 1894 // The following types cannot be copied
1908 if( lua_isinteger(L1, L1_i)) 1895 case LuaType::CDATA: [[fallthrough]];
1909 { 1896 case LuaType::THREAD: ret = false; break;
1910 lua_Integer const v{ lua_tointeger(L1, L1_i) };
1911 DEBUGSPEW_CODE(fprintf(stderr, LUA_INTEGER_FMT "\n", v));
1912 lua_pushinteger(L2, v);
1913 break;
1914 }
1915 else
1916#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
1917 {
1918 lua_Number const v{ lua_tonumber(L1, L1_i) };
1919 DEBUGSPEW_CODE(fprintf(stderr, LUA_NUMBER_FMT "\n", v));
1920 lua_pushnumber(L2, v);
1921 }
1922 break;
1923
1924 case LuaType::STRING:
1925 {
1926 size_t len;
1927 char const* const s{ lua_tolstring(L1, L1_i, &len) };
1928 DEBUGSPEW_CODE(fprintf(stderr, "'%s'\n", s));
1929 lua_pushlstring(L2, s, len);
1930 }
1931 break;
1932
1933 case LuaType::LIGHTUSERDATA:
1934 {
1935 void* const p{ lua_touserdata(L1, L1_i) };
1936 DEBUGSPEW_CODE(fprintf(stderr, "%p\n", p));
1937 lua_pushlightuserdata(L2, p);
1938 }
1939 break;
1940
1941 /* The following types are not allowed as table keys */
1942
1943 case LuaType::USERDATA:
1944 ret = inter_copy_userdata();
1945 break;
1946
1947 case LuaType::NIL:
1948 if (vt == VT::KEY)
1949 {
1950 ret = false;
1951 break;
1952 }
1953 lua_pushnil( L2);
1954 break;
1955
1956 case LuaType::FUNCTION:
1957 ret = inter_copy_function();
1958 break;
1959
1960 case LuaType::TABLE:
1961 ret = inter_copy_table();
1962 break;
1963
1964 /* The following types cannot be copied */
1965
1966 case LuaType::CDATA:
1967 case LuaType::THREAD:
1968 ret = false;
1969 break;
1970 } 1897 }
1971 1898
1972 STACK_CHECK(L2, ret ? 1 : 0); 1899 STACK_CHECK(L2, ret ? 1 : 0);