Lenguaje
Módulos (use / export)
Dividí el código en archivos. export hace público un task/type/let/enum/routes; todo lo demás queda privado. Un módulo es un map de sus exports, importado bajo un alias.
El módulo — mathlib.syn:
export task square(n)
give n * n
export let VERSION be "1.0"
task private_helper() -- sin `export` → no visible para quien importa
give 42
El entry que lo importa:
-- Doc example: modules (use / export). Imports ./mathlib.syn under the alias `math`.
intent: "doc example: modules"
use "./mathlib.syn" as math
print("math.square(5) = " + text(math.square(5)) + ", VERSION " + math.VERSION)
test "import an exported task and let (private_helper is NOT visible)"
assert_eq(math.square(5), 25)
assert_eq(math.VERSION, "1.0")Reglas§
use "./path.syn" as alias— los paths son relativos al archivo que importa; solo.syn, sin URLs/FFI, y el traversal (../) está bloqueado.- Las llamadas entre archivos necesitan el prefijo del alias:
math.square(5),math.VERSION. - Los imports están cacheados (se cargan una vez), son transitivos y con chequeo de ciclos.
- Un módulo no puede tener
requireniservetop-level — eso va en el archivo entry. Unrequirepor-task dentro de una task del módulo sí está bien. synsema check entry.synresuelve y parsea el grafo de imports completo (paths rotos, ciclos,serve/requireprohibidos en módulos: todo falla el check).
export routes — grupos de rutas que un serve puede montar (mount)§
Un sitio grande no tiene que ser un solo bloque serve. Un módulo exporta un grupo de rutas; el entry lo monta (los cuerpos llaman a los helpers privados del módulo por nombre simple):
-- shop.syn
task fmt(n) -- privado
give "$" + text(n)
export routes shop
route "GET /shop"
give html("<h1>" + fmt(99) + "</h1>")
route "POST /shop/buy"
expect body {item: text}
give created(json of request)
-- app.syn
use "./shop.syn" as shop
serve on 8080
mount shop.shop -- o: mount shop.shop at "/store"
Los grupos aceptan entradas route con su propio rate_limit y timeout (engine v0.6.19+: una ruta montada tiene su propia zona de rate limit, y un prefijo de mount es otra zona — antes de v0.6.19 los dos se rechazaban dentro de un grupo); las rutas stream y socket siguen yendo en el bloque serve, y synsema check lo dice con el mismo mensaje que daría serve al arrancar. Un requires auth montado sigue exigiendo auth with en el bloque serve, validado al construir el serve. Mirá Servidor HTTP y Construí un sitio web.