Herramientas
CLI
vaca # ejecuta el módulo y llama a principal()
vaca <archivo.vaca> # ejecuta un programa o un bundle
vaca <directorio> # ejecuta el módulo de ese directorio
vaca run [archivo] # igual, con argumentos extra
vaca repl # consola interactiva
vaca tokens <archivo> # volcado de tokens
vaca ast <archivo> # volcado del AST
vaca init <modulo> # crea vaca.mod e iniciar.vaca
vaca construir # empaqueta en .vaca/dist/<nombre>.vaca
vaca agregar <ruta>[@v] # añade e instala una dependencia
vaca instalar # instala las dependencias
vaca actualizar # re-resuelve ignorando el lock
vaca listar # muestra módulo, entrada y hashes
vaca limpiar # borra .vaca/paquetes y vaca.lock
vaca --version # versión
vaca --ayuda # ayuda + banner cowsay
Módulos y bundles
Un módulo declara su nombre, entrada y dependencias en vaca.mod:
vaca init ejemplo.com/mi-api
vaca # ejecuta iniciar.vaca y principal()
vaca construir # genera .vaca/dist/mi-api.vaca
El bundle es un único archivo con el código, vaca.mod, vaca.lock y las
dependencias vendorizadas. Incluye un SHA-256 al final que se verifica al
arrancar; si cambia un byte, la ejecución falla.
vaca mi-api.vaca
Detalles en Módulos y paquetes.
La versión incluye metadatos del último commit: 0.1.0+4.0b78e95 significa
versión semántica 0.1.0, 4 commits y el hash corto 0b78e95. Si el binario
se compila sin .git, muestra solo la versión de Cargo.toml.
Los argumentos que van después del archivo quedan disponibles en
sistema.argumentos():
vaca app.vaca --puerto 8080 --debug
importar sistema
imprimir(sistema.argumentos()) # ["--puerto", "8080", "--debug"]
REPL
vaca repl
El REPL acepta bloques de varias líneas y espera hasta que las llaves estén balanceadas:
vaca> fn doble(n) { retornar n * 2 }
vaca> doble(21)
42
vaca> frutas = ["pera", "uva"]
vaca> frutas.agregar("higo")
vaca> frutas
["pera", "uva", "higo"]
vaca> salir
Las variables y funciones definidas en el REPL persisten entre líneas.
Variables no usadas
Antes de ejecutar, Vaca analiza el programa. Una variable local declarada y nunca leída es un error de compilación:
fn calcular() {
resultado = 42
retornar 0
}
error de compilación: variables declaradas pero nunca usadas: variable 'resultado' (función 'calcular')
Reglas:
- Se revisan las variables locales de funciones, bloques, bucles y
atrapar. - Los parámetros están exentos.
- Las variables globales están exentas.
- Una variable solo escrita (nunca leída) cuenta como no usada.
- Los nombres que empiezan por
_están exentos. - El nombre
_se usa para descartar valores.
para _ = 1 hasta 3 {
imprimir("tres veces")
}
fn procesar(_ignorado, dato) {
retornar dato * 2
}
Tokens y AST
vaca tokens ejemplos/hola.vaca
vaca ast ejemplos/hola.vaca
tokens imprime línea, columna y tipo de cada token. ast imprime el árbol de
sintaxis con Debug. Son útiles para depurar el parser o entender cómo se
interpreta una construcción.
Editor de Zed
La extensión vive en editor/ e incluye:
- Resaltado de sintaxis con una gramática Tree-sitter propia.
- Emparejamiento de llaves.
- Indentación y plegado.
- Outline de funciones, clases y constantes.
- Text objects para funciones y clases.
- Comentarios
#,//y/* ... */.
Instalación:
- Abre la paleta de comandos de Zed.
- Ejecuta
zed: install dev extension. - Selecciona la carpeta
editor/. - Abre un archivo
.vacay elige el lenguaje Vaca.
La gramática está en editor/tree-sitter-vaca/. Solo necesitas Bun si
quieres regenerarla:
cd editor/tree-sitter-vaca
bun install
bun run generate
bun run test
Después de modificarla, ejecuta editor/actualizar.sh.
Empaquetado
Tarball con instalador
packaging/empaquetar.sh
# dist/vaca-0.1.0-x86_64-unknown-linux-gnu.tar.gz
El paquete incluye el binario, install.sh, la licencia y los ejemplos.
Binario estático
rustup target add x86_64-unknown-linux-musl
packaging/empaquetar.sh --target x86_64-unknown-linux-musl
Docker
docker build -f packaging/Dockerfile -t vaca:0.1.0 .
docker run --rm -p 8080:8080 vaca:0.1.0
systemd
packaging/vaca.service es una unidad de ejemplo. Ajusta ExecStart,
WorkingDirectory y User.
Instalación global
cargo install --path .
vaca --version
Pruebas
cargo test
python3 scripts/probar_servidor.py
python3 scripts/probar_api.py
python3 scripts/probar_concurrencia.py
cargo testejecuta las pruebas del lenguaje, la integración y todos los ejemplos que no son servidores.- Los scripts de Python levantan servidores reales, hacen peticiones y verifican las respuestas.
probar_concurrencia.pylanza 50 peticiones lentas simultáneas y comprueba el paralelismo y los contadores atómicos.
VM de bytecode
Las funciones se compilan a bytecode la primera vez que se llaman y se ejecutan en una VM de pila. Las variables pasan a ser posiciones fijas del marco, así que dentro de un bucle no se buscan nombres ni se recorren ámbitos.
vaca estres.vaca # ejecuta con la VM de bytecode
VACA_SIN_VM=1 vaca estres.vaca # fuerza solo el intérprete de árbol
Sustituye estres.vaca por tu programa. VACA_SIN_VM sirve para comparar el
rendimiento de ambos motores en la misma máquina y para aislar fallos: si un
programa funciona sin VM y falla con ella, el problema está en el compilador de
bytecode.
La VM cubre variables, bucles, condicionales, funciones, recursión, parámetros
por defecto, listas, diccionarios, índices, miembros, interpolación, nuevo y
lanzar. Se ejecutan con el intérprete de árbol las funciones que usan
intentar/atrapar o importar, las que crean cierres en su interior, las que
declaran funciones o clases anidadas y las funciones async.
Diagnóstico de errores
Errores de compilación
| Mensaje | Causa | Solución |
|---|---|---|
variables declaradas pero nunca usadas |
Variable local sin leer | Úsala, elimínala o renómbrala con _ |
las constantes ... MAYÚSCULAS |
Nombre de constante con minúsculas | Escríbelo todo en MAYÚSCULAS |
error de sintaxis en la línea N, columna M |
Llave, paréntesis o token inesperado | Revisa la línea indicada |
error léxico en la línea N, columna M |
Texto sin cerrar, carácter inválido | Revisa comillas y escapes |
Errores de ejecución
| Mensaje | Causa |
|---|---|
la variable 'x' no está definida |
Nombre mal escrito o fuera de ámbito |
índice 10 fuera de rango (longitud 3) |
Índice inválido en lista o texto |
la función 'f' espera 2 argumento(s), pero recibió 1 |
Aridad incorrecta |
división entre cero / módulo entre cero |
Operación inválida |
desbordamiento de pila: demasiada recursión |
Falta un caso base |
'romper' fuera de un bucle |
romper mal ubicado |
el constructor 'iniciar' no puede ser async |
iniciar declarado async |
no se pudo iniciar el servidor en '...' |
Puerto ocupado o permisos |
invalid peer certificate |
Certificado no confiable o nombre incorrecto |
Los errores léxicos y sintácticos indican línea y columna. Los de ejecución no
incluyen la posición: usa imprimir para rastrear el estado.
Depurar un servidor
fn manejador(peticion) {
imprimir(a"{peticion.metodo} {peticion.ruta} desde {peticion.ip}")
intentar {
# lógica
} atrapar error {
imprimir(a"Error en {peticion.ruta}: {error}")
retornar {"estado": 500, "cuerpo": {"error": "interno"}}
}
}
No imprimas secretos ni cuerpos completos en producción. Para carga, usa
/metricas con contadores atómicos en lugar de logs por petición.
Límites conocidos
- La VM cubre funciones y bucles;
intentar/atrapar, cierres creados dentro de una función, funciones o clases anidadas eimportarusan el intérprete de árbol. - No hay comprobación estática de tipos ni recolector de basura.
- No hay formateador (
vaca fmt), LSP nivaca test. - Sin ACME: los certificados se renuevan fuera de Vaca.
- No existe
superpara llamar al método del padre. - La concurrencia usa hilos del sistema, no un event loop.
- Los ciclos de referencias con
Arcno se liberan.
Consulta la referencia rápida para la lista completa.