Módulos: import, bibliotecas y componentes
Un proyecto de HoopLang se reparte en varios archivos .hoop. Hay dos
maneras de usar un archivo desde otro:
importtrae los nombres de una biblioteca: hilos (thread), constantes (const) y formas (shape). Así se escriben una sola vez los colores de un club, la carta de una marca o las medidas comunes.placetrae un diseño entero como componente, con valores para susparam, escalado, girado y ubicado (en unhoopo en una capa de otrodesign).
Este capítulo describe las formas de import, qué se puede importar, cómo se
resuelven las rutas, los ciclos, las bibliotecas de paleta de marca y los
componentes con parámetros. Los diagnósticos citados están en
Diagnósticos.
Formas de import#
import_decl := "import" IDENT "from" STRING
| "import" "{" IDENT ( "as" IDENT )? ( "," IDENT ( "as" IDENT )? )* "}" "from" STRINGUn import es una declaración de nivel superior. Como TypeScript, cada
import dice qué trae y con qué nombre: no existe "importar todo sin
prefijo".
Para los ejemplos, la biblioteca lib/colores.hoop:
// file: lib/colores.hoop
// Biblioteca del club
thread negro = #1c1616 "Negro" { brand: "Madeira", code: "1800" }
thread amarillo = #fcd414 "Amarillo" { brand: "Madeira", code: "1124" }
const borde = 3mm
shape escudo = polygon((0mm, 0mm), (40mm, 0mm), (20mm, 50mm))Espacio de nombres: import x from "archivo"#
Trae todos los thread, const y shape de la biblioteca, cada uno
con el prefijo x.:
import club from "lib/colores.hoop"
design "N" { canvas: rect(size: (40mm, 50mm)) }
layer a { fill club.amarillo { shape: club.escudo.inset(club.borde) } }
layer b { satin club.negro { border: club.escudo, width: club.borde } }club.negroes un nombre calificado (sin paréntesis); con paréntesis,club.escudo.inset(2mm), es una llamada a método sobre la forma importada.- Los miembros de forma también funcionan sobre nombres calificados:
club.escudo.center,club.escudo.width.
Selección: import { a, b as c } from "archivo"#
Trae sólo los nombres listados, sin prefijo; as les da otro nombre en este
archivo (para evitar un choque o abreviar):
import madeira from "lib/madeira.hoop"
import { escudo, borde as marco } from "lib/colores.hoop"
thread negro = #111111 "Negro local"
design "Insignia" { canvas: rect(size: (40mm, 50mm)) }
layer fondo { fill madeira.c1172 { shape: escudo.inset(marco) } }
layer borde { satin madeira.c1800 { border: escudo, width: marco } }
layer centro { fill negro { shape: circle(center: escudo.center, r: 3mm) } }con lib/madeira.hoop:
// file: lib/madeira.hoop
thread c1800 = #1c1c1c "Black" { brand: "Madeira", code: "1800" }
thread c1172 = #d8a21b "Gold" { brand: "Madeira", code: "1172" }- La lista no puede estar vacía (
E000 import { … } needs at least one name); los nombres se separan con comas. - Un nombre que la biblioteca no tiene es
E007archivohas nox, con sugerencia si hay uno parecido:E007:lib/colores.hoophas nonegor; did you meannegro?``.
La forma eliminada: import "archivo"#
Una versión anterior traía todo sin prefijo. Hoy es un error de sintaxis que sugiere las dos formas válidas:
// error E000
import "colores.hoop"
design "D" { canvas: rect(size: (20mm, 20mm)) }e000c.hoop:1:8: error E000: importing everything mixes names: use `import club from "file"` (then club.name) or `import { name } from "file"`Las comillas de la ruta pueden ser simples o dobles; hoop fmt las deja dobles.
Qué es una biblioteca#
Una biblioteca es un archivo .hoop sin design, sin hoop y sin
layer. Puede contener thread, const, shape, param e import.
- Importar un archivo que tiene
design,hoopolayeresE007…is not a library: it has a design (only thread, const, shape and import)(oa hoop,a layer). - Se exporta: cada
thread(con su color, nombre, marca y código), cadaconsty cadashapedeclarados en la biblioteca. - No se exporta: lo que la biblioteca importa (una biblioteca no
reexporta) ni sus
param, que sí puede usar por dentro:
Archivo lib/conparam.hoop:
// file: lib/conparam.hoop
param p = 2mm
const q = p * 2import { q } from "lib/conparam.hoop" verifica; import { p } … da E007 lib/conparam.hoophas nop; did you mean q?.
Cómo se evalúa#
- Cada biblioteca se verifica sola: no ve los nombres del archivo que la importa.
- Se importan sus valores ya evaluados. Una
constde la biblioteca que usa otra sigue valiendo lo mismo aunque afuera se llame distinto (o no se importe). - Una biblioteca que se importa varias veces (por dos
importo por dos caminos) se lee y verifica una sola vez por compilación. - Si la biblioteca tiene errores, se informan en la línea del
import, con el archivo y la posición, y no se importa nada de ella:
Archivo lib/mala.hoop:
// error E001
// file: lib/mala.hoop
const ok = 1mm
const x: Angle = 3mm// error E001
import mala from "lib/mala.hoop"
design "D" { canvas: rect(size: (20mm,20mm)) }imp_lib.hoop:1:1: error E001: in `lib/mala.hoop` 2:10: error: `x` is declared Angle but its value is LengthNombres repetidos#
Todo nombre importado debe ser único en el archivo:
| Situación | Diagnóstico |
|---|---|
Un nombre local igual a uno importado (el import puede estar antes o después) | E007 negrois already imported fromlib/colores.hoop; rename one of them (as in the import) en la declaración local |
El mismo nombre traído por dos import | E007 negrois already imported fromlib/colores.hoop`` en el segundo |
| Dos declaraciones locales iguales | E007 negro is already defined |
Con un espacio de nombres no hay choques: madeira.c1800 y un thread c1800 local conviven.
Hilos importados y archivo de máquina#
Al archivo de máquina llegan los hilos declarados en el propio archivo y, de los importados, sólo los que se usan en alguna primitiva (una paleta de marca trae cientos). Su nombre, marca y código viajan al PES y a los demás formatos que los admiten.
Resolución de rutas#
Las rutas de import y de place son cadenas con / como separador y se
resuelven relativas a la carpeta del archivo principal, es decir, el
archivo que se pasa a hoop check / hoop build (o el archivo que se
compila en el playground). Esto vale también para los import y place
anidados: un archivo en sub/ que importa "colores.hoop" busca
colores.hoop junto al archivo principal, no en sub/.
Con esta estructura:
ruta.hoop
sub/insignia.hoop (import { negro } from "colores.hoop")
sub/colores.hoopArchivo ruta.hoop:
// no-check Demostración de rutas con archivos sub/insignia.hoop y sub/colores.hoop cuyo contenido completo no se muestra.
hoop "Ruta" {
frame: Brother_100x100
place "sub/insignia.hoop" at (50mm, 50mm)
}$ hoop check ruta.hoop
ruta.hoop:3:3: error E007: in `sub/insignia.hoop` 1:1: error: cannot read `colores.hoop`: No such file or directory (os error 2)
ruta.hoop:3:3: error E003: in `sub/insignia.hoop` 3:11: error: undeclared thread `negro` (declare it with thread)
$ hoop check sub/insignia.hoop
sub/insignia.hoop: ok — 1 threads, 1 layers, 1 objectsDetalles:
- En la herramienta de línea de comandos, la ruta se une a la carpeta del
archivo principal tal cual (las rutas absolutas y
..funcionan como en el sistema de archivos). - En el playground (y en la API WASM), los archivos del proyecto se nombran
por su ruta dentro del proyecto; la ruta se une a la carpeta del archivo
principal y se resuelven
.y..(por ejemplo, desdegaleria/insignia.hoop,"../bibliotecas/janome.hoop"esbibliotecas/janome.hoop). Un archivo que no está dacannot read…: not found in the project (…). - Un archivo que no se puede leer es
E007 cannot read…: <motivo>en la línea delimporto delplace. - Las funciones de la biblioteca
hooplangno hacen E/S: quien llama entrega un cargador (ruta → texto). Sin cargador (hooplang::check), unimportesE007 import needs file access (compile with a file loader).
Ciclos#
Un ciclo de import es error, con la cadena completa, informado en cada
nivel (cada archivo lo informa en su import):
Archivo lib/ca.hoop:
// error E007
// file: lib/ca.hoop
import { b } from "lib/cb.hoop"
const a = 1mmArchivo lib/cb.hoop:
// error E007
// file: lib/cb.hoop
import { a } from "lib/ca.hoop"
const b = 1mm// error E007
design "D" { canvas: rect(size: (20mm,20mm)) }
import ca from "lib/ca.hoop"imp_lib.hoop:2:1: error E007: in `lib/ca.hoop` 1:1: error: in `lib/cb.hoop` 1:1: error: import cycle: lib/ca.hoop → lib/cb.hoop → lib/ca.hoopLo mismo con place: un diseño que se coloca a sí mismo, directa o
indirectamente, es E007 place cycle: …, informado tal cual (la cadena ya
nombra los archivos) en el place de más afuera:
Archivo ciclo.hoop:
// error E007
// file: ciclo.hoop
design "Ciclo" { canvas: rect(size: (40mm, 40mm)) }
layer a { place "ciclo.hoop" at (20mm, 20mm) }ciclo.hoop:2:11: error E007: place cycle: ciclo.hoop → ciclo.hoopBibliotecas de paleta de marca#
Una carta de hilos de una marca es una biblioteca con un thread por color,
con brand y code:
thread c1800 = #1c1c1c "Black" { brand: "Madeira", code: "1800" }El repositorio incluye docs/lenguaje/bibliotecas/brother.hoop (paleta PEC,
sin códigos) y docs/lenguaje/bibliotecas/janome.hoop (con su código
Janome); sus RGB son aproximados y su cabecera lo dice. Se usan con un
espacio de nombres o seleccionando:
import { c002 as negro } from "../bibliotecas/janome.hoop"(así empieza docs/lenguaje/galeria/polera.hoop).
La herramienta palette#
palette genera bibliotecas ya formateadas:
cargo run -q --release --bin palette -- csv carta.csv Madeira > madeira.hoop
cargo run -q --release --bin palette -- brother > brother.hoop
cargo run -q --release --bin palette -- janome > janome.hoopcsv <archivo.csv> <Marca>lee filascódigo,nombre,color, con el color como#rrggbborrggbb, con o sin cabecera; los campos pueden ir entre comillas (para nombres con comas). Una fila con menos de tres campos o un color inválido detiene la herramienta conline N: …y código de salida- El nombre de cada hilo sale del código: minúsculas,
_entre palabras y, si empieza con un dígito,cdelante (1800→c1800). Los nombres repetidos se omiten (queda el primero). - La cabecera dice la marca, la cantidad de colores, la fuente de los datos y cómo importarla:
// Madeira thread library (2 colors).
// Source: carta.csv
// Usage: import madeira from "madeira.hoop" (then madeira.<name>)Componentes: param y place con argumentos#
Un design puede declarar parámetros: valores por defecto que quien lo
coloca puede cambiar.
param_decl := "param" IDENT ( ":" TIPO )? "=" exprArchivo parche.hoop:
// file: parche.hoop
param nombre = "ANA"
param ancho: Length = 50mm
design "Parche" { canvas: rect(size: (ancho, 20mm), radius: 4mm) }
thread fondo = #f2f2f2 "Fondo"
thread borde = #1f3a8a "Azul"
layer base { fill fondo { shape: canvas } }
layer texto { text borde { value: nombre, height: 8mm, at: canvas.center + (0mm, 3mm), align: center } }
layer marco { satin borde { border: canvas, width: 2mm } }- El tipo es el declarado o, si no se declara, el del valor por defecto. Un
valor por defecto de otro tipo que el declarado es
E001xis declared T but its default is U. - Un
parames un nombre más del archivo (no puede repetir otro nombre) y se usa como unaconst. Compilado solo, el diseño usa los valores por defecto.
Quien coloca el diseño da valores con argumentos con nombre entre
paréntesis, pegados a la ruta (hoop fmt los escribe así; separados por un
espacio también vale):
hoop "Dos parches" {
frame: Brother_200x200
fabric: Twill
margin: 10mm
place "parche.hoop" at (100mm, 60mm)
place "parche.hoop"(nombre: "LUIS", ancho: 70mm) at (100mm, 120mm) anchor: top_center
}Los argumentos se evalúan en el archivo que coloca (pueden usar sus nombres
y las variables de un for) y el diseño se verifica y compila con esos
valores: cada place con argumentos distintos es un diseño distinto.
Validación de argumentos#
// error E001 E007
hoop "H" {
frame: Brother_200x200
place "parche.hoop"(nombr: "X") at (100mm, 50mm)
place "parche.hoop"(nombre: 3mm) at (100mm, 100mm)
place "cuadro.hoop"(nombre: "X") at (100mm, 150mm)
}h_noparam.hoop:3:30: error E007: `parche.hoop` has no param `nombr`; did you mean `nombre`?
h_noparam.hoop:4:3: error E001: in `parche.hoop` 1:1: error: `nombre` is String but it was given Length
h_noparam.hoop:5:31: error E007: `cuadro.hoop` has no params- Un argumento que no es
paramdel diseño:E007, en la posición del valor del argumento, con sugerencia, con la lista de parámetros (has no paramx(a, b)) o diciendo que no tiene ninguno. - Un argumento de otro tipo:
E001informado dentro del diseño, en la línea de suparam, y reportado en elplace; el diseño sigue con el valor por defecto para no producir errores en cascada. - Un argumento sin nombre:
E001 design arguments are named: place "x.hoop"(nombre: "ANA"). - Si un mismo nombre se da dos veces, vale el último (no hay diagnóstico).
Véase también#
- Bastidor:
hoop,placey sus modificadores. - Declaraciones:
thread,const,shape,param. - Diagnósticos: formato de los errores anidados.