local nt = {}
local function doEnvHack(start)
start = start or 1
if start < 1 then error() end
for i=1+start,math.huge do
if debug.getinfo(i) and debug.getinfo(i).what ~= "C" then
if getfenv(i) ~= nt and debug.getmetatable(getfenv(i)) then
return getfenv(i), i
end
end
if not debug.getinfo(i) then
return nt
end
end
return nt
end
for x,y in pairs(_G) do
nt[x]=y
end
setfenv(0,nt)
local function getStringMetatable(start)
local env, nextstart = doEnvHack((start and start+1 or 1))
while not debug.getmetatable(env).__stringmt do
env, nextstart = doEnvHack(nextstart)
end
return debug.getmetatable(env).__stringmt
end
-- replace string metatable
debug.setmetatable(getfenv(0),{
__stringmt = debug.getmetatable("")
})
local idx = 1
debug.setmetatable("",{
-- Indexing
__index = function(t,k)
local smt_index = rawget(getStringMetatable(idx),"__index")
if type(smt_index) == "function" then return smt_index(t,k)
else return rawget(smt_index,k) end
end,
__newindex = function(t,k)
local smt_newindex = rawget(getStringMetatable(idx),"__newindex")
if type(smt_newindex) == "function" then smt_newindex(t,k,v)
else rawset(smt_newindex,k,v) end
end,
-- Calling
__call = function(t,...)
return rawget(getStringMetatable(idx),"__call")(t,...)
end,
-- Math
__add = function(o1,o2)
return rawget(getStringMetatable(idx),"__add")(o1,o2)
end,
__sub = function(o1,o2)
return rawget(getStringMetatable(idx),"__sub")(o1,o2)
end,
__mul = function(o1,o2)
return rawget(getStringMetatable(idx),"__mul")(o1,o2)
end,
__div = function(o1,o2)
return rawget(getStringMetatable(idx),"__div")(o1,o2)
end,
__mod = function(o1,o2)
return rawget(getStringMetatable(idx),"__mod")(o1,o2)
end,
__pow = function(o1,o2)
return rawget(getStringMetatable(idx),"__pow")(o1,o2)
end,
__unm = function(o1,o2)
return rawget(getStringMetatable(idx),"__unm")(o1,o2)
end,
-- Etc
__concat = function(o1,o2)
return rawget(getStringMetatable(idx),"__concat")(o1,o2)
end,
__len = function(t)
return rawget(getStringMetatable(idx),"__len")(t)
end,
-- Compare
__eq = function(o1,o2)
return rawget(getStringMetatable(idx),"__eq")(o1,o2)
end,
__lt = function(o1,o2)
return rawget(getStringMetatable(idx),"__lt")(o1,o2)
end,
__le = function(o1,o2)
return rawget(getStringMetatable(idx),"__le")(o1,o2)
end
});
function f()
print(("this is a test"):lower())
end
local fenv = {}
for x,y in pairs(_G) do fenv[x]=y end
f() -- call it, no string metatable
setfenv(f,setmetatable(fenv,{__stringmt = {__index = {lower = string.upper}}}))
f() -- call it, with string metatable where __index.lower = string.upper