Bienvenidos sean a este post, hoy veremos como gracias a esta libreria podremos acceder a las variables locales, a las no globales y tambien a otras corutinas, comencemos con el primer acceso.
Accediendo a variables locales
Podemos inspeccionar las variables locales de las funciones activas con la siguiente funcion:
debug.getlocal
Esta funcion posee dos parametros: el nivel de la pila de la funcion que estas buscando y un indice variable, a su vez este devuelve dos valores:
- el nombre
- el valor de esta variable
Si el indice variable es mas grande que el numero de variables activas getlocal devuelve nil, si el nivel de la pila es invalido devuelve un error, para evitar esto podemos usar debug.getinfo para chequear la validez del nivel de la pila, Lua numera las variables locales en el orden que aparecen en una funcion, contando solo las variables que estan activas en el rango actual, veamos el siguiente codigo:
function foo(a,b)
local x
do local c = a - b end
local a = 1
while true do
local nombre, valor = debug.getlocal(1, a)
if not nombre then break end
print(nombre, valor)
a = a + 1
end
end
La variable con indice 1 es a (el primer parametro), 2 es b, 3 es x y 4 es la otra a, en este punto donde es llamado getlocal, c esta fuera del rango mientras que nombre y valor no son todavia del rango.
Nota: Recuerden que las variables locales son solo visibles despues de su codigo de inicializacion
Se puede cambiar tambien el valor de las variables locales con debug.setlocal, sus primeros dos parametros son el nivel de pila y el indice variable, igual a getlocal, su tercer parametro es el nuevo valor para esta variable, devuelve el nombre de la variable o nil si el indice variable esta fuera del rango, vamos a probar la funcion anterior de la siguiente manera:
> foo(10, 20)
a 10
b 20
x nil
a 4
Con esto concluimos esta seccion pasemos a la siguiente.
Accediendo a variables no locales
Esta libreria tambien nos permite acceder a las variables no locales usados por una funcion Lua con getupvalues, a diferencia de las variables locales las variables no locales referenciadas por una funcion existen incluso cuando la funcion no esta activo (esto es lo que cierres trata), por lo tanto el primer argumento para getupvalue no es un nivel de la pila pero si una funcion, en realidad un cierre para ser mas exactos, el segundo argumento es la indice variable, Lua numera las variables no locales en el orden que son referenciadas en una funcion pero este orden no es relevante porque una funcion no puede acceder a dos variables no locales con el mismo nombre, puedes tambien actualizar variables no locales con debug.setupvalue, como puedes esperar tambien tiene tres parametros, un cierre, un indice variable y el nuevo valor, como setlocal, devuelve el nombre de la variable o nil si el indice variable esta fuera del rango, veamos el siguiente codigo:
function getvarvalor(nombre)
local valor, encontrado
for i = 1, math.huge do
local a, v = debug.getlocal(2, i)
if not n then break end
if n == nombre then
valor = v
encontrado = true
end
end
if encontrado then return valor end
local func = debug.getinfo(2, "f").func
for i = 1, math.huge do
local n, v = debug.getupvalue(func, i)
if not n then break end
if n == nombre then return v end
end
return getfenv(func)[nombre]
end
Nota: Este programa funcionara correctamente hasta la version 5.1 de Lua para versiones posteriores se debe realizar unas modificaciones.
Este codigo muestra como se puede acceder al valor de cualquier variable informada de una funcion de llamada, dado el nombre de la variable, primero intentamos una variable local si hay mas de una con el nombre informado debemos conseguir la unica con el indice mas alto, asi que debemos pasar siempre atraves del bucle, si no podemos encontrar ningun variable local con ese nombre luego intentamos con las variables no locales, primero conseguimos la funcion de llamada con debug.getinfo y luego atravesamos sus variables no locales, si tampoco podemos encontrar una variable no local con ese nombre, despues conseguimos una variable global, observen que el uso del numero 2 como el primer argumento en las llamadas a debug.getlocal y debug.getinfo para acceder a la funcion de llamada.
Accediendo a otras corutinas
Todas las funciones introspectivas de esta libreria aceptan una corutina opcional, como su primer argumento, asi podemos inspeccionar las corutinas desde afuera, consideremos el siguiente ejemplo:
co = coroutine.create(function()
local x = 10
coroutine.yield()
error("Algun error")
end)
coroutine.resume(co)
print(debug.traceback(co))
La llamada a traceback trabajara en coroutine.co, resultando en algo como esto:
stack traceback:
[C]: in function 'coroutine.yield'
stdin:3: in function <stdin:1>
El rastro no va atraves de la llamada para reanudar (resume) porque la corutina y el programa principal corren en diferentes pilas, si una corutina devuelve un error este no desenrolla su pila, esto significa que podemos inspeccionarlo despues del error, continuando con nuestro ejemplo si reanudamos la corutina de nuevo devuelve este error:
> print(coroutine.resume(co))
false stdin:4: Algun error
Si imprimimos su rastro conseguimos algo como esto:
> print(debug.traceback(co))
stack traceback:
[C]: in function 'error'
stdin:4: in function <stdin:1>
Podemos tambien inspeccionar variables locales de una corutina incluso despues de un error:
> print(debug.getlocal(co, 1, 1))
x 10
En resumen, hoy hemos continuado con funciones introspectivas, hemos visto como acceder a variables locales de una funcion, variables no locales de una funcion, como acceder a una corutina, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.
Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.50