Empezando con Lua

Comentarios

Los comentarios de una sola línea en Lua comienzan con -- y continúan hasta el final de la línea:

-- this is single line comment
-- need another line
-- huh?

Los comentarios en bloque comienzan con --[[ y terminan con ]]:

--[[
    This is block comment.
    So, it can go on...
    and on...
    and on....
]]

Los comentarios de bloque usan el mismo estilo de delimitadores que las cadenas largas; Se puede agregar cualquier número de signos de igual entre los corchetes para delimitar un comentario:

--[=[
    This is also a block comment
    We can include "]]" inside this comment
--]=]

--[==[
    This is also a block comment
    We can include "]=]" inside this comment
--]==]

Un buen truco para comentar fragmentos de código es rodearlo con --[[ y --]]:

--[[
    print'Lua is lovely'
--]]

Para reactivar el fragmento, simplemente agrega un - a la secuencia de apertura del comentario:

---[[
    print'Lua is lovely'
--]]

De esta forma, la secuencia -- en la primera línea inicia un comentario de una sola línea, al igual que la última línea, y la instrucción print no se comenta.

Yendo un paso más allá, se pueden configurar dos bloques de código de tal manera que si el primer bloque está comentado, el segundo no lo estará, y viceversa:

---[[
  print 'Lua is love'
--[=[]]
  print 'Lua is life'
--]=]

Para activar el segundo fragmento mientras deshabilita el primero, elimine el - inicial en la primera línea:

--[[
  print 'Lua is love'
--[=[]]
  print 'Lua is life'
--]=]

Instalación

Binarios

La mayoría de las distribuciones de GNU/Linux proporcionan los binarios de Lua como un paquete.

Por ejemplo, en Debian, Ubuntu y sus derivados se puede adquirir ejecutando esto:

sudo apt-get install lua50
sudo apt-get install lua51
sudo apt-get install lua52

Se proporcionan algunas compilaciones semioficiales para Windows, MacOS y algunos otros sistemas operativos alojados en SourceForge.

Los usuarios de Apple también pueden instalar Lua fácilmente usando Homebrew:

brew install lua

(Actualmente Homebrew tiene 5.2.4, para 5.3 ver Homebrew/versions.)

Fuente

