|
|
||
|
|
Idk if I consider this a proposal or not, but
what if environments had stacks? For example, let's say we add a new keyword "setsenv" (set scope environment), and another one "getsenv" (get scope environment) (keywords that act like functions? yeah I like that :P), and we have some code like this: print("outside scope", getsenv) do setsenv {print=print, tostring=tostring} -- setting tostring would be needed as print would act on the current env print("inside scope", getsenv) end print("outside scope, again", getsenv) This would output bytecode like this: (pseudobytecode) GETGLOBAL "print" 0 LOADK "outside scope" 1 GETENV 2 CALL 0 2 0 -- call function at 0 with 2 arguments, put results starting from 0 -- some table boilerplate PUSHENV 0 GETGLOBAL "print" 0 LOADK "inside scope" 1 GETENV 2 CALL 0 2 0 POPENV -- caused by "end" in "do...end" GETGLOBAL "print" 0 LOADK "outside scope, again" 1 GETENV 2 CALL 0 2 0 Q: Why would this be good? A: 1. print()'s tostring() calls wouldn't depend on the "global globals" (that is, the "global environment", as stored in the C registry), but rather on the callers' currently active environment. 2. string metatable hacks for sandboxing would be possible like in Lua 5.1.[1] 3. other cool stuff[?] Q: What about loading bytecode that pops the environment stack multiple times? A: Environment stacks are per closure, not global. --
Disclaimer: these emails are public and can be accessed from <TODO: get a non-DHCP IP and put it here>. If you do not agree with this, DO NOT REPLY.
[1]: This is just an example and I don't remember the right values so the getfenv offsets might be wrong, but basically this is the code:
local globalstringmetatable = getmetatable''
debug.setmetatable('', {
__index = function(t,k)
local x = getmetatable(getfenv(2))
if type(x) == "table" and rawget(x, "__stringmt") then
local y = rawget(rawget(x, "__stringmt"), "__index")
if type(y) == "table" then
return y[k]
elseif type(y) == "function" then
return y(t,k)
elseif y == nil then
local y = rawget(globalstringmetatable, "__index")
if type(y) == "table" then
return y[k]
elseif type(y) == "function" then
return y(t,k)
else
error("Attempt to index a string value", 2)
end
else
error("Attempt to index a string value", 2)
end
end
end
})
|