REPL – Interfaz de Línea de Comandos Interactiva

Archivo: src/repl.rs315 líneas

¿Por qué existe?

El REPL (Read-Eval-Print Loop) permite a los usuarios escribir y ejecutar fragmentos de código Forja en tiempo real, facilitando pruebas rápidas, depuración y exploración del lenguaje sin necesidad de crear archivos fuente. Es la herramienta ideal para aprendizaje, experimentación y scripting rápido.

Estructura principal

REPL

CampoTipoDescripción
vm_modeStringModo de VM a utilizar: "fast" (ForjaFast con NaN tagging, default) o "jit"
bufferStringBuffer de entrada acumulada para expresiones multi-línea
show_bytecodeboolSi es cierto, muestra el bytecode generado antes de ejecutar
source_acumuladoStringCódigo fuente completo acumulado desde el inicio de la sesión
rlEditor<()>Editor de línea de rustyline con historial y edición
vm_fastOption<ForjaFast>Instancia de la VM rápida (modo fast), contenida en Option

Métodos públicos

REPL::new()

FirmaDescripción
pub fn new(modo: &str) -> Self Crea una nueva instancia del REPL. Inicializa rustyline con historial, configura el modo de VM según el string recibido ("fast", "jit", etc.), y prepara los buffers de código fuente.

REPL::iniciar()

FirmaDescripción
pub fn iniciar(&mut self) Método principal (~180 líneas). Bucle principal de lectura-ejecución:
  1. Muestra el prompt >>> y lee una línea con rustyline
  2. Agrega la línea al buffer de entrada acumulada
  3. Verifica si la entrada está completa (chequear_completud())
  4. Si está completa, pasa por el pipeline completo:
    • Lexer: tokeniza source_acumulado + buffer
    • Parser: construye el AST (Programa)
    • Generación de bytecode: compila a opcodes
    • Ejecución: corre en la VM seleccionada (ForjaFast o clásica)
    • Muestra el resultado
  5. Si está incompleta, espera más líneas
  6. Maneja comandos especiales (ver abajo)

Comandos del REPL

ComandoDescripción
:salir / :quitSale del REPL
:reset / :limpiarReinicia el estado de la VM (limpia variables, funciones, heap)
:reloadRecarga todos los módulos (re-parsea y re-compila desde las fuentes originales)
:reload moduloRecarga un módulo específico por su nombre
:variablesMuestra las variables definidas actualmente (solo modo fast)
:bytecodeAlterna la visualización del bytecode generado

Métodos privados

REPL::compilar_y_ejecutar()

FirmaDescripción
fn compilar_y_ejecutar(&mut self, source: &str) -> Result<String, String> Pipeline completo de compilación + ejecución (~44 líneas):
  1. Tokeniza el código fuente acumulado + la nueva línea
  2. Parsea los tokens a AST
  3. Genera bytecode a partir del AST
  4. Si show_bytecode está activo, muestra los opcodes generados
  5. Si el modo es "fast" (o cualquier otro): carga el bytecode en ForjaFast y ejecuta con ejecutar()
  6. Retorna el resultado formateado como String
En caso de error (léxico, sintáctico, semántico o de runtime), retorna el mensaje de error.

REPL::chequear_completud()

FirmaDescripción
fn chequear_completud(&self) -> bool Verifica si el buffer acumulado está completo contando llaves { y }. Si están balanceadas (misma cantidad), la entrada está completa y se ejecuta. Si hay más llaves abiertas que cerradas, espera más líneas de entrada.

Pipeline del REPL

┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────────┐   ┌─────────────┐
│ Entrada  │──▶│ Lexer    │──▶│ Parser   │──▶│ Bytecode Gen │──▶│ VM (fast/   │
│ usuario  │   │ tokens   │   │ AST      │   │ opcodes       │   │  jit)        │
└──────────┘   └──────────┘   └──────────┘   └──────────────┘   └──────┬──────┘
                                                                       │
                                                                       ▼
                                                                ┌──────────────┐
                                                                │  Resultado /  │
                                                                │  Error       │
                                                                └──────────────┘

Hot-reload de módulos

El REPL soporta recarga en caliente de módulos mediante :reload. Cuando se recarga un módulo, el sistema:

  1. Resuelve el módulo por su nombre a través del ModuleResolver
  2. Obtiene el bytecode actualizado con generar_para_modulo()
  3. Llama a hot_swap_module() en ForjaFast para reemplazar el bytecode en caliente
  4. Las funciones actualizadas se reemplazan sin detener la ejecución

Relación con el resto del compilador