Presentamos Achronyme — un lenguaje para pruebas zero-knowledge. Lee el anuncio

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

ErrorCausa
ModuleNotFoundLa ruta del archivo no resuelve a un archivo existente
CircularImportDos o más módulos se importan entre sí
ModuleLoadErrorEl archivo fue encontrado pero contiene errores de parseo
DuplicateModuleAliasDos archivos diferentes importados con el mismo alias
Nombre no exportadoimport { x } donde x no es exportado por el módulo (con sugerencia “did you mean?”)
Export duplicadoEl mismo nombre se exporta más de una vez (inline + lista, o listado dos veces)
Conflicto de importUn nombre importado selectivamente entra en conflicto con un global existente o un import previo de otro módulo
Export list indefinidoexport { x } donde x no está definido en el módulo

Advertencias

CódigoCausa
W005Un nombre importado selectivamente nunca se usa (prefija con _ para suprimir)

Restricciones

  • import y export solo están permitidos a nivel superior (no dentro de funciones o bloques)
  • import, export y as son palabras reservadas
  • from no es una palabra reservada — se reconoce contextualmente solo después de import { ... }, 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

SintaxisDescripción
export fn name() { ... }Exportar una función (inline)
export let X = valueExportar una constante (inline)
export { a, b, c }Exportar múltiples nombres (lista)
import "./file.ach" as aliasImport de namespace
import { a, b } from "./file.ach"Import selectivo
alias.nameAcceder a un binding de namespace
Navigation