Saltar al contenido
Vacav0.1.0GitHub

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:

  1. Abre la paleta de comandos de Zed.
  2. Ejecuta zed: install dev extension.
  3. Selecciona la carpeta editor/.
  4. Abre un archivo .vaca y 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 test ejecuta 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.py lanza 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 e importar usan el intérprete de árbol.
  • No hay comprobación estática de tipos ni recolector de basura.
  • No hay formateador (vaca fmt), LSP ni vaca test.
  • Sin ACME: los certificados se renuevan fuera de Vaca.
  • No existe super para llamar al método del padre.
  • La concurrencia usa hilos del sistema, no un event loop.
  • Los ciclos de referencias con Arc no se liberan.

Consulta la referencia rápida para la lista completa.