diff --git a/lib/std/normalize/init.lua b/lib/std/normalize/init.lua index 6708165..08e01cf 100644 --- a/lib/std/normalize/init.lua +++ b/lib/std/normalize/init.lua @@ -251,7 +251,7 @@ if debug_getfenv then -- No need to recurse because Lua doesn't support nested functors. -- __call can only (sensibly) be a function, so no need to adjust -- stack frame offset either. - fn =(getmetatable(fn) or {}).__call or fn + fn = fn.call or (getmetatable(fn) or {}).__call or fn end -- In Lua 5.1, only debug.getfenv works on C functions; but it @@ -270,7 +270,7 @@ else if n then fn = debug_getinfo(n + 1 + ARGCHECK_FRAME, 'f').func elseif type(fn) ~= 'function' then - fn = (getmetatable(fn) or {}).__call or fn + fn = fn.call or (getmetatable(fn) or {}).__call or fn end local name, env @@ -440,7 +440,7 @@ if debug_setfenv then return setfenv(n, env), nil end if type(fn) ~= 'function' then - fn =(getmetatable(fn) or {}).__call or fn + fn = fn.call or (getmetatable(fn) or {}).__call or fn end return debug_setfenv(fn, env) end @@ -456,7 +456,7 @@ else end fn = debug_getinfo(n, 'f').func elseif type(fn) ~= 'function' then - fn =(getmetatable(fn) or {}).__call or fn + fn = fn.call or (getmetatable(fn) or {}).__call or fn end local up, name = 0 diff --git a/spec/init_spec.yaml b/spec/init_spec.yaml index defb0b8..a82e675 100644 --- a/spec/init_spec.yaml +++ b/spec/init_spec.yaml @@ -363,6 +363,16 @@ specify std.normalize: - it returns the environment of a functor: ftor = setmetatable({}, {__call = fn}) expect(f(ftor)).to_be(fnenv) + - it returns the environment of a functor's call function: + fn = (loadstring or load) 'return tostring(42)' + dispatcher = function(self, ...) return self.call(...) end + ftor = setmetatable({call = fn}, {__call = dispatcher}) + dispatchenv = M.getfenv(dispatcher) + fnenv = {tostring = function() return 'wrapped' end} + M.setfenv(fn, fnenv) + expect(M.getfenv(ftor)).to_be(fnenv) + expect(M.getfenv(dispatcher)).to_be(dispatchenv) + expect(ftor()).to_be 'wrapped' - it returns the global environment: # FIXME: don't break out of the sandbox in Lua 5.1 # expect(f(0)).to_be(_G) @@ -398,6 +408,18 @@ specify std.normalize: ftor = setmetatable({}, {__call = fn}) os.exit(f(ftor) == fnenv and 0 or 1) ]])).to_succeed_with '' + - it returns the environment of a functor's call function: + expect(luaproc(preamble .. [[ + local fn = (loadstring or load) 'return tostring(42)' + local dispatcher = function(self, ...) return self.call(...) end + local ftor = setmetatable({call = fn}, {__call = dispatcher}) + local dispatchenv = M.getfenv(dispatcher) + local env = {tostring = function() return 'wrapped' end} + assert(M.setfenv(fn, env) == fn) + assert(M.getfenv(ftor) == env) + assert(M.getfenv(dispatcher) == dispatchenv) + assert(ftor() == 'wrapped') + ]])).to_succeed_with '' - it returns the global environment: # FIXME: don't break out of the sandbox in Lua 5.1 expect(luaproc(preamble .. [[ @@ -889,6 +911,16 @@ specify std.normalize: ftor = setmetatable({}, {__call = fn}) r = f(ftor, fnenv) expect(ftor {}).to_be(r) + - it sets the environment of a functor's call function: + fn = (loadstring or load) 'return tostring(42)' + dispatcher = function(self, ...) return self.call(...) end + ftor = setmetatable({call = fn}, {__call = dispatcher}) + dispatchenv = M.getfenv(dispatcher) + fnenv = {tostring = function() return 'wrapped' end} + M.setfenv(ftor, fnenv) + expect(M.getfenv(ftor)).to_be(fnenv) + expect(M.getfenv(dispatcher)).to_be(dispatchenv) + expect(ftor()).to_be 'wrapped' - it sets the global environment: | pending 'what is this supposed to do, anyway?' expect(luaproc [[ @@ -926,6 +958,18 @@ specify std.normalize: r = f(ftor, fnenv) os.exit(ftor {} == r and 0 or 1) ]])).to_succeed_with '' + - it sets the environment of a functor's call function: + expect(luaproc(preamble .. [[ + local fn = (loadstring or load) 'return tostring(42)' + local dispatcher = function(self, ...) return self.call(...) end + local ftor = setmetatable({call = fn}, {__call = dispatcher}) + local dispatchenv = M.getfenv(dispatcher) + local env = {tostring = function() return 'wrapped' end} + assert(M.setfenv(ftor, env) == fn) + assert(M.getfenv(ftor) == env) + assert(M.getfenv(dispatcher) == dispatchenv) + assert(ftor() == 'wrapped') + ]])).to_succeed_with '' - it sets the global environment: | pending 'what is this supposed to do, anyway?' expect(luaproc [[