Módulos
Dividir programas entre archivos con import y export.
Achronyme permite dividir código entre múltiples archivos .ach usando módulos. Exporta declaraciones para hacerlas disponibles e importa módulos por namespace o por nombre.
Exportar Declaraciones
Exports Inline
Usa export antes de fn o let para hacer una declaración disponible a otros archivos.
// math.ach
export fn add(a, b) { a + b }
export fn mul(a, b) { a * b }
export let PI = 3
Solo fn y let pueden exportarse. Variables mutables (mut), declaraciones public y witness no pueden exportarse.
// Estos son errores:
export mut x = 5 // ✗ no se puede exportar mut
export public y // ✗ no se puede exportar public
Listas de Export
También puedes agrupar los exports al final del archivo usando export { ... }:
// math.ach
fn add(a, b) { a + b }
fn mul(a, b) { a * b }
let PI = 3
export { add, mul, PI }
Esto es equivalente a marcar cada declaración con export individualmente. Puedes mezclar ambos estilos en el mismo archivo. Exportar el mismo nombre dos veces (inline + lista, o listado dos veces) es un error.
Las declaraciones sin export son privadas al archivo. Pueden ser usadas por funciones exportadas internamente pero no son accesibles desde afuera.
// helpers.ach
fn internal_helper(x) { x * x } // privada
export fn square(x) {
internal_helper(x) // funciona dentro del archivo
}
Importar un Módulo
Import de Namespace
Usa import "ruta" as alias para cargar un módulo. El alias es obligatorio y se convierte en el namespace para acceder a las exportaciones del módulo.
// main.ach
import "./math.ach" as math
print(math.add(1, 2)) // 3
print(math.PI) // 3
Accede a los valores exportados usando notación de punto: alias.nombre.
Import Selectivo
Usa import { nombre1, nombre2 } from "ruta" para importar nombres específicos directamente al ámbito, sin prefijo de namespace:
import { add, PI } from "./math.ach"
print(add(1, 2)) // 3 — sin prefijo
print(PI) // 3
Los imports selectivos copian el valor al momento de importar (semántica de snapshot). Los cambios en los globals del módulo original después de la importación no se reflejan.
Si un nombre solicitado no es exportado por el módulo, el compilador sugiere la coincidencia más cercana:
error: module "math.ach" does not export `ad`. Did you mean `add`?
Puedes combinar ambos estilos para el mismo módulo:
import { add } from "./math.ach"
import "./math.ach" as math
print(add(1, 2)) // selectivo — sin prefijo
print(math.mul(3, 4)) // namespace — con prefijo
Rutas de Módulos
Las rutas son relativas al archivo que importa y deben incluir la extensión .ach.
import "./utils.ach" as utils // mismo directorio
import "../lib/hash.ach" as hash // directorio padre
import "./crypto/poseidon.ach" as pos // subdirectorio
Las rutas absolutas no están soportadas. Todas las importaciones usan rutas relativas.
Importaciones Transitivas
Los módulos pueden importar otros módulos. La cadena se resuelve automáticamente.
// a.ach
export fn fa() { 1 }
// b.ach
import "./a.ach" as a
export fn fb() { a.fa() + 1 }
// c.ach
import "./b.ach" as b
print(b.fb()) // 2
Importaciones Circulares
Las dependencias circulares se detectan y producen un error.
// x.ach
import "./y.ach" as y // error: CircularImport
// y.ach
import "./x.ach" as x
Módulos en Circuitos
Las importaciones funcionan con ach circuit de la misma manera que con ach run. Las funciones importadas se inlinean en cada punto de llamada.
// hash_lib.ach
export fn my_hash(a, b) { poseidon(a, b) }
// circuit.ach
import "./hash_lib.ach" as h
circuit hash_check(out: Public, a: Witness, b: Witness) {
assert_eq(h.my_hash(a, b), out)
}
Errores
| Error | Causa |
|---|---|
ModuleNotFound | La ruta del archivo no resuelve a un archivo existente |
CircularImport | Dos o más módulos se importan entre sí |
ModuleLoadError | El archivo fue encontrado pero contiene errores de parseo |
DuplicateModuleAlias | Dos archivos diferentes importados con el mismo alias |
| Nombre no exportado | import { x } donde x no es exportado por el módulo (con sugerencia “did you mean?”) |
| Export duplicado | El mismo nombre se exporta más de una vez (inline + lista, o listado dos veces) |
| Conflicto de import | Un nombre importado selectivamente entra en conflicto con un global existente o un import previo de otro módulo |
| Export list indefinido | export { x } donde x no está definido en el módulo |
Advertencias
| Código | Causa |
|---|---|
| W005 | Un nombre importado selectivamente nunca se usa (prefija con _ para suprimir) |
Restricciones
importyexportsolo están permitidos a nivel superior (no dentro de funciones o bloques)import,exportyasson palabras reservadasfromno es una palabra reservada — se reconoce contextualmente solo después deimport { ... }, por lo que puede usarse como nombre de variable en otros contextos- Los imports selectivos usan semántica de snapshot (el valor se copia al momento de importar)
- Las re-exportaciones (
export import) no están soportadas - Importar el mismo archivo con dos alias diferentes está permitido (el archivo se parsea una sola vez)
Referencia Rápida
| Sintaxis | Descripción |
|---|---|
export fn name() { ... } | Exportar una función (inline) |
export let X = value | Exportar una constante (inline) |
export { a, b, c } | Exportar múltiples nombres (lista) |
import "./file.ach" as alias | Import de namespace |
import { a, b } from "./file.ach" | Import selectivo |
alias.name | Acceder a un binding de namespace |