Manejo de errores en Lua

El manejo de errores es necesario durante la ejecución del programa; en operaciones de archivos, transferencia de datos y llamadas a servicios web pueden ocurrir errores inesperados. Si no se presta atención al manejo de la información de errores, esto puede provocar fugas de información, fallos del programa, etc.

En cualquier lenguaje de programación se necesita el manejo de errores. Los tipos de errores son:

  • Error de sintaxis
  • Error de ejecución

Error de sintaxis

Los errores de sintaxis suelen deberse al uso incorrecto de componentes del programa (como operadores, expresiones). Un ejemplo sencillo es el siguiente:

-- test.lua 文件
a == 2

El resultado de ejecutar el código anterior es:

lua: test.lua:2: syntax error near '=='

Como puedes ver, arriba se produjo un error de sintaxis; un signo "=" es diferente de dos signos "=". Un "=" es una expresión de asignación y dos "=" son una operación de comparación.

Otro ejemplo:

Ejemplo

for a= 1,10
   print(a)
end

Al ejecutar el programa anterior aparecerá el siguiente error:

lua: test2.lua:2: 'do' expected near 'print'

Los errores de sintaxis son más simples que los errores de ejecución; los errores de ejecución no permiten localizar el error específico, mientras que los errores de sintaxis podemos resolverlos rápidamente. Por ejemplo, en el caso anterior solo necesitamos agregar do debajo de la declaración for:

Ejemplo

for a= 1,10
do
   print(a)
end

Error de ejecución

Un error de ejecución ocurre cuando el programa puede ejecutarse normalmente, pero muestra un mensaje de error. Como en el siguiente ejemplo, debido a una entrada incorrecta de parámetros, el programa reporta un error al ejecutarse:

function add(a,b)
   return a+b
end

add(10)

Cuando compilamos y ejecutamos el siguiente código, la compilación puede ser exitosa, pero al ejecutarlo se producirá el siguiente error:

lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value)
stack traceback:
    test2.lua:2: in function 'add'
    test2.lua:5: in main chunk
    [C]: ?

En Lua, al llamar a una función, incluso si la lista de argumentos reales no coincide con la lista de parámetros formales, la llamada puede tener éxito; los argumentos sobrantes se descartan y los parámetros faltantes se completan con nil.

El mensaje de error anterior se debe a que, después de que el parámetro b se completó con nil, nil participó en la operación +.

Siadddentro de la función no es"return a+b"sino"print(a,b)"en ese caso, el resultado se convertiría en"10 nil"no se reportaría un error.


Manejo de errores

Podemos usar dos funciones: assert y error para manejar errores. Ejemplo:

Ejemplo

local function add(a,b)
   assert(type(a) == "number", "a no es un número")
   assert(type(b) == "number", "b no es un número")
   return a+b
end
add(10)

Al ejecutar el programa anterior aparecerá el siguiente error:

lua: test.lua:3: b 不是一个数字
stack traceback:
    [C]: in function 'assert'
    test.lua:3: in local 'add'
    test.lua:6: in main chunk
    [C]: in ?

En el ejemplo, assert primero verifica el primer parámetro; si no hay problema, assert no hace nada; de lo contrario, assert lanza el segundo parámetro como mensaje de error.

La función error

Formato de sintaxis:

error (message [, level])

Función: termina la función que se está ejecutando y devuelve el contenido de message como información de error (la función error nunca retorna).

Normalmente, error añade cierta información sobre la ubicación del error al inicio de message.

El parámetro Level indica la ubicación del error a obtener:

  • Level=1 [por defecto]: es la ubicación donde se llama a error (archivo + número de línea)
  • Level=2: indica la función que llamó a la función que invocó a error
  • Level=0: no se añade información de ubicación del error

pcall y xpcall, debug

En Lua, para manejar errores, se puede usar la función pcall (protected call) para envolver el código que necesita ejecutarse.

pcall recibe una función y los argumentos que se le pasarán a esta, y la ejecuta. Resultado de la ejecución: con error o sin error; devuelve true o false, e info de error.

El formato de sintaxis es el siguiente

if pcall(function_name, ….) then
-- 没有错误
else
-- 一些错误
end

Ejemplo sencillo:

Ejemplo

> =pcall(function(i) print(i) end, 33)
33
true
   
> =pcall(function(i) print(i) error('error..') end, 33)
33
false        stdin:1: error..
> function f() return false,2 end
> if f() then print '1' else print '0' end
0

pcall llama al primer argumento en un "modo protegido", por lo que pcall puede capturar cualquier error durante la ejecución de la función.

Generalmente, cuando ocurre un error, se espera obtener más información de depuración, no solo la ubicación del error. Pero cuando pcall retorna, ya ha destruido parte del contenido de la pila de llamadas.

Lua proporciona la función xpcall, que recibe un segundo parámetro: una función de manejo de errores. Cuando ocurre un error, Lua llama a la función de manejo de errores antes de desplegar (unwind) la pila de llamadas, de modo que se pueda usar la biblioteca debug en esta función para obtener información adicional sobre el error.

La biblioteca debug proporciona dos funciones generales de manejo de errores:

  • debug.debug: proporciona un prompt de Lua para que el usuario examine la causa del error.
  • debug.traceback: construye un mensaje de error extendido basado en la pila de llamadas.
>=xpcall(function(i) print(i) error('error..') end, function() print(debug.traceback()) end, 33)
33
stack traceback:
stdin:1: in function <stdin:1>
[C]: in function 'error'
stdin:1: in function <stdin:1>
[C]: in function 'xpcall'
stdin:1: in main chunk
[C]: in ?
false        nil

Ejemplo 2 de uso de xpcall:

Ejemplo

function myfunction ()
   n = n/nil
end

function myerrorhandler( err )
   print( "ERROR:", err )
end

status = xpcall( myfunction, myerrorhandler )
print( status)

Al ejecutar el programa anterior aparecerá el siguiente error:

ERROR:    test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value)
false
Otras extensiones