Wednesday, December 30, 2009

Accessing Upvalues













Programming in Lua
Part III. The Standard Libraries
            
Chapter 23. The Debug Library



23.1.2 - Accessing Upvalues



The debug library also allows us to
access the upvalues that a Lua function uses,
with getupvalue.
Unlike local variables, however,
a function has its upvalues even when it is not active
(this is what closures are about, after all).
Therefore, the first argument for getupvalue is not a stack level,
but a function (a closure, more precisely).
The second argument is the upvalue index.
Lua numbers upvalues in the order they are first referred in a function,
but this order is not relevant,
because a function cannot have two upvalues with the same name.

You can also update upvalues,
with debug.setupvalue.
As you might expect, it has three parameters:
a closure, an upvalue index, and the new value.
Like setlocal, it returns the name of the upvalue,
or nil if the upvalue index is out of range.

The following code shows how we can access the value
of any given variable of a calling function,
given the variable name:


function getvarvalue (name)
local value, found

-- try local variables
local i = 1
while true do
local n, v = debug.getlocal(2, i)
if not n then break end
if n == name then
value = v
found = true
end
i = i + 1
end
if found then return value end

-- try upvalues
local func = debug.getinfo(2).func
i = 1
while true do
local n, v = debug.getupvalue(func, i)
if not n then break end
if n == name then return v end
i = i + 1
end

-- not found; get global
return getfenv(func)[name]
end

First, we try a local variable.
If there is more than one variable with the given name,
we must get the one with the highest index;
so we must always go through the whole loop.
If we cannot find any local variable with that name,
then we try upvalues.
First, we get the calling function,
with debug.getinfo(2).func,
and then we traverse its upvalues.
Finally, if we cannot find an upvalue with that name,
then we get a global variable.
Notice the use of the argument 2 in the calls
to debug.getlocal and debug.getinfo
to access the calling function.










Programming in Lua



No comments: