HoopLang Docs
/
Playground
Referencia del lenguaje

Estructura léxica

Este capítulo describe cómo el compilador separa el texto fuente de un archivo .hoop en tokens: espacios, comentarios, identificadores, palabras clave, literales, operadores y puntuación. Lo que aquí se describe corresponde al analizador léxico (crates/hoop/src/lexer.rs); cómo se combinan los tokens se describe en Expresiones y Declaraciones.

Codificación y posiciones#

El fuente es texto Unicode (UTF-8). El analizador trabaja por caracteres (puntos de código), no por bytes: las columnas de los diagnósticos (archivo:línea:columna) cuentan caracteres desde 1, y cada salto de línea \n incrementa la línea.

Cualquier carácter que Unicode considere espacio en blanco (espacio, tabulación, \r, \n, …) separa tokens y se descarta. Los saltos de línea no tienen significado sintáctico: una declaración puede ocupar varias líneas.

Un carácter que no inicia ningún token es un error:

Salida del compilador
error E000: unexpected character `@`

Comentarios#

ebnf
comentario_linea  = "//" { cualquier carácter salvo "\n" } ;
comentario_bloque = "/*" { cualquier carácter } "*/" ;
  • // comenta hasta el fin de la línea.
  • /* … */ comenta un bloque, que puede abarcar varias líneas. Los bloques no se anidan: el primer */ cierra el comentario.
  • Un /* sin su */ es E000: unclosed /* comment.

Los comentarios no afectan el significado; el formateador (hoop fmt, ver Herramientas) los conserva.

HoopLang
// comentario de línea
const borde = 2.5mm /* comentario
                       de bloque */

Identificadores#

ebnf
identificador = ( letra | "_" ) { letra | dígito | "_" } ;

Una letra es cualquier carácter alfabético Unicode y un dígito, cualquier carácter alfanumérico Unicode; así, ñandú, borde_negro y _x1 son identificadores válidos. Se distinguen mayúsculas de minúsculas (Twill no es twill).

HoopLang
const ñandú = 3mm
const borde_negro = 1.2mm
const _x1 = 2

Nombres calificados#

Un identificador seguido de . y otro identificador sin ( a continuación forma un nombre calificado: club.negro, escudo.center, canvas.width. Se usan para los nombres importados con espacio de nombres (ver Módulos) y para los miembros de una forma con nombre (ver Expresiones § Miembros). Si después del segundo identificador viene (, es una llamada a método (escudo.inset(2mm)). Los miembros y métodos también se aplican al resultado de cualquier expresión: canvas.inset(5mm).center, rect(size: (10mm, 5mm)).width.

Palabras clave#

El analizador léxico no reserva ninguna palabra: todas se leen como identificadores, y el analizador sintáctico las reconoce según el contexto. Las palabras con significado especial son:

ContextoPalabras
Inicio de una declaraciónimport, design, hoop, thread, param, const, shape, layer
Dentro de importfrom, as
Contenido de una capaseq, inside, for, in, if, else, place, at
Primitivasfill, satin, run, triple, text
Expresionesand, or, not, mod, if, else, path (seguido de {)
Segmentos de pathfrom, line, curve, close
Valores con nombretrue, false

Consecuencias de que sean contextuales:

  • true y false se evalúan siempre como Bool, aunque exista una constante con ese nombre.
  • Una palabra como layer o for puede usarse como nombre de constante (const layer = 2 compila), pero no es recomendable: dentro de una capa, for seguido de un identificador inicia un bucle.
  • Al inicio de una declaración, cualquier otra palabra es E000: x is not a declaration (import, design, hoop, thread, const, shape or layer).

Literales#

Números#

ebnf
número  = cifras [ unidad ] ;
cifras  = ( dígito | "." ) { dígito | "." } ;   (* sin ".." *)
unidad  = "mm" | "cm" | "deg" | "%" ;

Un número es una secuencia de dígitos ASCII y puntos, seguida inmediatamente (sin espacio) de una unidad opcional. La secuencia se interpreta como un número decimal: 2.5, .5 y 1. son válidos; 1.2.3 es E000: invalid number: 1.2.3. No hay notación exponencial ni signo: -3mm es el operador - aplicado a 3mm (ver Expresiones).

Un número termina antes de .., de modo que 0..4 son tres tokens (0, .., 4).

La unidad determina el tipo (ver Tipos):

LiteralTipoValor interno
2.5mmLength2.5 mm
1cmLength10 mm
45degAngle45 grados
30%Ratio0.30
3Int3
  • Cualquier secuencia de letras (o %) pegada al número que no sea una de las unidades es E001: unknown unit px (use mm, cm, deg or %).
  • Un número sin unidad debe ser entero: 1.5 es E001: 1.5 has no unit: add mm, cm, deg or %.
  • Con espacio entre número y unidad (3 mm) la unidad se lee como un identificador aparte, lo que suele terminar en un error de sintaxis.
HoopLang
const a = 2.5mm
const b: Length = .5mm
const c: Length = 1cm
const d: Angle = 45deg
const e: Ratio = 30%
const f: Int = 3
HoopLang
// error E001
const g = 1.5 // error E001

Textos#

ebnf
texto   = '"' { carácter | escape } '"'
        | "'" { carácter | escape } "'" ;
escape  = "\" carácter ;

Un texto (tipo String) se escribe entre comillas dobles o simples; termina en la misma comilla con que empezó, así que dentro de "…" la comilla simple es un carácter más, y viceversa. Un texto no puede contener un salto de línea literal: un texto sin cerrar antes del fin de la línea es E000: unclosed string (missing closing quote).

Escapes: \n es un salto de línea; \ seguido de cualquier otro carácter produce ese carácter (\" → ", \' → ', \\ → \, \t → t).

HoopLang
const a = "HANNOVER"
const b = 'Club "Los Andes"'
const c = "MARÍA\nJOSÉ"
const d = 'it\'s'

Colores#

ebnf
color = "#" hex hex hex hex hex hex ;

Un color (tipo Color) es # seguido de exactamente seis dígitos hexadecimales. Se normaliza a minúsculas: #1C1616 y #1c1616 son el mismo valor. Cualquier otra cantidad de dígitos es E000: a color is written #rrggbb (6 hex digits).

HoopLang
const rojo = #C8102E
const igual: Bool = #FF0000 == #ff0000

Booleanos#

true y false no son tokens propios: son identificadores que el verificador evalúa como valores Bool (ver Palabras clave).

Operadores y puntuación#

TokenUso
{ }bloques: propiedades, capas, cuerpos de for/if, path
( )agrupación, puntos (x, y), argumentos
[ ]listas
,separa argumentos, elementos y propiedades (opcional en muchos sitios)
:nombre: valor, anotación de tipo
=en const, shape, param, thread
.nombre calificado, miembro, método
..rango (0..4)
+ - * /aritmética; + - también unión y diferencia de formas
&intersección de formas
== != < <= > >=comparación

Los tokens de dos caracteres (==, !=, <=, >=, ..) se reconocen antes que los de uno. ! solo no es un token (not es la negación lógica). Un . seguido de un dígito inicia un número (.5mm), no un acceso.

Los operadores con nombre (and, or, not, mod) son identificadores reconocidos por el analizador sintáctico; su precedencia está en Expresiones § Precedencia.