// __index metamethod handler. // For proxied tables, return proxies of children, preferably cached // For proxied strings, return methods static int l_str_index(lua_State *L) { // Look up cached value, and return it if present aux_push_weak_table(L, 1); lua_pushvalue(L, 1); lua_gettable(L, 3); lua_replace(L, 3); lua_pushvalue(L, 2); lua_rawget(L, 3); if(!lua_isnil(L, 4)) return 1; lua_pop(L, 1); // Fetch the proxied value aux_push_weak_table(L, 0); lua_pushvalue(L, 1); lua_rawget(L, 4); lua_replace(L, 4); // Handle string methods if(lua_type(L, 4) == LUA_TSTRING) { lua_rawgeti(L, luaT_environindex, 4); lua_pushvalue(L, 2); lua_gettable(L, 5); return 1; } // Handle __random, as it shouldn't be cached if(lua_type(L, 2) == LUA_TSTRING) { size_t iLen; const char* sKey = lua_tolstring(L, 2, &iLen); if(iLen == 8 && strcmp(sKey, "__random") == 0) { aux_push_random_key(L); lua_replace(L, 2); lua_settop(L, 2); return l_str_index(L); } } // Fetch desired value lua_pushvalue(L, 2); lua_gettable(L, 4); lua_replace(L, 4); // Create new userdata proxy l_str_new_aux(L); aux_mk_table(L, 0, 2, 1, 2); lua_setfenv(L, 4); // Save to cache and return lua_pushvalue(L, 2); lua_pushvalue(L, 4); lua_rawset(L, 3); return 1; }
// Create a new root-level userdata proxy static int l_str_new(lua_State *L) { // Pack extra arguments into a table int iNArgs = lua_gettop(L); lua_createtable(L, iNArgs - 2, 0); lua_replace(L, 1); // Value inserted by __call for(int i = iNArgs; i >= 3; --i) lua_rawseti(L, 1, i - 2); // Make proxy luaL_checkany(L, 2); l_str_new_aux(L); // Save extra arguments as reconstruction information lua_insert(L, 1); lua_setfenv(L, 1); return 1; }
// Generic string method handler // The name of the method is stored at upvalue 1 static int l_str_func(lua_State *L) { int iArgCount = lua_gettop(L); lua_checkstack(L, iArgCount + 10); int iUserdataCount = 0; // Construct the resulting value aux_push_weak_table(L, 0); for(int i = 1; i <= iArgCount; ++i) { lua_pushvalue(L, i); if(lua_type(L, i) == LUA_TUSERDATA) { lua_rawget(L, iArgCount + 1); ++iUserdataCount; } } lua_pushvalue(L, luaT_upvalueindex(1)); lua_gettable(L, iArgCount + 2); lua_replace(L, iArgCount + 1); lua_call(L, iArgCount, 1); // Trivial case of result not depending upon any proxies if(iUserdataCount == 0) return 1; // Wrap result in a proxy l_str_new_aux(L); // Create and save reconstruction information lua_createtable(L, iArgCount + 1, 0); lua_pushvalue(L, luaT_upvalueindex(1)); lua_rawseti(L, -2, 1); for(int i = 1; i <= iArgCount; ++i) { lua_pushvalue(L, i); lua_rawseti(L, -2, i + 1); } lua_setfenv(L, -2); return 1; }