Sintaxis básica
Cómo se escribe un programa en JARU: en qué orden van sus partes, cómo se separan las instrucciones, cómo se cierran los bloques, cómo se escriben los valores y en qué orden se calculan los operadores. Al final están las trampas en las que más se cae.
Cada parte del lenguaje tiene después su página: Variables y constantes, Operadores, Estructuras de control, Funciones...
Un programa
Un programa de JARU es un fichero .aru, o varios. No hay una función principal: la VM ejecuta el fichero principal de arriba abajo, y el programa acaba al llegar al final.
Lo habitual es escribirlo en este orden:
use Math // 1. Los módulos que usa el programa
const LADO = 4 // 2. Las constantes
func area(lado) // 3. Las funciones
return lado * lado
end
// 4. Lo que hace el programa
var a = area(LADO)
println("Área: ", a) // Área: 16
println("La mayor: ", Math.max(a, 20)) // La mayor: 20
useabre los módulos de la VM que vas a usar; caben varios en una línea:use Display, Sprite, Input. Sin él, el programa compila, pero se para en la primera línea que usa el módulo, con el error «Module 'Math' not found or not imported.». Los módulos están en La API.import "Fichero.aru"trae el código de otro fichero del proyecto. Ese código se ejecuta antes que la primera línea del fichero principal, aunque elimportesté más abajo. Lo cuenta Programas de varios ficheros.- Una función existe desde la línea en que se declara. Si la llamas desde más arriba, el programa se para con el error «Undefined variable». Más en Funciones.
- El programa también puede terminar antes, con
exit: ver Errores y excepciones.
Instrucciones y punto y coma
Lo normal es escribir una instrucción por línea. El punto y coma del final es opcional:
var vidas = 3
var puntos = 0;
Para poner varias en la misma línea, sepáralas con ;. El compilador también las separa sin él, pero se leen peor:
var x = 10; var y = 20; println(x + y) // 30
El salto de línea no termina una instrucción: el compilador la da por acabada cuando lo que viene detrás ya no puede formar parte de ella. Por eso una instrucción larga puede seguir en la línea de abajo:
var total = 10 +
20 +
30
println(total) // 60
++ o --Como el salto de línea no corta la instrucción, un ++ o un -- al principio de una línea se pega a la línea de arriba si esta acaba en una variable:
var partidas = 0
var puntos = 10
var record = puntos
++partidas // se lee como: var record = puntos++
println(record, " ", puntos, " ", partidas) // 10 11 0
Escribe partidas++ o partidas += 1, o termina con ; la línea de arriba.
Comentarios
// Comentario de una línea: llega hasta el final de la línea
var vidas = 3 // también detrás de una instrucción
/* Comentario de
varias líneas */
println("10 // 2") // dentro de una cadena, // es texto: imprime 10 // 2
- Los comentarios pueden llevar tildes y eñes.
- Un
/* … */no puede ir dentro de otro: el primer*/cierra el comentario, y lo que queda detrás da error. - Un
/*sin su*/da el error «Detected unterminated comment, expecting '*/'».
/* Un comentario /* dentro de otro */ no se puede */
println("hola")
Bloques: end, paréntesis y then
Todos los bloques se cierran con end. La sangría no cuenta para el compilador: solo sirve para leer mejor el código.
| Bloque | Se abre con | Página |
|---|---|---|
| Condición | if (…) then, y dentro elsif (…) then y else | Estructuras de control |
| Selección | switch (…), y dentro case …: y default: | Estructuras de control |
| Bucles | for (…; …; …), foreach (var x in …), while (…) y until (…) | Estructuras de control |
| Funciones | func nombre(…) y fn(…): | Funciones |
| Clases | class Nombre, y dentro def metodo(…) | Clases y objetos |
| Structs y enumerados | struct Nombre y enum Nombre | Structs y Enumerados |
| Errores | try, y dentro catch (var e) | Errores y excepciones |
Las reglas que más se olvidan:
- La condición va entera entre paréntesis en
if,elsif,while,untilyswitch. ifyelsifllevan siemprethen.whileyuntilno llevan nithennido.- Es
elsif, nielifnielse if. Unelse ifabre unifnuevo dentro delelse, que necesita su propioend. Si falta, el compilador lo dice: «missing 'end' at the end of the 'else' block (check the 'else if' on line 4: in JARU it is 'elsif')». - Un bloque corto cabe en una línea:
if (vidas == 0) then println("Fin") end.
var vidas = 2
var tiempo = 30
if (vidas > 0 and tiempo > 0) then
println("Sigue jugando")
elsif (vidas > 0) then
println("Se acabó el tiempo")
else
println("Fin de la partida")
end
Estos tres no compilan:
var vidas = 2
if vidas > 0 then // falta el paréntesis
println("Sigue jugando")
end
var vidas = 2
var tiempo = 30
if (vidas > 0) and (tiempo > 0) then // la condición se acaba en el primer )
println("Sigue jugando")
end
var nivel = 2
if (nivel == 1) then
println("Fácil")
elif (nivel == 2) then // es elsif
println("Normal")
end
Literales
Así se escribe cada valor directamente en el código:
| Valor | Ejemplos | Cómo se escribe |
|---|---|---|
| Entero | 42, -7, 0x1F, 0xff | En decimal, o en hexadecimal con 0x delante |
| Decimal | 3.14, .5, 1e3, 2.5e-2 | Con punto o con exponente |
| Cadena | "hola", 'hola' | Entre comillas dobles o simples |
| Booleano | true, false, on, off | on es true, y off es false |
| Sin valor | nil | |
| Lista, mapa y array | [1, 2], {"x": 1}, {1, 2} | Ver Listas, mapas y arrays |
println(0x1F) // 31
println(0xff) // 255
println(1e3) // 1000
println(on == true) // true
En hexadecimal, las letras valen en mayúsculas y en minúsculas. Un número con exponente es siempre decimal, aunque println escriba 1000. El rango de los enteros, lo que pasa con un número que no cabe en 32 bits y los hexadecimales por encima de 0x7FFFFFFF están en Tipos de datos.
Cadenas
Una cadena acaba con la misma comilla con la que empieza, así que la otra puede ir dentro: 'Dijo "hola"', "It's". La barra \ empieza un escape: \n (salto de línea), \r, \t y \\ (una barra).
\"no es un escape. La cadena no se corta ahí, pero la barra se queda dentro:"dijo \"hola\""imprimedijo \"hola\". Para meter comillas dobles, escribe la cadena entre comillas simples.- Cuidado con las rutas de Windows:
"C:\nivel"lleva un salto de línea. Escribe"C:\\nivel". - Una cadena no acaba al final de la línea. Si se te olvida cerrarla, sigue en las líneas de abajo, y el error, «String without terminating quotation mark», sale más abajo de donde falta la comilla.
- Las tildes y la eñe valen dentro de las cadenas, pero no en los nombres.
Qué pone cada escape y cómo se escribe una cadena de varias líneas está en Escribir cadenas.
Prioridad de los operadores
Cuando una expresión tiene varios operadores, se calculan antes los de las filas de arriba. Los de una misma fila se calculan de izquierda a derecha, salvo ? : y las asignaciones, que van de derecha a izquierda.
| Operadores | Qué son | |
|---|---|---|
| 1 | a.b, a[i], f(x) | Propiedad o método, índice y llamada |
| 2 | -x, +x, not x, !x, ~x, ++x, --x, x++, x-- | Operadores de un solo valor |
| 3 | *, /, %, div, mod | Multiplicación y división |
| 4 | +, - | Suma y resta |
| 5 | <<, >> | Desplazamiento de bits |
| 6 | &, |, ^ | Bit a bit |
| 7 | <, <=, >, >= | Comparación |
| 8 | ==, != | Igualdad |
| 9 | and, or | Lógicos |
| 10 | ? : | Condicional |
| 11 | =, +=, -=, *=, /=, %= | Asignación |
Tres cosas cambian respecto a otros lenguajes:
println(not 1 == 2) // false: es (not 1) == 2
println(not (1 == 2)) // true
println(6 & 3 == 2) // true: es (6 & 3) == 2
println(4 | 1 & 2) // 0: es (4 | 1) & 2
println(true or false and false) // false: es (true or false) and false
println(true or (false and false)) // true
noty!se calculan antes que las comparaciones. Para negar una comparación, ponla entre paréntesis.- Los operadores bit a bit van antes que las comparaciones, al revés que en C, y
&,|y^tienen la misma prioridad. andyortambién tienen la misma prioridad:
and y or tienen la misma prioridadEn la mayoría de los lenguajes, and se calcula antes que or. En JARU no: se calculan de izquierda a derecha, así que a or b and c es (a or b) and c. Cuando mezcles and y or, pon paréntesis.
Trampas
Todos los problemas conocidos de JARU, juntos, están en Problemas conocidos.
Cadena + número
+ une dos cadenas, pero no una cadena y un número. "Vidas: " + vidas compila, pero el programa se para al llegar a esa línea, con el error «Unsupported operand types for operator '+'.». Convierte antes el número con toString(), como en "Vidas: " + vidas.toString(), o pasa las partes a println por separado: println("Vidas: ", vidas). Lo cuenta Unir cadenas.
.. no es un operador de JARU: el compilador da el error «Operator '..' doesn't exist in JARU. Use '+' to join strings.».
var vidas = 3
println("Vidas: " .. vidas)
Métodos sobre un literal o un paréntesis
Un método va detrás de una variable, de un elemento o de una propiedad: nombre.size(), lista[0].toString(), jugador.vidas.toString(). Detrás de un literal o de un paréntesis no compila, con el error «Expected identifier in method name.»:
println("hola".size())
var a = 2
var b = 3
println((a + b).toString())
Guarda antes el valor en una variable:
var saludo = "hola"
println(saludo.size()) // 4
var a = 2
var b = 3
var suma = a + b
println(suma.toString()) // 5
Con un número es peor: en 5.toString(), el compilador lee 5. como el decimal 5.0, y toString() como otra instrucción. Una línea como var s = 5.toString() compila, y el programa se para con «Undefined variable 'toString'.».
Indexar lo que devuelve una llamada
f(x)[0] compila, pero no indexa lo que devuelve f: el programa se para con el error «This object type is not indexable.». Con un método es peor: mapa.keys()[0] hace que el compilador se cierre sin explicar el error, y lista.copy()[0] para el programa con un error que no se entiende («List has no property ''.»). Guarda antes el resultado en una variable:
func extremos(lista)
return [lista[0], lista[lista.size() - 1]]
end
var numeros = [4, 8, 15]
// println(extremos(numeros)[0]) <- se para al ejecutarse
var e = extremos(numeros)
println(e[0], " ", e[1]) // 4 15