# Getting Variables From Values

If we have a value, can we obtain its variable? For example, can a function return the names of the variables passed to it?

```f(x,y) --> 'x', 'y'
```

Or can Lua support "pass-by-reference" (or maybe even "pass-by-name") calling semantics?

```local a = 10; local b = 11
print(a,b) --> 10,11
swap(a,b)
print(a,b) --> 11,10
```

The answer is not normally. However, with some byte code inspection (using the lbci library [1]) and Lua debug library hackery, it may be possible...

Note first the bytecode in a typical function call:

```\$ echo -e 'local x = {2,3};\n local y = 4;\n f(x,y,z)' | luac -p -l -
main <stdin:0,0> (11 instructions, 44 bytes at 0x6d0ea8)
0+ params, 6 slots, 0 upvalues, 2 locals, 5 constants, 0 functions
1       [1]     NEWTABLE        0 2 0
2       [1]     LOADK           1 -1    ; 2
3       [1]     LOADK           2 -2    ; 3
4       [1]     SETLIST         0 2 1   ; 1
5       [2]     LOADK           1 -3    ; 4
6       [3]     GETGLOBAL       2 -4    ; f
7       [3]     MOVE            3 0
8       [3]     MOVE            4 1
9       [3]     GETGLOBAL       5 -5    ; z
10      [3]     CALL            2 4 1
11      [3]     RETURN          0 1
```

The instructions prior to the CALL move the variables into place. Here's how we might make use of that:

```-- D.Manura, 2009-10. Public domain.

require "bci"

-- Returns list of variables passed to function at given
-- stack level number `level`.  `level` defaults to 1, the calling
-- function, if omitted. If confused, returns nothing.
-- See code for format of variables.
-- WARNING: This code is experimental.  Not intended for production use.
local mt
local function getargvariables(level)
mt = mt or {__tostring = function(t)
local s = '{'
for i=1,#t do
s = s .. (i==1 and '' or ',') .. tostring(t[i])
end
s = s .. '}'
return s
end}

-- Get function info.
level = (level or 1) + 2
local f = debug.getinfo(level,'f').func
if not f then return end -- could be a tail call
local currentline = debug.getinfo(level,'l').currentline

-- Get instruction pointer of call.
-- Unfortunately, we only have the line number from which to infer the
-- instruction pointer.  So, we can only do this unambiguously when the
-- call is the only call on its line.  Perhaps bci or debug.getinfo
-- could be patched to return the exact instruction pointer.
local count = 0
local currentip
for i=1,F.instructions do
local line, opcode, a, b, c = inspector.getinstruction(f,i)
if line == currentline and opcode == "CALL" then
currentip = i
count = count + 1
end
end
if count ~= 1 then return end -- ambiguous, return nothing

-- Get CALL opcode data
local _,_,idxfunc,nparamsp,_ = inspector.getinstruction(f,currentip)

-- Get arguments.
local names = {}
for i=1,nparamsp-1 do
local _,opcode,a,b,c = inspector.getinstruction(f,currentip-i)
if opcode == 'MOVE' and a == idxfunc + nparamsp - i then -- local
local varname,_,_ = inspector.getlocal(f,b+1)
names[nparamsp - i] = setmetatable({'local', varname, b+1}, mt)
elseif opcode == 'GETGLOBAL' and b < 0 then -- global
local varname = inspector.getconstant(f,-b)
names[nparamsp - i] = setmetatable({'global', varname}, mt)
else
return -- other possibilities not currently implemented
end
end
return unpack(names, 1, nparamsp-1)
end

-- Set variable `var` (as returned by `getargvariables`) in context of
-- stack level number `level` to value `value`.
local function setvariable(level, var, value)
level = (level or 1) + 1
if var[1] == 'local' then
local varname, idx = var[2], var[3]
debug.setlocal(level, idx, value)
elseif var[1] == 'global' then
local varname = var[2]
getfenv(2)[varname] = value
else
assert(false)
end
end

-- TESTS

local function f(a,b)
print(getargvariables()) --> {local,y,5} {local,z,6} {global,w}
end

do
local y=1
local z=2
f(y,z,w)
end

local function swap(x,y)
local xvar, yvar = getargvariables()
assert(xvar and yvar)
setvariable(2, xvar, y)
setvariable(2, yvar, x)
end

a = 10
local b = 11
print(a,b) --> 10,11
swap(a,b)
print(a,b) --> 11,10

print 'DONE'
```

As is, the above is not intended for production use. The above could be generalized further. Please do so if you are so inclined.