Anuncios

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.

Anuncios

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
Anuncios

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
Anuncios

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
Anuncios

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.

Anuncios

Accediendo a variables no locales

Anuncios

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.
Anuncios

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.

Anuncios

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))
Anuncios

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>
Anuncios

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
Anuncios

Si imprimimos su rastro conseguimos algo como esto:

> print(debug.traceback(co))
stack traceback:
        [C]: in function 'error'
        stdin:4: in function <stdin:1>
Anuncios

Podemos tambien inspeccionar variables locales de una corutina incluso despues de un error:

> print(debug.getlocal(co, 1, 1))
x       10
Anuncios

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.00