diff options
Diffstat (limited to 'src/tools.c')
-rw-r--r-- | src/tools.c | 121 |
1 files changed, 79 insertions, 42 deletions
diff --git a/src/tools.c b/src/tools.c index 41163c4..29959a8 100644 --- a/src/tools.c +++ b/src/tools.c | |||
@@ -395,65 +395,102 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelud | |||
395 | 395 | ||
396 | if (lua_isnil(L,-1)) | 396 | if (lua_isnil(L,-1)) |
397 | { | 397 | { |
398 | int oldtop; | ||
399 | // No metatable yet. We have two things to do: | 398 | // No metatable yet. We have two things to do: |
400 | |||
401 | // 1 - make one and register it | 399 | // 1 - make one and register it |
402 | lua_pop(L,1); | 400 | { |
401 | int oldtop; | ||
403 | 402 | ||
404 | // tbl= idfunc( "metatable" ) | 403 | lua_pop( L, 1); |
405 | // | ||
406 | oldtop = lua_gettop( L); | ||
407 | idfunc( L, "metatable"); | ||
408 | // | ||
409 | // [-2]: proxy | ||
410 | // [-1]: metatable (returned by 'idfunc') | ||
411 | 404 | ||
412 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) | 405 | // tbl= idfunc( "metatable" ) |
413 | { | 406 | // |
414 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); | 407 | oldtop = lua_gettop( L); |
415 | } | 408 | idfunc( L, "metatable"); |
409 | // | ||
410 | // [-2]: proxy | ||
411 | // [-1]: metatable (returned by 'idfunc') | ||
416 | 412 | ||
417 | // Add '__gc' method | 413 | if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1)) |
418 | // | 414 | { |
419 | lua_pushcfunction( L, deep_userdata_gc ); | 415 | luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); |
420 | lua_setfield( L, -2, "__gc" ); | 416 | } |
421 | 417 | ||
422 | // Memorize for later rounds | 418 | // Add '__gc' method |
423 | // | 419 | // |
424 | lua_pushvalue( L,-1 ); | 420 | lua_pushcfunction( L, deep_userdata_gc ); |
425 | lua_pushlightuserdata( L, idfunc ); | 421 | lua_setfield( L, -2, "__gc" ); |
426 | // | 422 | |
427 | // [-4]: proxy | 423 | // Memorize for later rounds |
428 | // [-3]: metatable (2nd ref) | 424 | // |
429 | // [-2]: metatable | 425 | lua_pushvalue( L,-1 ); |
430 | // [-1]: idfunc | 426 | lua_pushlightuserdata( L, idfunc ); |
427 | // | ||
428 | // [-4]: proxy | ||
429 | // [-3]: metatable (2nd ref) | ||
430 | // [-2]: metatable | ||
431 | // [-1]: idfunc | ||
431 | 432 | ||
432 | set_deep_lookup(L); | 433 | set_deep_lookup(L); |
434 | } | ||
433 | 435 | ||
434 | // 2 - cause the target state to require the module that exported the idfunc | 436 | // 2 - cause the target state to require the module that exported the idfunc |
435 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc | 437 | // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc |
436 | lua_getglobal( L, "require"); | 438 | STACK_CHECK(L) |
437 | if( lua_isfunction( L, -1)) // just in case... | ||
438 | { | 439 | { |
440 | char const * modname; | ||
439 | // make sure the function pushed a single value on the stack! | 441 | // make sure the function pushed a single value on the stack! |
440 | int oldtop = lua_gettop( L); | ||
441 | idfunc( L, "module"); | ||
442 | if( lua_gettop( L) - oldtop != 1 || !lua_isstring( L, -1)) | ||
443 | { | 442 | { |
444 | luaL_error( L, "Bad idfunc on \"module\": should return a string"); | 443 | int oldtop = lua_gettop( L); |
444 | idfunc( L, "module"); // ... "module"/nil | ||
445 | if( lua_gettop( L) - oldtop != 1) | ||
446 | { | ||
447 | luaL_error( L, "Bad idfunc on \"module\": should return a single value"); | ||
448 | } | ||
445 | } | 449 | } |
446 | // if we are inside a call to require, this will raise a "reentrency" error that we absorb silently (we don't care, this probably means the module is already being required, which is what we need) | 450 | modname = luaL_optstring( L, -1, NULL); // raises an error if not a string or nil |
447 | if( lua_pcall( L, 1, 0, 0) != 0) | 451 | if( modname) // we actually got a module name |
448 | { | 452 | { |
449 | //char const * const errMsg = lua_tostring( L, -1); // just to see it in the debugger | 453 | // somehow, L.registry._LOADED can exist without having registered the 'package' library. |
450 | lua_pop( L, 1); | 454 | lua_getglobal( L, "require"); // ... "module" require() |
455 | // check that the module is already loaded (or being loaded, we are happy either way) | ||
456 | if( lua_isfunction( L, -1)) | ||
457 | { | ||
458 | lua_insert( L, -2); // ... require() "module" | ||
459 | lua_getfield( L, LUA_REGISTRYINDEX, "_LOADED"); // ... require() "module" L.registry._LOADED | ||
460 | if( lua_istable( L, -1)) | ||
461 | { | ||
462 | bool_t alreadyloaded; | ||
463 | lua_pushvalue( L, -2); // ... require() "module" L.registry._LOADED "module" | ||
464 | lua_rawget( L, -2); // ... require() "module" L.registry._LOADED module | ||
465 | alreadyloaded = lua_toboolean( L, -1); | ||
466 | if( !alreadyloaded) // not loaded | ||
467 | { | ||
468 | lua_pop( L, 2); // ... require() "module" | ||
469 | lua_call( L, 1, 0); // call require "modname" // ... | ||
470 | } | ||
471 | else // already loaded, we are happy | ||
472 | { | ||
473 | lua_pop( L, 4); // ... | ||
474 | } | ||
475 | } | ||
476 | else // no L.registry._LOADED; can this ever happen? | ||
477 | { | ||
478 | luaL_error( L, "unexpected error while requiring a module"); | ||
479 | lua_pop( L, 3); // ... | ||
480 | } | ||
481 | } | ||
482 | else // a module name, but no require() function :-( | ||
483 | { | ||
484 | luaL_error( L, "lanes receiving deep userdata should register the 'package' library"); | ||
485 | lua_pop( L, 2); // ... | ||
486 | } | ||
487 | } | ||
488 | else // no module name | ||
489 | { | ||
490 | lua_pop( L, 1); // ... | ||
451 | } | 491 | } |
452 | } | 492 | } |
453 | else | 493 | STACK_END(L,0) |
454 | { | ||
455 | lua_pop( L, 1); | ||
456 | } | ||
457 | } | 494 | } |
458 | STACK_MID(L,2) | 495 | STACK_MID(L,2) |
459 | ASSERT_L( lua_isuserdata(L,-2) ); | 496 | ASSERT_L( lua_isuserdata(L,-2) ); |