La fuente está disponible en [la página oficial] (https://www.lua.org/download.html). La adquisición de fuentes y la construcción en sí deberían ser triviales. En los sistemas Linux, lo siguiente debería ser suficiente:

$ wget http://lua.org/ftp/lua-5.3.3.tar.gz
$ echo "a0341bc3d1415b814cc738b2ec01ae56045d64ef ./lua-5.3.3.tar.gz" | sha1sum -c -
$ tar -xvf ./lua-5.3.3.tar.gz
$ make -C ./lua-5.3.3/ linux

En el ejemplo anterior, básicamente estamos descargando un tarball fuente del sitio oficial, verificando su suma de verificación y extrayendo y ejecutando make. (Compruebe dos veces la suma de comprobación en la página oficial.)

Nota: debe especificar qué objetivo de compilación desea. En el ejemplo, especificamos linux. Otros objetivos de compilación disponibles incluyen solaris, aix, bsd, freebsd, macosx, mingw, etc. Consulte doc/readme.html, que se incluye en el código fuente, para obtener más información. detalles. (También puede encontrar la última versión del LÉAME en línea.)

Módulos

Las bibliotecas estándar están limitadas a primitivas:

  • coroutine - funcionalidad de gestión de coroutine
  • debug - ganchos y herramientas de depuración
  • io - primitivas básicas de E/S
  • paquete - funcionalidad de gestión de módulos
  • string - funcionalidad de coincidencia de patrones específicos de string y Lua
  • tabla - primitivas para tratar con un tipo Lua esencial pero complejo - tablas
  • os - operaciones básicas del sistema operativo
  • utf8 - primitivas UTF-8 básicas (desde Lua 5.3)

Todas esas bibliotecas pueden deshabilitarse para una compilación específica o cargarse en tiempo de ejecución.

La infraestructura y las bibliotecas Lua de terceros para distribuir módulos son escasas, pero están mejorando. Proyectos como LuaRocks, Lua Toolbox y LuaDist están mejorando la situación. Se puede encontrar mucha información y muchas sugerencias en el antiguo Lua Wiki, pero tenga en cuenta que parte de esta información es bastante antigua y está desactualizada.

Empezando

Variables

var = 50 -- a global variable
print(var) --> 50
do
  local var = 100 -- a local variable
  print(var) --> 100
end
print(var) --> 50
-- The global var (50) still exists 
-- The local var (100) has gone out of scope and can't be accessed any longer.

tipos

num = 20 -- a number
num = 20.001 -- still a number
str = "zaldrizes buzdari iksos daor" -- a string
tab = {1, 2, 3} -- a table (these have their own category)
bool = true -- a boolean value
bool = false -- the only other boolean value
print(type(num)) --> 'number'
print(type(str)) --> 'string'
print(type(bool)) --> 'boolean'
type(type(num)) --> 'string'

-- Functions are a type too, and first-class values in Lua.
print(type(print)) --> prints 'function'
old_print = print
print = function (x) old_print "I'm ignoring the param you passed me!" end
old_print(type(print)) --> Still prints 'function' since it's still a function.
-- But we've (unhelpfully) redefined the behavior of print.
print("Hello, world!") --> prints "I'm ignoring the param you passed me!"

El tipo especial nil

Otro tipo en Lua es nil. El único valor en el tipo nil es nil. nil existe para ser diferente de todos los demás valores en Lua. Es una especie de valor sin valor.

print(foo) -- This prints nil since there's nothing stored in the variable 'foo'.
foo = 20
print(foo) -- Now this prints 20 since we've assigned 'foo' a value of 20.

-- We can also use `nil` to undefine a variable
foo = nil -- Here we set 'foo' to nil so that it can be garbage-collected.

if nil then print "nil" end --> (prints nothing)
-- Only false and nil are considered false; every other value is true.
if 0 then print "0" end --> 0
if "" then print "Empty string!" --> Empty string!

expresiones

a = 3
b = a + 20 a = 2 print(b, a) -- hard to read, can also be written as
b = a + 20; a = 2; print(a, b) -- easier to read, ; are optional though
true and true --> returns true
true and 20 --> 20
false and 20 --> false
false or 20 --> 20
true or 20 --> true
tab or {}
  --> returns tab if it is defined
  --> returns {} if tab is undefined
  -- This is useful when we don't know if a variable exists
tab = tab or {} -- tab stays unchanged if it exists; tab becomes {} if it was previously nil.

a, b = 20, 30 -- this also works
a, b = b, a -- switches values

Definición de funciones

function name(parameter)
    return parameter
end
print(name(20)) --> 20
-- see function category for more information
name = function(parameter) return parameter end -- Same as above

booleanos

Solo falso y nil se evalúan como falsos, todo lo demás, incluidos 0 y la cadena vacía, se evalúan como verdaderos.

recolección de basura

tab = {"lots", "of", "data"}
tab = nil; collectgarbage()
-- tab does no longer exist, and doesn't take up memory anymore.

mesas

tab1 = {"a", "b", "c"}
tab2 = tab1
tab2[1] = "d"
print(tab1[1]) --> 'd' -- table values only store references.
--> assigning tables does not copy its content, only the reference.

tab2 = nil; collectgarbage()
print(tab1) --> (prints table address) -- tab1 still exists; it didn't get garbage-collected.

tab1 = nil; collectgarbage()
-- No more references. Now it should actually be gone from memory.

Estos son los conceptos básicos, pero hay una sección sobre tablas con más información.

condiciones

if (condition) then
    -- do something
elseif (other_condition) then
    -- do something else
else
    -- do something
end

para bucles

Hay dos tipos de bucles for en Lua: un bucle for numérico y un bucle for genérico.

  • Un bucle for numérico tiene la siguiente forma:

    for a=1, 10, 2 do -- for a starting at 1, ending at 10, in steps of 2
      print(a) --> 1, 3, 5, 7, 9
    end
    

    The third expression in a numeric for loop is the step by which the loop will increment. This makes it easy to do reverse loops:

     for a=10, 1, -1 do
       print(a) --> 10, 9, 8, 7, 6, etc.
     end
    

    If the step expression is left out, Lua assumes a default step of 1.

     for a=1, 10 do
       print(a) --> 1, 2, 3, 4, 5, etc.
     end
    

    Also note that the loop variable is local to the for loop. It will not exist after the loop is over.

  • Los bucles for genéricos funcionan a través de todos los valores que devuelve una función iteradora:

    for key, value in pairs({"some", "table"}) do
      print(key, value)
      --> 1 some
      --> 2 table
    end
    

Lua proporciona varios iteradores integrados (por ejemplo, pairs, ipairs), y los usuarios pueden definir sus propios iteradores personalizados para usarlos con bucles for genéricos.

hacer bloques

local a = 10
do
    print(a) --> 10
    local a = 20
    print(a) --> 20
end
print(a) --> 10

Algunas cosas difíciles

A veces Lua no se comporta como uno pensaría después de leer la documentación. Algunos de estos casos son:

Nil y Nothing no son lo mismo (¡ERROR COMÚN!)

Como era de esperar, table.insert(my_table, 20) agrega el valor 20 a la tabla, y table.insert(my_table, 5, 20) agrega el valor 20 en la quinta posición. ¿Qué hace table.insert(my_table, 5, nil)? Uno podría esperar que tratara nil como ningún argumento e inserte el valor 5 al final de la tabla, pero en realidad agrega el valor nil en la quinta posición de la tabla. ¿Cuándo es esto un problema?

(function(tab, value, position)
    table.insert(tab, position or value, position and value)
end)({}, 20)
-- This ends up calling table.insert({}, 20, nil)
-- and this doesn't do what it should (insert 20 at the end)

Algo similar sucede con tostring():

print (tostring(nil)) -- this prints "nil"
table.insert({}, 20) -- this returns nothing
-- (not nil, but actually nothing (yes, I know, in lua those two SHOULD
-- be the same thing, but they aren't))

-- wrong:
print (tostring( table.insert({}, 20) ))
-- throws error because nothing ~= nil

--right:
local _tmp = table.insert({}, 20) -- after this _tmp contains nil
print(tostring(_tmp)) -- prints "nil" because suddenly nothing == nil

Esto también puede dar lugar a errores al utilizar código de terceros. Si, por ejemplo, la documentación de alguna función dice “devuelve donuts si tiene suerte, nil de lo contrario”, la implementación podría parecerse a esto

function func(lucky)
    if lucky then
        return "donuts"
    end
end

esta implementación puede parecer razonable al principio; devuelve donuts cuando tiene que hacerlo, y cuando escribe result = func(false), el resultado contendrá el valor nil.

Sin embargo, si se escribiera print(tostring(func(false))) lua arrojaría un error que se parece a este stdin:1: bad argument #1 to 'tostring' (valor esperado)

¿Porqué es eso? tostring claramente obtiene un argumento, aunque sea nil. Equivocado. func no devuelve nada en absoluto, por lo que tostring(func(false)) es lo mismo que tostring() y NO lo mismo que tostring(nil).

Los errores que dicen “valor esperado” son una fuerte indicación de que esta podría ser la fuente del problema.

Dejando espacios en las matrices

Esta es una gran trampa si eres nuevo en lua, y hay mucha [información] (https://www.wikiod.com/es/lua/mesas#Evitar espacios en las tablas utilizadas como matrices as-arrays#t=20170113143427074516) en la categoría tables

Ejecutando programas Lua

Por lo general, Lua se envía con dos binarios:

  • lua - intérprete independiente y consola interactiva
  • luac - compilador de código de bytes

Digamos que tenemos un programa de ejemplo (bottles_of_mate.lua) como este:

local string = require "string"    

function bottle_take(bottles_available)

    local count_str = "%d bottles of mate on the wall."
    local take_str = "Take one down, pass it around, " .. count_str
    local end_str = "Oh noes, " .. count_str
    local buy_str = "Get some from the store, " .. count_str
    local bottles_left = 0

    if bottles_available > 0 then
         print(string.format(count_str, bottles_available))
         bottles_left = bottles_available - 1
         print(string.format(take_str, bottles_left))
    else
        print(string.format(end_str, bottles_available))
        bottles_left = 99
        print(string.format(buy_str, bottles_left))
    end

    return bottles_left
end

local bottle_count = 99

while true do
    bottle_count = bottle_take(bottle_count)
end

El programa en sí se puede ejecutar ejecutando lo siguiente en su shell:

$ lua bottles_of_mate.lua

La salida debería verse así, ejecutándose en el ciclo sin fin:

Get some from the store, 99 bottles of mate on the wall.
99 bottles of mate on the wall.
Take one down, pass it around, 98 bottles of mate on the wall.
98 bottles of mate on the wall.
Take one down, pass it around, 97 bottles of mate on the wall.
97 bottles of mate on the wall.
...
...
3 bottles of mate on the wall.
Take one down, pass it around, 2 bottles of mate on the wall.
2 bottles of mate on the wall.
Take one down, pass it around, 1 bottles of mate on the wall.
1 bottles of mate on the wall.
Take one down, pass it around, 0 bottles of mate on the wall.
Oh noes, 0 bottles of mate on the wall.
Get some from the store, 99 bottles of mate on the wall.
99 bottles of mate on the wall.
Take one down, pass it around, 98 bottles of mate on the wall.
...

Puede compilar el programa en el código de bytes de Lua ejecutando lo siguiente en su shell:

$ luac bottles_of_mate.lua -o bottles_of_mate.luac

También está disponible la lista de códigos de bytes ejecutando lo siguiente:

$ luac -l bottles_of_mate.lua


main <./bottles.lua:0,0> (13 instructions, 52 bytes at 0x101d530)
0+ params, 4 slots, 0 upvalues, 2 locals, 4 constants, 1 function
    1    [1]    GETGLOBAL    0 -1    ; require
    2    [1]    LOADK        1 -2    ; "string"
    3    [1]    CALL         0 2 2
    4    [22]    CLOSURE      1 0    ; 0x101d710
    5    [22]    MOVE         0 0
    6    [3]    SETGLOBAL    1 -3    ; bottle_take
    7    [24]    LOADK        1 -4    ; 99
    8    [27]    GETGLOBAL    2 -3    ; bottle_take
    9    [27]    MOVE         3 1
    10    [27]    CALL         2 2 2
    11    [27]    MOVE         1 2
    12    [27]    JMP          -5    ; to 8
    13    [28]    RETURN       0 1

function <./bottles.lua:3,22> (46 instructions, 184 bytes at 0x101d710)
1 param, 10 slots, 1 upvalue, 6 locals, 9 constants, 0 functions
    1    [5]    LOADK        1 -1    ; "%d bottles of mate on the wall."
    2    [6]    LOADK        2 -2    ; "Take one down, pass it around, "
    3    [6]    MOVE         3 1
    4    [6]    CONCAT       2 2 3
    5    [7]    LOADK        3 -3    ; "Oh noes, "
    6    [7]    MOVE         4 1
    7    [7]    CONCAT       3 3 4
    8    [8]    LOADK        4 -4    ; "Get some from the store, "
    9    [8]    MOVE         5 1
    10    [8]    CONCAT       4 4 5
    11    [9]    LOADK        5 -5    ; 0
    12    [11]    EQ           1 0 -5    ; - 0
    13    [11]    JMP          16    ; to 30
    14    [12]    GETGLOBAL    6 -6    ; print
    15    [12]    GETUPVAL     7 0    ; string
    16    [12]    GETTABLE     7 7 -7    ; "format"
    17    [12]    MOVE         8 1
    18    [12]    MOVE         9 0
    19    [12]    CALL         7 3 0
    20    [12]    CALL         6 0 1
    21    [13]    SUB          5 0 -8    ; - 1
    22    [14]    GETGLOBAL    6 -6    ; print
    23    [14]    GETUPVAL     7 0    ; string
    24    [14]    GETTABLE     7 7 -7    ; "format"
    25    [14]    MOVE         8 2
    26    [14]    MOVE         9 5
    27    [14]    CALL         7 3 0
    28    [14]    CALL         6 0 1
    29    [14]    JMP          15    ; to 45
    30    [16]    GETGLOBAL    6 -6    ; print
    31    [16]    GETUPVAL     7 0    ; string
    32    [16]    GETTABLE     7 7 -7    ; "format"
    33    [16]    MOVE         8 3
    34    [16]    MOVE         9 0
    35    [16]    CALL         7 3 0
    36    [16]    CALL         6 0 1
    37    [17]    LOADK        5 -9    ; 99
    38    [18]    GETGLOBAL    6 -6    ; print
    39    [18]    GETUPVAL     7 0    ; string
    40    [18]    GETTABLE     7 7 -7    ; "format"
    41    [18]    MOVE         8 4
    42    [18]    MOVE         9 5
    43    [18]    CALL         7 3 0
    44    [18]    CALL         6 0 1
    45    [21]    RETURN       5 2
    46    [22]    RETURN       0 1

Hola Mundo

Este es el código de hola mundo:

print("Hello World!")

¿Cómo funciona? ¡Es simple! Lua ejecuta la función print() y usa la cadena "Hello World" como argumento.