lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


You could simulate such a behavior by using metatables in the environment
tables. Like this:

environment = {}


setmetatable(environment,
  {
    __index = function (self,key)
      local value = _G[key]
      
      if type(value) == "function" then
        return function (...)
          local prevenv = getfenv(value)
          pcall(setfenv,value,environment) 
            -- C Function environments cannot be overridden
            -- and will throw error, thus just pcall it
          local arg = {value(...)}
          pcall(setfenv,value,prevenv)
          return unpack(arg)
        end  
      end
      return value
    end
  }
)

function boo ()
  print("environment value:  a =",a)
end

function foo ()
  boo()
end

function sandbox ()
  a = 10 -- set a to 10, but this will only affect 
   -- the environment table, not _G!
  foo()
end

setfenv(sandbox,environment)

foo() -- prints out a = nil 
sandbox() -- prints out a = 10 - boo() inherited environment
foo() -- prints out a = nil again - just correct

-- end

The problem here is, that it is not performant (at least not this code) and its
also not very elegant. Setting the environment tables each call... that's not
pretty. But at least it works - as long as no C Function is hit that calls a
lua function again. You have to override the C Functions then with lua
functions that handle these special cases.
But maybe there's an more elegant solution for that problem.

Eike

> Hi,
> 
> Is there any way to set the environment of a function such that all  
> functions it calls will also inherit this environment?  In the  
> example below, I change the environment of fmain, which in turn calls  
> fsub, but the environment of fsub is unchanged.
> 
> I also tried changing the environment in fmain using setfenv(1, e)  
> but it still doesn't affect fsub.  Setting the global environment via  
> setfenv(0, e) affects everything in the program. Would changing the  
> environment via C (LUA_GLOBALSINDEX perhaps?) achieve what I want, or  
> is that the equivalent of setfenv(0)?  Basically, is it possible for  
> a function to have the environment dynamically bound, or is it fixed  
> at creation/setfenv time?
> 
> fsub = function()
> 	print("fsub", getfenv(0), getfenv(1))
> 	b = 1
> end
> 
> fmain = function()
> 	print("fmain", getfenv(0), getfenv(1))
> 	a = 1
> 	fsub()
> end
> 
> e = { __index = getfenv(0) }
> setmetatable(e, e)
> 
> setfenv(fmain, e)
> 
> fmain()
> 
> print(a, b)
> print(e.a, e.b)
> 
> outputs:
> fmain	table: 0x1452a450	table: 0x1452f010
> fsub	table: 0x1452a450	table: 0x1452a450
> nil	1
> 1	1
> 
> 
> 
> 
> 
>