Bienvenidos sean a este post, hoy hablaremos sobre uno de los dos tipos de funciones disponibles en la libreria debug como son las introspectivas.

Anuncios

Su funcion principal es debug.getinfo, el primer parametro de esta funcion es una funcion o un nivel de la pila, por ejemplo si nosotros llamamos a:

degug.getinfo(foo) 
Anuncios

Te devuelve una tabla con algunos datos sobre la funcion foo y esta podria tener alguno de los siguientes campos:

  • source, donde se definio a la funcion
  • short_src, una version corta de hasta 60 caracteres
  • linedefined, la primera linea de la fuente (source) donde la funcion fue definida
  • lastlinedefined, similar al anterior pero con la ultima linea
  • what, devuelve que tipo de funcion es
  • name, devuelve un nombre razonable para la funcion
  • namewhat, que tipo de campo es
  • nups, el numero de upvalues de la funcion
  • activelines, una tabla representando el conjunto de lineas activas de la funcion
  • func, la funcion en si misma
Anuncios

Continuando con la tabla, en source si la funcion fue definida en una cadena (p.e. a traves de loadstring) source sera la cadena, en cambio si la funcion fue definida en un archivo source sera el nombre del archivo con una arroba (@) adelante, short_src es utilizado habitualmente para mensajes de error, what puede devolvernos un valor “Lua” si es una funcion comun de Lua, “C” si es una funcion de C o “main” si es parte principal del chunk de Lua, namewhat puede devolvernos:

  • global
  • local
  • method
  • field
  • “” (cadena vacia)
Anuncios

Este ultimo valor significa que Lua no pudo encontrar un nombre para la funcion, para que activelines considere una linea activa esta linea debe tener algun codigo como oposicion a lineas vacias o lineas conteniendo solo comentarios, un uso tipico de esta informacion es para setear un breakpoint porque .Lua no te permitira usarlo por fuera de una linea activa, por ultimo a func lo veremos mas adelante.

Anuncios

Vamos a suponer que foo es una funcion de C, Lua no posee mucha informacion sobre ella, por eso para tales funciones solo los campos what, name y namewhat son relevantes, cuando llamas a debug.getinfo(n) para algun numero n, consigues la informacion y la funcion activa a ese nivel de la pila, por ejemplo si n es 1 te entrega la funcion haciendo la llamada (cuando n es 0 te devuelve informacion sobre getinfo, una funcion de C), si n es mas grande que la cantidad de funciones activas en la pila getinfo devuelve nil, cuando se busca una funcion activa llamando a debug.getinfo con un numero la tabla resultante tiene un campo extra, currentline, con el numero de linea donde la funcion esta en ese momento, ademas func tiene la funcion que esta activa en ese nivel.

Anuncios

El campo name es engañoso porque las funciones son valores de primera clase en Lua, una funcion podria no tener nombre o podria tener varios nombres, Lua intenta encontrar un nombre para una funcion mirando dentro del codigo que llamo a la funcion, para ver como fue llamada, este metodo trabaja solo cuando llamamos a getinfo con un numero es decir que obtenemos informacion sobre una invocacion en particular, si bien la funcion getinfo no es eficiente, Lua mantiene la informacion de depuracion en una forma que no afecta la ejecucion del programa, la recuperacion eficiente es una segunda meta aqui.

Anuncios

Para obtener una mejor performance getinfo tiene un segundo parametro opcional que selecciona cual informacion conseguir, con este parametro la funcion no desperdicia tiempo recolectando informacion que el usuario no necesita, el formato de este parametro es una cadena donde cada letra selecciona un grupo de campos, de acuerdo a la siguiente tabla:

ParametroDescripcion
nElige name y namewhat
fElige func
SElige source, short_src, what, linedefined y lastlinedefined
lElige currentline
LElige activelines
uElige nup
Anuncios

La siguiente funcion ilustra como funciona debug.getinfo, la cual imprime un rastreo primitivo de la pila activa:

function rastrear()
	for nivel = 1, math.huge do
		local info = debug.getinfo(nivel, "Sl")
		if not info then break end
		if info.what == "C" then
			print(nivel, "Funcion de C")
		else
			print(string.format("[%s]:%d", info.short_src,
					info.currentline))
		end
	end
end
Anuncios

En este caso usaremos un bucle for que nos mostrara nivel por nivel, primero en una variable local llamada info almacenaremos a debug.info, miren la tabla para ver que informacion, luego chequearemos si info esta vacio sale del for, luego chequeamos si what es igual a C, en ese caso mostramos el nivel y una etiqueta de lo contrario consideramos que es de Lua y en este caso mostraremos el nombre corto (short_src) y la linea actual (currentline), si lo probamos veremos algo semejante a esto:

> rastrear()
[stdin]:3
2       Funcion de C
Anuncios

No seria muy dificil mejorar esta funcion incluyendo mas datos de getinfo aunque en realidad la libreria debug posee una version mejorada de nuestra funcion rastrear (traceback), a diferencia de nuestra funcion la version de la libreria llamada debug.traceback no imprime sus resultados sino que devuelve una cadena, usualmente larga, con el rastro o traceback, este seria un ejemplo:

> debug.traceback()
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
Anuncios

En resumen, hoy hemos visto como es una funcion introspectiva, para que se usa, como se usa, que datos nos devuelve, como podemos usarla en un simple ejemplo y que parametros son realmente utiles para algun tipo de funcion, 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