Copyright original © 2015 Lua.org, PUC-Rio. Disponible libremente bajo los términos de la licencia de Lua. Modificado para Luan.
Luan es un lenguaje de programación de alto nivel basado en Lua. Una gran fortaleza de Lua es su simplicidad y Luan lleva esto aún más lejos, siendo incluso más simple que Lua. El objetivo es proporcionar un lenguaje de programación simple para el programador ocasional con la menor cantidad de conceptos posible para que uno pueda aprender rápidamente el lenguaje y luego entender fácilmente cualquier código escrito en Luan.
Luan está implementado en Java y está estrechamente acoplado con Java. Por lo tanto, es un gran lenguaje de scripting para programadores de Java.
A diferencia de Lua, que está destinado a ser embebido, Luan está destinado a ser un lenguaje de scripting completo. Esto se logra no añadiendo características a Luan, sino proporcionando un conjunto completo de librerías.
Esta sección describe los conceptos básicos del lenguaje.
Luan es un lenguaje de tipado dinámico. Esto significa que las variables no tienen tipos; solo los valores los tienen. No hay definiciones de tipo en el lenguaje. Todos los valores llevan su propio tipo.
Todos los valores en Luan son valores de primera clase. Esto significa que todos los valores pueden ser almacenados en variables, pasados como argumentos a otras funciones y devueltos como resultados.
Hay ocho tipos básicos en Luan: nil, booleano, número, cadena, binario, función, java, y tabla. Nil es el tipo del valor nil, cuya propiedad principal es ser diferente de cualquier otro valor; normalmente representa la ausencia de un valor útil. Nil se implementa como el valor Java null. Booleano es el tipo de los valores false y true. Booleano se implementa como la clase Java Boolean. Número representa tanto números enteros como números reales (de punto flotante). Número se implementa como la clase Java Number. Cualquier subclase de Java de Number está permitida y esto es invisible para el usuario de Luan. Las operaciones en números siguen las mismas reglas de la implementación subyacente de Java. Cadena se implementa como la clase Java String. Binario se implementa como el tipo Java byte[].
Luan puede llamar (y manipular) funciones escritas en Luan y funciones escritas en Java (ver Llamadas a Funciones). Ambas están representadas por el tipo función.
El tipo java se proporciona para permitir que objetos Java arbitrarios sean almacenados en variables de Luan. Un valor java es un objeto Java que no es uno de los tipos estándar de Luan. Los valores Java no tienen operaciones predefinidas en Luan, excepto la asignación y la prueba de identidad. Los valores Java son útiles cuando el acceso a Java está habilitado en Luan.
El tipo tabla implementa arreglos asociativos, es decir, arreglos que pueden ser indexados no solo con números, sino con cualquier valor de Luan excepto nil. Las tablas pueden ser heterogéneas; es decir, pueden contener valores de todos los tipos (excepto nil). Cualquier clave con valor nil no se considera parte de la tabla. Por el contrario, cualquier clave que no sea parte de una tabla tiene un valor asociado nil.
Las tablas son el único mecanismo de estructuración de datos en Luan;
pueden ser usadas para representar arreglos ordinarios, secuencias,
tablas de símbolos, conjuntos, registros, gráficos, árboles, etc.
Para representar registros, Luan usa el nombre del campo como un índice.
El lenguaje soporta esta representación proporcionando a.name como azúcar sintáctica para a["name"].
Hay varias formas convenientes de crear tablas en Luan
(ver Constructores de Tablas).
Usamos el término secuencia para denotar una tabla donde el conjunto de todas las claves numéricas positivas es igual a {1..n} para algún entero no negativo n, que se llama la longitud de la secuencia (ver El Operador de Longitud).
Al igual que los índices, los valores de los campos de la tabla pueden ser de cualquier tipo. En particular, debido a que las funciones son valores de primera clase, los campos de la tabla pueden contener funciones. Por lo tanto, las tablas también pueden llevar métodos (ver Definiciones de Funciones).
La indexación de tablas sigue
definición de igualdad cruda en el lenguaje.
Las expresiones a[i] y a[j]
denotan el mismo elemento de tabla
si y solo si i y j son crudos iguales
(es decir, iguales sin metamétodos).
En particular, los flotantes con valores integrales
son iguales a sus respectivos enteros
(por ejemplo, 1.0 == 1).
Los valores de Luan son objetos: las variables no contienen realmente valores, sólo referencias a ellos. La asignación, el paso de parámetros y los retornos de funciones siempre manipulan referencias a valores; estas operaciones no implican ningún tipo de copia.
La función de librería Luan.type devuelve una cadena que describe el tipo
de un valor dado.
El entorno de un fragmento comienza con solo una variable local: require. Esta función se usa para cargar y acceder a librerías y otros módulos. Todas las demás variables deben ser añadidas al entorno usando declaraciones locales.
Como se discutirá en Variables y Asignación,
cualquier referencia a un nombre libre
(es decir, un nombre no vinculado a ninguna declaración) var
puede ser traducida sintácticamente a _ENV.var si _ENV está definido.
El código Luan puede generar explícitamente un error llamando a la
error función.
Si necesitas capturar errores en Luan,
puedes usar la Declaración Try.
Siempre que hay un error,
una tabla de errores
se propaga con información sobre el error.
Ver Luan.new_error.
Cada tabla en Luan puede tener una metatabla.
Esta metatabla es una tabla Luan ordinaria
que define el comportamiento del valor original
bajo ciertas operaciones especiales.
Puedes cambiar varios aspectos del comportamiento
de las operaciones sobre un valor estableciendo campos específicos en su metatabla.
Por ejemplo, cuando una tabla es el operando de una suma,
Luan busca una función en el campo "__add" de la metatabla de la tabla.
Si encuentra una,
Luan llama a esta función para realizar la suma.
Las claves en una metatabla se derivan de los nombres de eventos;
los valores correspondientes se llaman metamétodos.
En el ejemplo anterior, el evento es "add"
y el metamétodo es la función que realiza la suma.
Puedes consultar la metatabla de cualquier tabla
usando la función get_metatable.
Puedes reemplazar la metatabla de las tablas
usando la función set_metatable.
Una metatabla controla cómo se comporta una tabla en operaciones aritméticas, operaciones bit a bit, comparaciones de orden, concatenación, operación de longitud, llamadas e indexación.
A continuación se da una lista detallada de eventos controlados por metatablas.
Cada operación se identifica por su nombre de evento correspondiente.
La clave para cada evento es una cadena con su nombre precedido por
dos guiones bajos, '__';
por ejemplo, la clave para la operación "add" es la
cadena "__add".
Ten en cuenta que las consultas para metamétodos son siempre crudas;
el acceso a un metamétodo no invoca otros metamétodos.
Puedes emular cómo Luan consulta un metamétodo para un objeto obj
con el siguiente código:
raw_get(get_metatable(obj) or {}, "__" .. event_name)
Aquí están los eventos:
"add":
la operación +.
Si cualquier operando para una suma es una tabla,
Luan intentará llamar a un metamétodo.
Primero, Luan verificará el primer operando (incluso si es válido).
Si ese operando no define un metamétodo para el evento "__add",
entonces Luan verificará el segundo operando.
Si Luan puede encontrar un metamétodo,
llama al metamétodo con los dos operandos como argumentos,
y el resultado de la llamada
(ajustado a un valor)
es el resultado de la operación.
De lo contrario,
se genera un error.
"sub":
la operación -.
Comportamiento similar a la operación "add".
"mul":
la operación *.
Comportamiento similar a la operación "add".
"div":
la operación /.
Comportamiento similar a la operación "add".
"idiv":
la operación //.
Comportamiento similar a la operación "add".
"mod":
la operación %.
Comportamiento similar a la operación "add".
"pow":
la operación ^ (exponenciación).
Comportamiento similar a la operación "add".
"unm":
la operación - (menos unario).
Comportamiento similar a la operación "add".
"concat":
la operación .. (concatenación).
Comportamiento similar a la operación "add".
"len":
la operación # (longitud).
Si hay un metamétodo,
Luan lo llama con el objeto como argumento,
y el resultado de la llamada
(siempre ajustado a un valor)
es el resultado de la operación.
Si no hay un metamétodo pero el objeto es una tabla,
entonces Luan usa la operación de longitud de la tabla (ver El Operador de Longitud).
De lo contrario, Luan genera un error.
"eq":
la operación == (igual).
Comportamiento similar a la operación "add",
excepto que Luan intentará un metamétodo solo cuando los valores
que se comparan son ambos tablas
y no son primitivamente iguales.
El resultado de la llamada siempre se convierte en un booleano.
"lt":
la operación < (menor que).
Comportamiento similar a la operación "add".
El resultado de la llamada siempre se convierte en un booleano.
"le":
la operación <= (menor o igual).
A diferencia de otras operaciones,
La operación menor o igual puede usar dos eventos diferentes.
Primero, Luan busca el metamétodo "__le" en ambos operandos,
como en la operación "lt".
Si no puede encontrar tal metamétodo,
entonces intentará el evento "__lt",
asumiendo que a <= b es equivalente a not (b < a).
Como con los otros operadores de comparación,
el resultado siempre es un booleano.
"index":
El acceso de indexación table[key].
Este evento ocurre
cuando key no está presente en table.
El metamétodo se busca en table.
A pesar del nombre,
el metamétodo para este evento puede ser de cualquier tipo.
Si es una función,
se llama con table y key como argumentos.
De lo contrario
el resultado final es el resultado de indexar este objeto metamétodo con key.
(Esta indexación es regular, no cruda,
y por lo tanto puede desencadenar otro metamétodo si el objeto metamétodo es una tabla.)
"new_index":
La asignación de indexación table[key] = value.
Al igual que el evento de índice,
este evento ocurre cuando
cuando key no está presente en table.
El metamétodo se busca en table.
Al igual que con la indexación,
el metamétodo para este evento puede ser una función o una tabla.
Si es una función,
se llama con table, key y value como argumentos.
Si es una tabla,
Luan hace una asignación de indexación a esta tabla con la misma clave y valor.
(Esta asignación es regular, no cruda,
y por lo tanto puede desencadenar otro metamétodo.)
Siempre que hay un metamétodo "new_index",
Luan no realiza la asignación primitiva.
(Si es necesario,
el propio metamétodo puede llamar a raw_set
para hacer la asignación.)
"gc":
Esto es cuando una tabla es recolectada por el recolector de basura. Cuando el método finalize de la tabla es llamado por el recolector de basura de Java, si hay un metamétodo "__gc" entonces se llama con la tabla como parámetro.
Luan usa la recolección de basura de Java.
Esta sección describe la léxis, la sintaxis y la semántica de Luan. En otras palabras, esta sección describe qué tokens son válidos, cómo pueden combinarse, y qué significan sus combinaciones.
Los constructos del lenguaje se explicarán usando la notación BNF extendida habitual, en la cual {a} significa 0 o más a's, y [a] significa un a opcional. Los no terminales se muestran como no-terminal, las palabras clave se muestran como kword, y otros símbolos terminales se muestran como ‘=’. La sintaxis completa de Luan se puede encontrar en §9 al final de este manual.
Luan ignora espacios y comentarios entre elementos léxicos (tokens), excepto como delimitadores entre nombres y palabras clave. Luan considera el final de una línea como el final de una declaración. Esto detecta errores y fomenta la legibilidad. Si deseas continuar una declaración en otra línea, puedes usar una barra invertida seguida de un salto de línea que se tratará como espacio en blanco.
Nombres (también llamados identificadores) en Luan pueden ser cualquier cadena de letras, dígitos y guiones bajos, no comenzando con un dígito. Los identificadores se usan para nombrar variables, campos de tabla y etiquetas.
Las siguientes palabras clave están reservadas y no pueden usarse como nombres:
and break catch continue do else elseif end_do end_for end_function end_if end_try end_while false finally for function if in local nil not or repeat return then true try until while
Luan es un lenguaje sensible a mayúsculas y minúsculas:
and es una palabra reservada, pero And y AND
son dos nombres diferentes y válidos.
Las siguientes cadenas denotan otros tokens:
+ - * / // % ^ # & ~ | == ~= <= >= < > = ( ) { } [ ] ; , . .. ... %> <% <%=
Cadenas literales
pueden estar delimitadas por comillas simples o dobles coincidentes,
y pueden contener las siguientes secuencias de escape similares a C:
'\a' (campana),
'\b' (retroceso),
'\f' (salto de formulario),
'\n' (nueva línea),
'\r' (retorno de carro),
'\t' (tabulación horizontal),
'\v' (tabulación vertical),
'\\' (barra invertida),
'\"' (comillas [comillas dobles]),
y '\'' (apóstrofo [comillas simples]).
Una barra invertida seguida de una nueva línea real
resulta en una nueva línea en la cadena.
La secuencia de escape '\z' omite el siguiente tramo
de caracteres de espacio en blanco,
incluyendo saltos de línea;
es particularmente útil para dividir e indentar una cadena literal larga
en varias líneas sin agregar los saltos de línea y espacios
en el contenido de la cadena.
Luan puede especificar cualquier carácter en una cadena literal por su valor numérico.
Esto se puede hacer
con la secuencia de escape \xXX,
donde XX es una secuencia de exactamente dos dígitos hexadecimales,
o con la secuencia de escape \uXXXX,
donde XXXX es una secuencia de exactamente cuatro dígitos hexadecimales,
o con la secuencia de escape \ddd,
donde ddd es una secuencia de hasta tres dígitos decimales.
(Tenga en cuenta que si una secuencia de escape decimal debe ser seguida por un dígito,
debe expresarse usando exactamente tres dígitos.)
Las cadenas literales también pueden definirse usando un formato largo
delimitado por corchetes largos.
Definimos un corchete largo de apertura de nivel n como un corchete
cuadrado de apertura seguido de n signos de igual seguidos de otro
corchete cuadrado de apertura.
Entonces, un corchete largo de apertura de nivel 0 se escribe como [[,
un corchete largo de apertura de nivel 1 se escribe como [=[,
y así sucesivamente.
Un corchete largo de cierre se define de manera similar;
por ejemplo,
un corchete largo de cierre de nivel 4 se escribe como ]====].
Un literal largo comienza con un corchete largo de apertura de cualquier nivel y
termina en el primer corchete largo de cierre del mismo nivel.
Puede contener cualquier texto excepto un corchete de cierre del mismo nivel.
Los literales en esta forma entre corchetes pueden extenderse por varias líneas,
no interpretan ninguna secuencia de escape,
y ignoran los corchetes largos de cualquier otro nivel.
Cualquier tipo de secuencia de fin de línea
(retorno de carro, nueva línea, retorno de carro seguido de nueva línea,
o nueva línea seguida de retorno de carro)
se convierte en una nueva línea simple.
Cualquier carácter en una cadena literal no afectado explícitamente por las reglas anteriores se representa a sí mismo. Sin embargo, Luan abre archivos para analizar en modo texto, y las funciones de archivo del sistema pueden tener problemas con algunos caracteres de control. Por lo tanto, es más seguro representar datos no textuales como un literal entre comillas con secuencias de escape explícitas para caracteres no textuales.
Por conveniencia, cuando el corchete largo de apertura es seguido inmediatamente por una nueva línea, la nueva línea no se incluye en la cadena. Como ejemplo las cinco cadenas literales a continuación denotan la misma cadena:
a = 'alo\n123"'
a = "alo\n123\""
a = '\97lo\10\04923"'
a = [[alo
123"]]
a = [==[
alo
123"]==]
Una constante numérica (o número)
puede escribirse con una parte fraccionaria opcional
y un exponente decimal opcional,
marcado por una letra 'e' o 'E'.
Luan también acepta constantes hexadecimales,
que comienzan con 0x o 0X.
Las constantes hexadecimales también aceptan una parte fraccionaria opcional
más un exponente binario opcional,
marcado por una letra 'p' o 'P'.
Una constante numérica con un punto fraccionario o un exponente
denota un flotante;
de lo contrario, denota un entero.
Ejemplos de constantes enteras válidas son
3 345 0xff 0xBEBADA
Ejemplos de constantes flotantes válidas son
3.0 3.1416 314.16e-2 0.31416E1 34e1 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
Un comentario comienza con un doble guion (--)
en cualquier lugar fuera de una cadena.
Si el texto inmediatamente después de -- no es un corchete largo de apertura,
el comentario es un comentario corto,
que se extiende hasta el final de la línea.
De lo contrario, es un comentario largo,
que se extiende hasta el corchete largo de cierre correspondiente.
Los comentarios largos se utilizan con frecuencia para deshabilitar código temporalmente.
Las variables son lugares que almacenan valores. Hay tres tipos de variables en Luan: variables globales, variables locales y campos de tabla.
Un solo nombre puede denotar una variable global o una variable local (o un parámetro formal de una función, que es un tipo particular de variable local):
var ::= Name
Name denota identificadores, como se define en Convenciones Léxicas.
Las variables locales son de ámbito léxico: las variables locales pueden ser accedidas libremente por funciones definidas dentro de su ámbito (ver Reglas de Visibilidad).
Antes de la primera asignación a una variable, su valor es nil.
Los corchetes se usan para indexar una tabla:
var ::= prefixexp ‘[’ exp ‘]’
El significado de los accesos a campos de tabla puede cambiarse mediante metatablas.
Un acceso a una variable indexada t[i] es equivalente a
una llamada gettable_event(t,i).
(Ver Metatablas y Metamétodos para una descripción completa de la
función gettable_event.
Esta función no está definida ni es invocable en Luan.
La usamos aquí solo con fines explicativos.)
La sintaxis var.Name es solo azúcar sintáctico para
var["Name"]:
var ::= prefixexp ‘.’ Name
Las variables globales no están disponibles por defecto. Para habilitar la variable global, debes definir _ENV como una variable local cuyo valor es una tabla. Si _ENV no está definido, entonces un nombre de variable no reconocido producirá un error de compilación. Si _ENV está definido, entonces un acceso a un nombre de variable no reconocido se considerará una variable global. Entonces, un acceso a la variable global x
es equivalente a _ENV.x.
Debido a la forma en que se compilan los fragmentos,
_ENV nunca es un nombre global (ver Entornos).
Luan admite un conjunto casi convencional de declaraciones, similar a las de Pascal o C. Este conjunto incluye asignaciones, estructuras de control, llamadas a funciones, y declaraciones de variables.
Un bloque es una lista de declaraciones, que se ejecutan secuencialmente:
block ::= {stat}
Luan tiene declaraciones vacías que te permiten separar declaraciones con punto y coma, iniciar un bloque con un punto y coma o escribir dos puntos y coma en secuencia:
stat ::= ‘;’
Un bloque puede delimitarse explícitamente para producir una sola declaración:
stat ::= do block end_do end_do ::= end_do | end
Los bloques explícitos son útiles para controlar el ámbito de las declaraciones de variables. Los bloques explícitos también se utilizan a veces para agregar una declaración return en el medio de otro bloque (ver Estructuras de Control).
La unidad de compilación de Luan se llama fragmento. Sintácticamente, un fragmento es simplemente un bloque:
chunk ::= block
Luan maneja un fragmento como el cuerpo de una función anónima con un número variable de argumentos (ver Definiciones de Funciones). Como tal, los fragmentos pueden definir variables locales, recibir argumentos y devolver valores.
Un fragmento puede almacenarse en un archivo o en una cadena dentro del programa anfitrión. Para ejecutar un fragmento, Luan primero carga el mismo, compilando el código del fragmento, y luego Luan ejecuta el código compilado.
Luan permite múltiples asignaciones. Por lo tanto, la sintaxis para la asignación define una lista de variables en el lado izquierdo y una lista de expresiones en el lado derecho. Los elementos en ambas listas están separados por comas:
stat ::= varlist ‘=’ explist
varlist ::= var {‘,’ var}
explist ::= exp {‘,’ exp}
Las expresiones se discuten en Expresiones.
Antes de la asignación, la lista de valores se ajusta a la longitud de la lista de variables. Si hay más valores de los necesarios, los valores en exceso se descartan. Si hay menos valores de los necesarios, la lista se extiende con tantos nil como sea necesario. Si la lista de expresiones termina con una llamada a función, entonces todos los valores devueltos por esa llamada ingresan a la lista de valores, antes del ajuste (excepto cuando la llamada está encerrada entre paréntesis; ver Expresiones).
La declaración de asignación primero evalúa todas sus expresiones y solo entonces se realizan las asignaciones. Así que el código
i = 3
i, a[i] = i+1, 20
asigna a[3] a 20, sin afectar a[4]
porque el i en a[i] se evalúa (a 3)
ante de que se asigne 4.
De manera similar, la línea
x, y = y, x
intercambia los valores de x y y,
y
x, y, z = y, z, x
permuta cíclicamente los valores de x, y y z.
El significado de las asignaciones a variables globales
y campos de tabla puede cambiarse mediante metatablas.
Una asignación a una variable indexada t[i] = val es equivalente a
settable_event(t,i,val).
(Ver Metatablas y Metamétodos para una descripción completa de la
función settable_event.
Esta función no está definida ni es invocable en Luan.
La usamos aquí solo con fines explicativos.)
Una asignación a un nombre global x = val
es equivalente a la asignación
_ENV.x = val (ver Entornos).
Los nombres globales solo están disponibles cuando _ENV está definido.
Las estructuras de control if, while y repeat tienen el significado habitual y sintaxis familiar:
stat ::= while exp do block end_while
stat ::= repeat block until exp
stat ::= if exp then block {elseif exp then block} [else block] end_if
end_while ::= end_while | end
end_if ::= end_if | end
Luan también tiene una declaración for (ver Declaración For).
La expresión de condición de una estructura de control debe ser un booleano. Cualquier otro tipo de valor producirá un error. Esto ayuda a detectar errores y hace que el código sea más legible.
En el bucle repeat–until, el bloque interno no termina en la palabra clave until, sino solo después de la condición. Por lo tanto, la condición puede referirse a variables locales declaradas dentro del bloque del bucle.
La declaración break termina la ejecución de un bucle while, repeat o for, saltando a la siguiente declaración después del bucle:
stat ::= break
Un break termina el bucle más interno.
La declaración continue salta al comienzo de un bucle while, repeat o for para la siguiente iteración, saltando la ejecución de declaraciones dentro del cuerpo del bucle para la iteración actual:
stat ::= continue
La declaración return se usa para devolver valores de una función o un fragmento (que es una función anónima). Las funciones pueden devolver más de un valor, así que la sintaxis para la declaración return es
stat ::= return [explist] [‘;’]
La declaración for funciona sobre funciones, llamadas iteradores. En cada iteración, la función iteradora se llama para producir un nuevo valor, deteniéndose cuando este nuevo valor es nil. El bucle for tiene la siguiente sintaxis:
stat ::= for namelist in exp do block end_for
namelist ::= Name {‘,’ Name}
end_for ::= end_for | end
Una declaración for como
for var_1, ···, var_n in exp do block end
es equivalente al código:
do
local f = exp
while true do
local var_1, ···, var_n = f()
if var_1 == nil then break end
block
end
end
Nota lo siguiente:
exp se evalúa solo una vez.
Su resultado es una función iteradora.
f es una variable invisible.
El nombre está aquí solo con fines explicativos.
var_i son locales al bucle;
no puedes usar sus valores después de que el for termine.
Si necesitas estos valores,
entonces asígnalos a otras variables antes de romper o salir del bucle.
La declaración try tiene la misma semántica que en Java.
stat ::= try block [catch Name block] [finally block] end_try end_try ::= end_try | end
Para permitir posibles efectos secundarios, las llamadas a funciones pueden ejecutarse como declaraciones:
stat ::= functioncall
En este caso, todos los valores devueltos se descartan. Las llamadas a funciones se explican en Llamadas a Funciones.
Expresiones lógicas pueden ser declaraciones. Esto es útil en casos como este:
x==5 or error "x should be 5"
Las variables locales pueden declararse en cualquier lugar dentro de un bloque. La declaración puede incluir una asignación inicial:
stat ::= local namelist [‘=’ explist]
Si está presente, una asignación inicial tiene la misma semántica de una asignación múltiple (ver Asignación). De lo contrario, todas las variables se inicializan con nil.
Un fragmento también es un bloque (ver Fragmentos), y por lo tanto las variables locales pueden declararse en un fragmento fuera de cualquier bloque explícito.
Las reglas de visibilidad para las variables locales se explican en Reglas de Visibilidad.
Las declaraciones de plantilla proporcionan el equivalente completo de JSP pero de manera general. Las declaraciones de plantilla escriben en la salida estándar. Por ejemplo:
local name = "Bob"
%>
Hello <%= name %>!
Bye <%= name %>.
<%
es equivalente al código:
local name = "Bob"
require("luan:Io.luan").stdout.write( "Hello ", name , "!\nBye ", name , ".\n" )
Las expresiones básicas en Luan son las siguientes:
exp ::= prefixexp exp ::= nil | false | true exp ::= Numeral exp ::= LiteralString exp ::= functiondef exp ::= tableconstructor exp ::= ‘...’ exp ::= exp binop exp exp ::= unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’
Los números y las cadenas literales se explican en Convenciones Léxicas;
las variables se explican en Variables;
las definiciones de funciones se explican en Definiciones de Funciones;
las llamadas a funciones se explican en Llamadas a Funciones;
los constructores de tablas se explican en Constructores de Tablas.
Las expresiones vararg,
denotadas por tres puntos ('...'), solo pueden usarse cuando
directamente dentro de una función vararg;
se explican en Definiciones de Funciones.
Los operadores binarios comprenden operadores aritméticos (ver Operadores Aritméticos), operadores relacionales (ver Operadores Relacionales), operadores lógicos (ver Operadores Lógicos), y el operador de concatenación (ver Concatenación). Los operadores unarios comprenden el menos unario (ver Operadores Aritméticos), el not lógico unario (ver Operadores Lógicos), y el operador de longitud unario (ver El Operador de Longitud).
Tanto las llamadas a funciones como las expresiones vararg pueden resultar en múltiples valores. Si una llamada a función se usa como una declaración (ver Llamadas a Funciones como Declaraciones), entonces su lista de retorno se ajusta a cero elementos, descartando así todos los valores devueltos. Si una expresión se usa como el último (o el único) elemento de una lista de expresiones, entonces no se hace ningún ajuste (a menos que la expresión esté encerrada entre paréntesis). En todos los demás contextos, Luan ajusta la lista de resultados a un elemento, ya sea descartando todos los valores excepto el primero o agregando un solo nil si no hay valores.
Aquí hay algunos ejemplos:
f() -- ajustado a 0 resultados
g(f(), x) -- f() se ajusta a 1 resultado
g(x, f()) -- g obtiene x más todos los resultados de f()
a,b,c = f(), x -- f() se ajusta a 1 resultado (c obtiene nil)
a,b = ... -- a obtiene el primer parámetro vararg, b obtiene
-- el segundo (tanto a como b pueden obtener nil si no
-- hay un parámetro vararg correspondiente)
a,b,c = x, f() -- f() se ajusta a 2 resultados
a,b,c = f() -- f() se ajusta a 3 resultados
return f() -- devuelve todos los resultados de f()
return ... -- devuelve todos los parámetros vararg recibidos
return x,y,f() -- devuelve x, y, y todos los resultados de f()
{f()} -- crea una lista con todos los resultados de f()
{...} -- crea una lista con todos los parámetros vararg
{f(), nil} -- f() se ajusta a 1 resultado
Cualquier expresión encerrada entre paréntesis siempre resulta en solo un valor.
Así,
(f(x,y,z)) es siempre un solo valor,
incluso si f devuelve varios valores.
(El valor de (f(x,y,z)) es el primer valor devuelto por f
o nil si f no devuelve ningún valor.)
Luan admite los siguientes operadores aritméticos:
La adición, sustracción, multiplicación, división y menos unario son los mismos que estos operadores en Java. La exponenciación utiliza la función Math.pow de Java.
La división de piso (//) es una división que redondea el cociente hacia menos infinito, es decir, el piso de la división de sus operandos.
El módulo se define como el resto de una división que redondea el cociente hacia menos infinito (división de piso). (El operador de módulo de Java no se usa.)
Luan generalmente evita las conversiones automáticas. La concatenación de cadenas convierte automáticamente todos sus argumentos en cadenas.
Luan proporciona funciones de librería para conversiones de tipo explícitas.
Luan admite los siguientes operadores relacionales:
Estos operadores siempre resultan en false o true.
La igualdad (==) primero compara el tipo de sus operandos.
Si los tipos son diferentes, entonces el resultado es false.
De lo contrario, se comparan los valores de los operandos.
Las cadenas, números y valores binarios se comparan de la manera obvia (por valor).
Las tablas se comparan por referencia: dos objetos se consideran iguales solo si son el mismo objeto. Cada vez que creas una nueva tabla, es diferente de cualquier tabla existente previamente. Las clausuras también se comparan por referencia.
Puedes cambiar la forma en que Luan compara tablas usando el metamétodo "eq" (ver Metatablas y Metamétodos).
Los valores de Java se comparan por igualdad con el método equals de Java.
Las comparaciones de igualdad no convierten cadenas en números
o viceversa.
Por lo tanto, "0"==0 evalúa a false,
y t[0] y t["0"] denotan diferentes
entradas en una tabla.
El operador ~= es exactamente la negación de la igualdad (==).
Los operadores de orden funcionan de la siguiente manera.
Si ambos argumentos son números,
entonces se comparan siguiendo
la regla habitual para operaciones binarias.
De lo contrario, si ambos argumentos son cadenas,
entonces sus valores se comparan según la configuración regional actual.
De lo contrario, Luan intenta llamar al metamétodo "lt" o "le"
(ver Metatablas y Metamétodos).
Una comparación a > b se traduce a b < a
y a >= b se traduce a b <= a.
Los operadores lógicos en Luan son and, or y not. Los operadores and y or consideran tanto false como nil como falsos y cualquier otra cosa como verdadera. Al igual que las estructuras de control (ver Estructuras de Control), el operador not requiere un valor booleano.
El operador de negación not siempre devuelve false o true. El operador de conjunción and devuelve su primer argumento si este valor es false o nil; de lo contrario, and devuelve su segundo argumento. El operador de disyunción or devuelve su primer argumento si este valor es diferente de nil y false; de lo contrario, or devuelve su segundo argumento. Tanto and como or utilizan evaluación de cortocircuito; es decir, el segundo operando se evalúa solo si es necesario. Aquí hay algunos ejemplos:
10 or 20 --> 10 10 or error() --> 10 nil or "a" --> "a" nil and 10 --> nil false and error() --> false false and nil --> false false or nil --> nil 10 and 20 --> 20
(En este manual,
--> indica el resultado de la expresión anterior.)
El operador de concatenación de cadenas en Luan es
denotado por dos puntos ("..").
Todos los operandos se convierten en cadenas.
El operador de longitud está denotado por el operador unario de prefijo #.
La longitud de una cadena es su número de caracteres.
La longitud de un binario es su número de bytes.
Un programa puede modificar el comportamiento del operador de longitud para
cualquier tabla a través del metamétodo __len (ver Metatablas y Metamétodos).
A menos que se proporcione un metamétodo __len,
la longitud de una tabla t se define
como el número de elementos en secuencia,
es decir,
el tamaño del conjunto de sus claves numéricas positivas es igual a {1..n}
para algún entero no negativo n.
En ese caso, n es su longitud.
Tenga en cuenta que una tabla como
{10, 20, nil, 40}
tiene una longitud de 2, porque esa es la última clave en secuencia.
La precedencia de operadores en Luan sigue la tabla a continuación, de menor a mayor prioridad:
or and < > <= >= ~= == .. + - * / % operadores unarios (not # -) ^
Como de costumbre,
puedes usar paréntesis para cambiar las precedencias de una expresión.
Los operadores de concatenación ('..') y exponenciación ('^')
son asociativos a la derecha.
Todos los demás operadores binarios son asociativos a la izquierda.
Los constructores de tablas son expresiones que crean tablas. Cada vez que se evalúa un constructor, se crea una nueva tabla. Un constructor puede usarse para crear una tabla vacía o para crear una tabla e inicializar algunos de sus campos. La sintaxis general para los constructores es
tableconstructor ::= ‘{’ fieldlist ‘}’
fieldlist ::= [field] {fieldsep [field]}
field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
fieldsep ::= ‘,’ | ‘;’ | end_of_line
Cada campo de la forma [exp1] = exp2 agrega a la nueva tabla una entrada
con clave exp1 y valor exp2.
Un campo de la forma name = exp es equivalente a
["name"] = exp.
Finalmente, los campos de la forma exp son equivalentes a
[i] = exp, donde i son enteros consecutivos
comenzando con 1.
Los campos en los otros formatos no afectan este conteo.
Por ejemplo,
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
es equivalente a
do
local t = {}
t[f(1)] = g
t[1] = "x" -- 1er exp
t[2] = "y" -- 2do exp
t.x = 1 -- t["x"] = 1
t[3] = f(x) -- 3er exp
t[30] = 23
t[4] = 45 -- 4to exp
a = t
end
El orden de las asignaciones en un constructor es indefinido. (Este orden solo sería relevante cuando hay claves repetidas.)
Si el último campo en la lista tiene la forma exp
y la expresión es una llamada a función o una expresión vararg,
entonces todos los valores devueltos por esta expresión ingresan a la lista consecutivamente
(ver Llamadas a Funciones).
La lista de campos puede tener un separador final opcional, como una conveniencia para el código generado por máquina.
Una llamada a función en Luan tiene la siguiente sintaxis:
functioncall ::= prefixexp args
En una llamada a función, primero se evalúan prefixexp y args. El valor de prefixexp debe tener tipo función. Esta función se llama con los argumentos dados.
Los argumentos tienen la siguiente sintaxis:
args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
Todas las expresiones de argumento se evalúan antes de la llamada.
Una llamada de la forma f{fields} es
azúcar sintáctico para f({fields});
es decir, la lista de argumentos es una sola nueva tabla.
Una llamada de la forma f'string'
(o f"string" o f[[string]])
es azúcar sintáctico para f('string');
es decir, la lista de argumentos es una sola cadena literal.
La sintaxis para la definición de funciones es
functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end_function end_function ::= end_function | end
El siguiente azúcar sintáctico simplifica las definiciones de funciones:
stat ::= function funcname funcbody
stat ::= local function Name funcbody
funcname ::= Name {‘.’ Name} [‘:’ Name]
La declaración
function f () body end
se traduce a
f = function () body end
La declaración
function t.a.b.c.f () body end
se traduce a
t.a.b.c.f = function () body end
La declaración
local function f () body end
se traduce a
local f; f = function () body end
no a
local f = function () body end
(Esto solo hace una diferencia cuando el cuerpo de la función
contiene referencias a f.)
Una definición de función es una expresión ejecutable, cuya valor tiene tipo función. Cuando Luan precompila un fragmento, todos sus cuerpos de función también se precompilan. Luego, cada vez que Luan ejecuta la definición de la función, la función es instanciada (o cerrada). Esta instancia de función (o clausura) es el valor final de la expresión.
Los parámetros actúan como variables locales que son inicializadas con los valores de los argumentos:
parlist ::= namelist [‘,’ ‘...’] | ‘...’
Cuando se llama a una función,
la lista de argumentos se ajusta a
la longitud de la lista de parámetros si la lista es demasiado corta,
a menos que la función sea una función vararg,
que se indica con tres puntos ('...')
al final de su lista de parámetros.
Una función vararg no ajusta su lista de argumentos;
en cambio, recopila todos los argumentos adicionales y los suministra
a la función a través de una expresión vararg,
que también se escribe como tres puntos.
El valor de esta expresión es una lista de todos los argumentos adicionales reales,
similar a una función con múltiples resultados.
Si una expresión vararg se usa dentro de otra expresión
o en el medio de una lista de expresiones,
entonces su lista de retorno se ajusta a un elemento.
Si la expresión se usa como el último elemento de una lista de expresiones,
entonces no se hace ningún ajuste
(a menos que esa última expresión esté encerrada entre paréntesis).
Como ejemplo, considera las siguientes definiciones:
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end
Entonces, tenemos el siguiente mapeo de argumentos a parámetros y a la expresión vararg:
CALL PARAMETERS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) error en tiempo de ejecución f(r(), 10) error en tiempo de ejecución f(r()) error en tiempo de ejecución g(3) a=3, b=nil, ... --> (nada) g(3, 4) a=3, b=4, ... --> (nada) g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 g(5, r()) a=5, b=1, ... --> 2 3
Los resultados se devuelven usando la declaración return (ver Estructuras de Control). Si el control llega al final de una función sin encontrar una declaración return, entonces la función devuelve sin resultados.
Un bloque entre comillas invertidas se ejecuta y luego lo que se envió a la salida estándar se devuelve como una cadena. Ejemplos:
local s = `%>1 + 1 = <%=1+1%><%`
local s = ` fn(whatever) `
local s = `%>
...
<%`
Las comillas invertidas complementan declaraciones de plantilla.
Luan es un lenguaje de ámbito léxico. El ámbito de una variable local comienza en la primera declaración después de su declaración y dura hasta la última declaración no vacía del bloque más interno que incluye la declaración. Considera el siguiente ejemplo:
local x = 10 -- global al módulo
do -- nuevo bloque
local x = x -- nuevo 'x', con valor 10
print(x) --> 10
x = x+1
do -- otro bloque
local x = x+1 -- otro 'x'
print(x) --> 12
end
print(x) --> 11
end
print(x) --> 10 (el global)
Observa que, en una declaración como local x = x,
el nuevo x que se está declarando aún no está en el ámbito,
y por lo tanto el segundo x se refiere a la variable externa.
Debido a las reglas de ámbito léxico, las variables locales pueden ser accedidas libremente por funciones definidas dentro de su ámbito. Una variable local utilizada por una función interna se llama una upvalue, o variable local externa, dentro de la función interna.
Observa que cada ejecución de una declaración local define nuevas variables locales. Considera el siguiente ejemplo:
local a = {}
local x = 20
for i=1,10 do
local y = 0
a[i] = function () y=y+1; return x+y end
end
El bucle crea diez clausuras
(es decir, diez instancias de la función anónima).
Cada una de estas clausuras usa una variable y diferente,
mientras que todas comparten el mismo x.
Las librerías estándar de Luan proporcionan funciones útiles
que están implementadas tanto en Java como en el propio Luan.
Cómo se implementa cada función no debería importar al usuario.
Algunas de estas funciones proporcionan servicios esenciales al lenguaje
(por ejemplo, type y get_metatable);
otras proporcionan acceso a servicios "externos" (por ejemplo, I/O).
Esto se proporciona por defecto como una variable local para cualquier código Luan como se describe en Entornos.
Uso de ejemplo:
local Table = require "luan:Table.luan"
Podría definirse como:
local function require(mod_name)
return Package.load(mod_name) or Luan.error("module '"..mod_name.."' not found")
end
Un caso especial es:
require "java"
Esto habilita Java en el bloque actual si ese bloque tiene permiso para usar Java. Si el bloque no tiene permiso para usar Java, entonces se lanza un error.
Incluye esta librería por:
local Luan = require "luan:Luan.luan"
La librería básica proporciona funciones básicas a Luan que no dependen de otras librerías.
Si Luan se ejecutó desde la línea de comandos, entonces esta es una lista de los argumentos de la línea de comandos. Por ejemplo, si uno ejecuta Luan así:
luan t.luan a b c
Entonces Luan.arg contendrá:
{
[0] = "t.luan"
[1] = "a"
[2] = "b"
[3] = "c"
}
Y por supuesto #Luan.arg será 3.
Podría definirse como:
function Luan.do_file(uri)
local fn = Luan.load_file(uri) or Luan.error("file '"..uri.."' not found")
return fn()
end
Lanza un error que contiene el mensaje.
Podría definirse como:
function Luan.error(message)
Luan.new_error(message).throw()
end
Evalúa text como una expresión Luan.
Podría definirse como:
function Luan.eval(text,source_name, env)
return Luan.load( "return "..text, source_name or "eval", env )()
end
Si table no tiene una metatabla, devuelve nil.
De lo contrario,
si la metatabla de la tabla tiene un campo "__metatable",
devuelve el valor asociado.
De lo contrario, devuelve la metatabla de la tabla dada.
Devuelve el código hash de v.
Devuelve una función iteradora para que la construcción
for i,v in ipairs(t) do body end
iterará sobre los pares clave–valor
(1,t[1]), (2,t[2]), ...,
hasta el primer valor nulo.
Podría definirse como:
function Luan.ipairs(t)
local i = 0
return function()
if i < #t then
i = i + 1
return i, t[i]
end
end
end
Carga un bloque.
El text se compila.
Si no hay errores sintácticos,
devuelve el bloque compilado como una función;
de lo contrario, lanza un error.
El parámetro source_name es una cadena que indica de dónde proviene el texto. Se utiliza para producir mensajes de error. Por defecto es "load".
Si se proporciona el parámetro env, se convierte en el _ENV del bloque.
El parámetro persist es un booleano que determina si el código compilado se almacena en caché de forma persistente en un archivo temporal. Por defecto es false.
Similar a load,
pero obtiene el bloque del archivo file_uri.
file_uri puede ser una cadena o una tabla uri.
Crea una nueva tabla de error que contiene el mensaje asignado a "message". La tabla de error también contiene una función throw que lanza el error. La tabla también contiene una lista de elementos de traza de pila donde cada elemento de traza de pila es una tabla que contiene "source", "line", y posiblemente "call_to". La tabla también tiene una metatabla que contiene "__to_string" para renderizar el error.
Para imprimir la traza de pila actual, podrías hacer:
Io.print( Luan.new_error "stack" )
Si t tiene un metamétodo __pairs,
lo llama con t como argumento y devuelve el
resultado de la llamada.
De lo contrario, devuelve una función para que la construcción
for k,v in pairs(t) do body end
iterará sobre todos los pares clave–valor de la tabla t.
Este es el equivalente de Luan a JSON.parse() de Javascript, pero para un valor de Luan. Además de los valores JSON habituales, Luan.parse permite cadenas largas y permite especificar tipos numéricos de double, float, integer, y long. Por ejemplo:
local t = Luan.parse[=[
{
nothing = nil
t = true
f = false
s = "string"
ls = [[long string]]
n = 3
d = double(3)
f = float(3)
i = integer(3)
l = long(3)
list = { 1, 2, 3 }
table = {
one = 1
two = 2
three = 3
}
["ugly-key"] = "something"
}
]=]
Basado en la función range() de Python, esto permite iterar a través de una secuencia de números.
Uso de ejemplo:
for i in range(1,10) do
Io.print("count up:",i)
end
for i in range(10,0,-1) do
Io.print("count down:",i)
end
Podría definirse como:
function Luan.range(start, stop, step)
step = step or 1
step == 0 and Luan.error "bad argument #3 (step may not be zero)"
local i = start
return function()
if step > 0 and i <= stop or step < 0 and i >= stop then
local rtn = i
i = i + step
return rtn
end
end
end
Verifica si v1 es igual a v2,
sin invocar ningún metamétodo.
Devuelve un booleano.
Obtiene el valor real de table[index],
sin invocar ningún metamétodo.
table debe ser una tabla;
index puede ser cualquier valor.
Devuelve la longitud del objeto v,
que debe ser una tabla o una cadena,
sin invocar ningún metamétodo.
Devuelve un entero.
Establece el valor real de table[index] a value,
sin invocar ningún metamétodo.
table debe ser una tabla,
index cualquier valor diferente de nil,
y value cualquier valor de Luan.
Devuelve el valor antiguo de table[index].
Establece la metatabla para la tabla dada.
Si metatable es nil,
remueve la metatabla de la tabla dada.
Si la metatabla original tiene un campo "__metatable",
lanza un error.
Este es el equivalente de Luan a JSON.stringify() de Javascript, pero para un valor de Luan.
v es un valor de cualquier tipo que se convierte en una cadena que es una expresión de Luan. options puede ser una tabla o una función. Si options es una tabla, puede contener las siguientes banderas cuyo valor true significa:
["key"]Si options es una función, entonces esta función debe tomar un argumento stack y devolver una tabla options. El stack será una lista de claves que indica dónde stringify está procesando actualmente. Esto permite aplicar diferentes opciones en diferentes lugares de una estructura de datos.
Recibe un valor de cualquier tipo y lo convierte en una cadena en un formato legible por humanos.
Si la metatabla de v tiene un campo "__to_string",
entonces to_string llama al valor correspondiente
con v como argumento,
y usa el resultado de la llamada como su resultado.
Devuelve el tipo de su único argumento, codificado como una cadena.
Los posibles resultados de esta función son
"nil" (una cadena, no el valor nil),
"number",
"string",
"binary",
"boolean",
"table",
"function",
y "java".
Devuelve una función para que la construcción
for i, v in Luan.values(···) do body end
iterará sobre todos los valores de ···.
Incluye esta librería por:
local Package = require "luan:Package.luan"
La librería de paquetes proporciona facilidades básicas para cargar módulos en Luan.
Carga el módulo dado.
La función comienza buscando en la tabla Package.loaded
para determinar si mod_uri ya está cargado.
Si lo está, entonces Package.load devuelve el valor almacenado
en Package.loaded[mod_uri].
De lo contrario, intenta cargar un nuevo valor para el módulo.
Para cargar un nuevo valor, Package.load primero verifica si mod_uri comienza con "java:". Si es así, entonces esta es una clase Java que se carga mediante un código Java especial.
De lo contrario, Package.load intenta leer el texto del archivo referido por mod_uri. Si el archivo no existe, entonces Package.load devuelve false. Si el archivo existe, entonces su contenido se compila en un bloque llamando a Luan.load. Este bloque se ejecuta pasando mod_uri como argumento. El valor devuelto por el bloque no debe ser nil y se carga.
Si un nuevo valor para el módulo se carga con éxito, entonces se almacena en Package.loaded[mod_uri]. El valor se devuelve.
Una tabla utilizada por Package.load para controlar qué
módulos ya están cargados.
Cuando cargas un módulo mod_uri y
Package.loaded[mod_uri] no es nil,
Package.load simplemente devuelve el valor almacenado allí.
Esta variable es solo una referencia a la tabla real;
asignaciones a esta variable no cambian la
tabla utilizada por Package.load.
Incluye esta librería por:
local String = require "luan:String.luan"
Esta librería proporciona funciones genéricas para la manipulación de cadenas, como encontrar y extraer subcadenas, y coincidencia de patrones. Al indexar una cadena en Luan, el primer carácter está en la posición 1 (no en 0, como en Java). Se permite que los índices sean negativos y se interpretan como indexación hacia atrás, desde el final de la cadena. Por lo tanto, el último carácter está en la posición -1, y así sucesivamente.
Recibe cero o más enteros. Devuelve una cadena con longitud igual al número de argumentos, en la que cada carácter tiene el código numérico interno igual a su argumento correspondiente.
Devuelve un booleano que indica si s contiene s2.
Devuelve una cadena de resumen hexadecimal de s. Podría definirse como:
function String.digest_message(algorithm,s)
return Binary.to_hex( Binary.digest_message( algorithm, String.to_binary(s) ) )
end
Codifica el argumento s en una cadena que se puede colocar entre comillas para devolver el valor original de la cadena.
Devuelve un booleano que indica si s termina con s2.
Busca la primera subcadena
s2 en la cadena s.
Si encuentra una coincidencia, entonces find devuelve el índice de s
donde comienza esta ocurrencia;
de lo contrario, devuelve nil.
Un tercer argumento numérico opcional init especifica
dónde comenzar la búsqueda;
su valor predeterminado es 1 y puede ser negativo.
Busca la última subcadena
s2 en la cadena s.
Si encuentra una coincidencia, entonces find devuelve el índice de s
donde comienza esta ocurrencia;
de lo contrario, devuelve nil.
Un tercer argumento numérico opcional init especifica
dónde comenzar la búsqueda;
su valor predeterminado es -1.
Devuelve una versión formateada de su número variable de argumentos
siguiendo la descripción dada en su primer argumento (que debe ser una cadena).
La cadena de formato sigue las mismas reglas que la función de Java String.format porque Luan llama a esto internamente.
Tenga en cuenta que String.format de Java es demasiado estúpido para convertir entre enteros y flotantes, por lo que debe proporcionar el tipo correcto de número.
Recibe una cadena y devuelve una copia de esta cadena con todas las letras mayúsculas cambiadas a minúsculas. Todos los demás caracteres se dejan sin cambios.
Devuelve una tabla regex para el patrón s.
Devuelve una cadena que coincide con la cadena literal s en una expresión regular. Esta función es simplemente el método de Java Pattern.quote.
Devuelve una cadena que es la concatenación de n copias de
la cadena s separadas por la cadena sep.
El valor predeterminado para sep es la cadena vacía
(es decir, sin separador).
Devuelve la cadena vacía si n no es positivo.
Devuelve una cadena donde cada subcadena target en s es reemplazada por replacement.
Devuelve una cadena que es la cadena s invertida.
Divide s usando la subcadena s2 y devuelve los resultados. Si limit es positivo, entonces solo devuelve como máximo esa cantidad de resultados. Si limit es cero, entonces elimina los resultados vacíos finales.
Devuelve un booleano que indica si s comienza con s2.
Devuelve la subcadena de s que
comienza en i y continúa hasta j;
i y j pueden ser negativos.
Si j está ausente, entonces se asume que es igual a -1
(que es lo mismo que la longitud de la cadena).
En particular,
la llamada string.sub(s,1,j) devuelve un prefijo de s
con longitud j,
y string.sub(s, -i) devuelve un sufijo de s
con longitud i.
Si, después de la traducción de índices negativos,
i es menor que 1,
se corrige a 1.
Si j es mayor que la longitud de la cadena,
se corrige a esa longitud.
Si, después de estas correcciones,
i es mayor que j,
la función devuelve la cadena vacía.
Convierte una cadena a binario llamando al método de Java String.getBytes.
Cuando se llama sin base,
to_number intenta convertir su argumento a un número.
Si el argumento es
una cadena convertible a un número,
entonces to_number devuelve este número;
de lo contrario, devuelve nil.
La conversión de cadenas puede resultar en enteros o flotantes.
Cuando se llama con base,
entonces s debe ser una cadena para ser interpretada como
un numeral entero en esa base.
En bases superiores a 10, la letra 'A' (en mayúsculas o minúsculas)
representa 10, 'B' representa 11, y así sucesivamente,
con 'Z' representando 35.
Si la cadena s no es un numeral válido en la base dada,
la función devuelve nil.
Elimina los espacios en blanco al principio y al final llamando al método de Java String.trim.
Devuelve los códigos numéricos internos de los caracteres s[i],
s[i+1], ..., s[j].
El valor predeterminado para i es 1;
el valor predeterminado para j es i.
Estos índices se corrigen
siguiendo las mismas reglas de la función String.sub.
Recibe una cadena y devuelve una copia de esta cadena con todas las letras minúsculas cambiadas a mayúsculas. Todos los demás caracteres se dejan sin cambios. La definición de lo que es una letra minúscula depende de la configuración regional actual.
Las expresiones regulares se manejan usando una tabla regex generada por String.regex.
La coincidencia de patrones se basa en la clase de Java Pattern.
Busca la primera coincidencia de
la regex en la cadena s.
Si encuentra una coincidencia, entonces find devuelve los índices de s
donde comienza y termina esta ocurrencia;
de lo contrario, devuelve nil.
Un tercer argumento numérico opcional init especifica
dónde comenzar la búsqueda;
su valor predeterminado es 1 y puede ser negativo.
Si la regex tiene capturas, entonces en una coincidencia exitosa los valores capturados también se devuelven, después de los dos índices.
Devuelve una función iteradora que,
cada vez que se llama,
devuelve las siguientes capturas de la regex
sobre la cadena s.
Si la regex no especifica capturas,
entonces la coincidencia completa se produce en cada llamada.
Como ejemplo, el siguiente bucle
iterará sobre todas las palabras de la cadena s,
imprimiendo una por línea:
local r = String.regex[[\w+]]
local s = "hello world from Lua"
for w in r.gmatch(s) do
print(w)
end
El siguiente ejemplo recoge todos los pares key=value de la
cadena dada en una tabla:
local t = {}
local r = String.regex[[(\w+)=(\w+)]]
local s = "from=world, to=Lua"
for k, v in r.gmatch(s) do
t[k] = v
end
Para esta función, un acento circunflejo '^' al inicio de un patrón no
funciona como un ancla, ya que esto impediría la iteración.
Devuelve una copia de s
en la que todas (o las primeras n, si se da)
ocurrencias de la regex han sido
reemplazadas por una cadena de reemplazo especificada por repl,
que puede ser una cadena, una tabla o una función.
gsub también devuelve, como su segundo valor,
el número total de coincidencias que ocurrieron.
El nombre gsub proviene de Global SUBstitution.
Si repl es una cadena, entonces su valor se usa para el reemplazo.
El carácter \ funciona como un carácter de escape.
Cualquier secuencia en repl de la forma $d,
con d entre 1 y 9,
representa el valor de la d-ésima subcadena capturada.
La secuencia $0 representa la coincidencia completa.
Si repl es una tabla, entonces la tabla se consulta para cada coincidencia,
usando la primera captura como clave.
Si repl es una función, entonces esta función se llama cada vez que ocurre una
coincidencia, con todas las subcadenas capturadas pasadas como argumentos,
en orden.
En cualquier caso, si la regex no especifica capturas, entonces se comporta como si toda la regex estuviera dentro de una captura.
Si el valor devuelto por la consulta de la tabla o por la llamada a la función no es nil, entonces se usa como la cadena de reemplazo; de lo contrario, si es nil, entonces no hay reemplazo (es decir, la coincidencia original se mantiene en la cadena).
Aquí hay algunos ejemplos:
local r = String.regex[[(\w+)]]
local x = r.gsub("hello world", "$1 $1")
--> x="hello hello world world"
local r = String.regex[[(\w+)]]
local x = r.gsub("hello world", "$0 $0", 1)
--> x="hello hello world"
local r = String.regex[[(\w+)\s*(\w+)]]
local x = r.gsub("hello world from Luan", "$2 $1")
--> x="world hello Luan from"
local r = String.regex[[\$(.*?)\$]]
local x = r.gsub("4+5 = $return 4+5$", function(s)
return load(s)()
end)
--> x="4+5 = 9"
local r = String.regex[[\$(\w+)]]
local t = {name="lua", version="5.3"}
local x = r.gsub("$name-$version.tar.gz", t)
--> x="lua-5.3.tar.gz"
Busca la primera coincidencia de
la regex en la cadena s.
Si encuentra una, entonces match devuelve
las capturas de la regex;
de lo contrario, devuelve nil.
Si la regex no especifica capturas,
entonces se devuelve la coincidencia completa.
Un tercer argumento numérico opcional init especifica
dónde comenzar la búsqueda;
su valor predeterminado es 1 y puede ser negativo.
Devuelve un booleano que indica si la regex se puede encontrar en la cadena s.
Esta función es equivalente a
return regex.match(s) ~= nil
Cambia el patrón de la regex a pattern.
Divide s usando la regex y devuelve los resultados. Si limit es positivo, entonces solo devuelve como máximo esa cantidad de resultados. Si limit es cero, entonces elimina los resultados vacíos finales.
Incluye esta librería por:
local Binary = require "luan:Binary.luan"
Igual que Base64.Decoder.decode de Java.
Igual que Base64.Encoder.encodeToString de Java.
Recibe cero o más bytes (como enteros). Devuelve un binario con longitud igual al número de argumentos, en el que cada byte tiene el código numérico interno igual a su argumento correspondiente.
Devuelve los códigos numéricos internos de los bytes b[i],
b[i+1], ..., b[j].
El valor predeterminado para i es 1;
el valor predeterminado para j es i.
Estos índices se corrigen
siguiendo las mismas reglas de la función String.sub.
Implementado en Java como:
return MessageDigest.getInstance(algorithm).digest(b);
Convierte un binario a una cadena hexadecimal.
Si charset no es nulo, entonces convierte el binario b a una cadena usando el constructor de String de Java, de lo contrario, convierte cada byte en un carácter.
Incluye esta librería por:
local Table = require "luan:Table.luan"
Esta librería proporciona funciones genéricas para la manipulación de tablas.
Proporciona todas sus funciones dentro de la tabla Table.
Devuelve una tabla con claves de cadena insensibles a mayúsculas y minúsculas. Copia tbl o está vacía.
Limpia la tabla.
Dada una lista,
devuelve la cadena list[i]..sep..list[i+1] ··· sep..list[j].
El valor predeterminado para sep es la cadena vacía,
el predeterminado para i es 1,
y el predeterminado para j es #list.
Si i es mayor que j, devuelve la cadena vacía.
Si i es nil, devuelve una copia superficial de tbl.
De lo contrario, devuelve una nueva tabla que es una lista de los elementos tbl[i] ··· tbl[j].
Por defecto, j es #tbl.
Inserta el elemento value en la posición pos en list,
desplazando hacia arriba los elementos
list[pos], list[pos+1], ···, list[#list].
Aplica recursivamente java_to_table_shallow para convertir un objeto Java a tablas anidadas. java_to_table_shallow por defecto es Table.java_to_table_shallow.
Convierte un objeto Java a una tabla. Funciona para tipos de colección List, Map, Set, y arreglos de Java.
Devuelve una nueva tabla con todos los parámetros almacenados en las claves 1, 2, etc.
y con un campo "n" con el número total de parámetros.
Tenga en cuenta que la tabla resultante puede no ser una secuencia.
Elimina de list el elemento en la posición pos,
devolviendo el valor del elemento eliminado.
Cuando pos es un entero entre 1 y #list,
desplaza hacia abajo los elementos
list[pos+1], list[pos+2], ···, list[#list]
y borra el elemento list[#list];
El índice pos también puede ser 0 cuando #list es 0,
o #list + 1;
en esos casos, la función borra el elemento list[pos].
Ordena los elementos de la lista en un orden dado, en su lugar,
desde list[1] hasta list[#list].
Si se da comp,
entonces debe ser una función que reciba dos elementos de la lista
y devuelva verdadero cuando el primer elemento debe venir
antes que el segundo en el orden final
(para que not comp(list[i+1],list[i]) sea verdadero después de la ordenación).
Si no se da comp,
entonces se utiliza el operador estándar de Lua <.
El algoritmo de ordenación no es estable; es decir, los elementos considerados iguales por el orden dado pueden tener sus posiciones relativas cambiadas por la ordenación.
Devuelve los elementos de la lista dada. Esta función es equivalente a
return list[i], list[i+1], ···, list[j]
Por defecto, i es 1 y j es list.n or #list.
Incluye esta librería por:
local Number = require "luan:Number.luan"
Devuelve x como un double.
Devuelve x como un float.
Si el valor x es convertible a un entero,
devuelve ese entero.
De lo contrario, lanza un error.
Si el valor x es convertible a un long,
devuelve ese long.
De lo contrario, lanza un error.
Convierte el valor long i a una cadena llamando a Long.toString.
Devuelve una cadena para el tipo numérico de x. Los posibles valores de retorno incluyen "integer", "long", "double", y "float".
Incluye esta librería por:
local Math = require "luan:Math.luan"
Esta librería proporciona funciones matemáticas básicas.
Proporciona todas sus funciones y constantes dentro de la tabla Math.
Devuelve el valor absoluto de x.
Devuelve el arcocoseno de x (en radianes).
Devuelve el arcoseno de x (en radianes).
Devuelve el arcotangente de un valor; el ángulo devuelto está en el rango -pi/2 a pi/2.
Devuelve el arcotangente de y/x (en radianes),
pero usa los signos de ambos parámetros para encontrar el
cuadrante del resultado.
(También maneja correctamente el caso de que x sea cero.)
Devuelve el valor integral más pequeño mayor o igual a x.
Devuelve el coseno de x (se asume que está en radianes).
Convierte el ángulo x de radianes a grados.
Devuelve el valor ex
(donde e es la base de los logaritmos naturales).
Devuelve el valor integral más grande menor o igual a x.
Devuelve el resto de la división de x por y
que redondea el cociente hacia cero.
Un valor mayor que cualquier otro valor numérico.
Devuelve el logaritmo de x en la base dada.
El valor predeterminado para base es e
(para que la función devuelva el logaritmo natural de x).
Devuelve el argumento con el valor máximo,
según el operador de Lua <.
Un entero con el valor máximo para un entero.
Devuelve el argumento con el valor mínimo,
según el operador de Lua <.
Un entero con el valor mínimo para un entero.
Devuelve la parte integral de x y la parte fraccionaria de x.
El valor de π.
Convierte el ángulo x de grados a radianes.
Cuando se llama sin argumentos,
devuelve un flotante pseudoaleatorio con distribución uniforme
en el rango [0,1).
Cuando se llama con dos enteros m y n,
Math.random devuelve un entero pseudoaleatorio
con distribución uniforme en el rango [m, n].
(El valor m-n no puede ser negativo y debe caber en un entero de Luan.)
La llamada Math.random(n) es equivalente a Math.random(1,n).
Esta función es una interfaz para la función generadora pseudoaleatoria subyacente proporcionada por Java. No se pueden dar garantías sobre sus propiedades estadísticas.
Devuelve el seno de x (se asume que está en radianes).
Devuelve la raíz cuadrada de x.
(También puedes usar la expresión x^0.5 para calcular este valor.)
Devuelve la tangente de x (se asume que está en radianes).