# 01 — Sintaxis > [← README](README.md) · [Siguiente: 02 — Tipos →](02-tipos.md) > **Convención editorial.** Usamos **type** (sin traducir) cuando referimos a la entidad sintáctica del lenguaje — un type declarado por el programador, una keyword, o la categoría léxica que empieza con mayúscula. Usamos **tipo** (en español) cuando referimos al concepto general — "el tipo de un valor", "tipo inferido", "tipos primitivos". El criterio: si la palabra aparece junto a un identificador concreto o reemplaza a la keyword del lenguaje, "type"; si describe la noción, "tipo". ## Sensibilidad a mayúsculas Keywords del lenguaje → case insensitive. `action`, `Action`, `ACTION` son equivalentes. Identificadores → case sensitive. La primera letra determina la categoría: - **Mayúscula → type**: `Background`, `LoginError`, `Sprite`. - **Minúscula → todo lo demás**: variables, instancias, acciones, parámetros. `background`, `my_bg`, `factorial`, `login`, `move_camera`. **Excepción — primitivos y colecciones del núcleo:** los tipos `number`, `text`, `boolean` y `nothing`, y las keywords de colección `list`, `map` y `set`, se escriben en minúscula aunque son tipos. Son parte del lenguaje mismo — el compilador los trata distinto a los types definidos por el programador. Todo type creado por el programador sigue la regla normal: mayúscula obligatoria. ``` Background # type — empieza con mayúscula (PascalCase) has style: BackgroundStyle end background: Background # instancia — empieza con minúscula, naming libre my_bg: Background bg: Background action move_camera with at: Point # acción — empieza con minúscula camera.position = at end ``` El compilador rechaza un type que empiece con minúscula o cualquier otro identificador que empiece con mayúscula. La distinción es estructural, no solo convención — permite que una expresión como `factorial with n - 1` se lea sin ambigüedad: `factorial` no puede ser un type, así que necesariamente es una acción o una variable. Un type define la estructura de un objeto — es el blueprint del que se crean las instancias. Caracteres válidos en identificadores: letras, números y `_`. El punto (`.`) es exclusivo del acceso a miembros — nunca puede formar parte de un nombre. El primer carácter debe ser una letra — nunca `_` ni un dígito. Esto mantiene la regla "la primera letra define la categoría" sin casos especiales: no existe `_foo` ni `_Sprite`. ``` Motor25D # válido Motor2_5D # válido Motor2.5D # error — punto reservado para acceso a miembros _foo # error — el primer carácter debe ser letra 2Motor # error — el primer carácter debe ser letra ``` ## Keywords reservadas Todas son case insensitive. El compilador las rechaza como nombres de identificadores. ``` # control de flujo if then else match when on changes for each in where repeat times return while break continue retain # definición action needs returns fails with has does is can be derives from end # módulos module expose use exposing # lógica and or not # colecciones list set map of to add remove contains # valores nothing true false # nothing también funciona como tipo (text or nothing) # tipos primitivos number text boolean # otros as raw increases decreases by ``` **Keywords contextuales — solo reservadas en posiciones específicas.** - `success` y `failure` son etiquetas válidas únicamente tras `on` en un bloque de handler de resultado (`on success`, `on success as user`, `on failure`, `on failure as err`). - `wait` solo se reserva tras `can` en una firma de acción (`-> X can wait`), para marcar acciones que pueden bloquear esperando un mensaje. - `parallel` solo se reserva tras `in` en un `for each` (`for each x in xs in parallel`), para indicar paralelismo de datos. Fuera de esos contextos, el compilador las acepta como identificadores normales. La razón: son nombres con valor semántico solo cuando rotulan una construcción específica; reservarlas globalmente colisionaría con nombres comunes (`success`, `failure` como variables de estado; `wait`, `parallel` como nombres de campos o acciones de un módulo). Algunas keywords tienen más de un rol — el compilador las desambigua por contexto. La lista siguiente es una referencia rápida; cada rol específico se cubre en la sección donde aparece (acciones en el archivo 04, colecciones en 07, range y match en 05, módulos en 06): - `as` — casting (`42 as text`) y binding de resultado (`on success as user`) - `with` — declara parámetros en la firma (`action f with n: number`) y los pasa en la llamada (`f with n`) - `of` — especifica el tipo de una colección (`list of number`), declara parámetros de tipo genéricos (`action first_of of T`) y aplica una función matemática (`floor of x`) - `to` — asocia clave a valor en map (`map of K to V`) y extremo superior de un range (`1 to 10`); además `does add to items` - `from` — origen de un valor derivado (`derives from`) y delegación de protocolo (`does remove from items`) - `by` — paso en un range (`0 to 100 by 10`) y delta exacto en una transición (`when score increases by 100`) - `or` — operador lógico (`a or b`) y unión de tipos en firmas (`User or nothing`, `T or fails with E`) - `->` — retorno de acción, branch de match, handler de resultado y asociación en map (ver "Principio de símbolos") ## Principio de símbolos Si el símbolo se deriva de notación matemática universal, se queda. Si es una convención arbitraria sin base matemática, se reemplaza con una palabra. `->` aparece en cuatro contextos: retorno de acción, branch de match, handler de resultado y asociación en map. En todos significa lo mismo — "esto produce aquello" — y el compilador lo desambigua por contexto. ## Operadores — se quedan ``` A + B A - B A * B A / B A = B A != B A > B A < B A >= B A <= B ``` **`=` cumple dos roles, desambiguados por contexto sintáctico:** - **Asignar a un *target asignable*.** Un target asignable es siempre uno de: un nombre, `obj.field`, o `obj[key]`. Seis contextos comparten esa estructura: - Declaración inicial de variable: `n = 5`, `result: Outcome = play_round` - Rebind de variable local: `total = total + n` - Campo dentro de un bloque de instanciación: `position = my_point` - Argumento nombrado en una llamada: `move_camera with at = my_point` - Campo de una instancia: `camera.tilt = 90` - Slot de un map por clave: `scores["Alice"] = 95` - **Comparación de igualdad** — `if n = 0 then ...`, `match score where score = 100`, `tier = if lives = 0 then "fin" else "sigue"`. La regla es estructural, no posicional: si `=` aparece como la "raíz" de un statement, de una línea de un bloque de instanciación, o de un argumento dentro de un `with`, es asignación. Si aparece dentro de la condición de un `if`/`match`/`when` o del lado derecho de otra asignación, es comparación. El compilador nunca confunde los dos casos — no hay ambigüedad parseable. Es la misma elección de Pascal, Lua y SQL. Quien viene de C/Java/Python necesita ajustar el hábito de leer `==`, pero el compilador rechaza inmediatamente cualquier mal uso (intentar asignar dentro de una condición no parsea). ## Operadores — se reemplazan ``` && -> and || -> or !A -> not A {} -> end (solo como delimitador de bloque) ; -> nada (fin de línea es suficiente) ``` Las llaves `{}` siguen apareciendo en literales de colección — `list { 1, 2, 3 }`, `set {}`, `map { "a" -> 1 }` — porque ahí no delimitan un bloque sino el contenido del literal. La sustitución por `end` aplica únicamente al rol de delimitador de bloque. ## Precedencia de operadores Sigue la convención matemática estándar. De mayor a menor: ``` 1. acceso a miembro obj.field (más alto — siempre agrupa primero) 2. llamadas action with arg (agrupa a la derecha del with) 3. operaciones aritméticas * / antes que + - 4. comparaciones = != > < >= <= 5. is nothing x is nothing 6. not 7. and 8. or ``` ``` not a = b → not (a = b) # comparación primero, luego not not a and b → (not a) and b # not primero, luego and a and b or c → (a and b) or c # and antes que or not sprite.label is nothing → not (sprite.label is nothing) # is nothing primero, luego not ``` Las llamadas con `with` agrupan a la derecha: `factorial with n - 1` es `factorial with (n - 1)`, no `(factorial with n) - 1`. Si el argumento es una expresión compleja, los paréntesis lo hacen explícito. ### Parseo greedy de `with` y `of` Una vez que aparece `with` después de un nombre de acción, se consume todo lo que sigue como lista de argumentos separados por comas, hasta encontrar uno de estos delimitadores: - fin de línea - paréntesis de cierre `)` - corchete de cierre `]` que pertenezca a una indexación exterior, sea de list o map (`scores[k] = total of items with x`, `items[i] = total of xs with k`) - coma o llave de cierre `}` que pertenezca a un literal de colección exterior (`list { f with x, g with y }`) - una keyword de control (`then`, `else`, `where`) - el operador `->` (que abre el cuerpo de un handler, branch de `match`, o cuerpo de `for each`) - un cierre de bloque (`end`) Para "sacar" parte de la expresión de la lista de argumentos, se usan paréntesis. La misma regla greedy y los mismos delimitadores aplican a `of` cuando introduce el argumento de una función matemática: `floor of 10 / 3` es `floor(10 / 3)`, no `floor(10) / 3`. Para forzar lo segundo, paréntesis explícitos: `(floor of 10) / 3`. ``` factorial with n - 1 → factorial(n - 1) move_camera with at, tilt + 1 → move_camera(at, tilt + 1) total = factorial with 5 → total = factorial(5) total = factorial with 5 + 1 → total = factorial(5 + 1) # greedy hasta fin de línea total = (factorial with 5) + 1 → total = factorial(5) + 1 # paréntesis explícito if n = factorial with 5 then ok → if (n = factorial(5)) then ok # `then` corta los argumentos ``` **Estilo recomendado.** Cuando un argumento contiene operadores aritméticos y la llamada está dentro de una expresión más grande (parte de una asignación con otras operaciones, condición de `if`, segundo operando de otro `+`), agrega paréntesis explícitos alrededor del argumento. La semántica no cambia, pero la intención queda inmediata para quien lee: ``` total = base + factorial with (n - 1) # recomendado — los paréntesis hacen explícito qué es argumento return factorial with n - 1 # sin paréntesis está bien — el return cierra la expresión ``` Los paréntesis anulan la precedencia cuando el programador quiere ser explícito: ``` not (a and b) (a or b) and c ``` ## Bloques Una línea → el fin de línea la cierra. Varias líneas → `end` cierra el bloque. La indentación es opcional pero recomendada para legibilidad. ``` # una línea — sin end Direction can be north, south, east, west Background has style: BackgroundStyle, infinite: boolean if n = 0 then return 1 # varias líneas — con end Background has style: BackgroundStyle has infinite: boolean end action factorial with n: number -> number if n = 0 then return 1 return n * factorial with n - 1 end ``` ## Comentarios ``` # comentario de una línea ## comentario multilínea útil para deshabilitar bloques o explicar secciones ## ```