Transpilador a Rust
Archivo: src/transpiler.rs
Forja es un lenguaje autocontenido que ejecuta a través de su propia máquina virtual; sin embargo, también proporciona la capacidad de **transpilar a código fuente de Rust** compilable. Esta característica permite generar ejecutables nativos de alto rendimiento delegando la compilación final al compilador de Rust (rustc) mediante la optimización de LLVM.
Estructura del Transpiler
Estructura Transpiler
pub struct Transpiler {
output: String,
indent_level: usize,
temp_counter: usize,
pub saltar_main: bool,
clases: HashMap<String, ClaseInfo>,
declaraciones_globales: Vec<Declaracion>,
funciones_externas: Vec<String>,
} output: Búfer de string donde se genera el código Rust.indent_level: Controla la profundidad de llaves para el sangrado automático del archivo exportado.clases: Mapa de metadatos recopilados sobre las clases del usuario para estructurar los campos y métodos en la traducción final.declaraciones_globales: Copia del AST global para realizar análisis estático de mutabilidad local.funciones_externas: Nombres de firmas FFI para agruparlas en bloques nativosextern "C".
Desglose de Funciones de Transpiler
1. Funciones Auxiliares del Módulo
es_variable_mutable(nombre: &str, declaraciones: &[Declaracion], ...) -> bool- ¿Por qué?: Rust exige que las variables modificables se declaren explícitamente con
let mut, mientras que en Forja no se requiere esta distinción estricta en la declaración original de la variable. - ¿Cómo?: Realiza un análisis estático recursivo sobre las declaraciones buscando asignaciones directas (
Asignacion) o indexadas al identificadornombre. Detiene el escaneo y no cruza las fronteras de definiciones de funciones locales (ya que cada una define su propio contexto aislado de variables). - ¿Para qué?: Decidir si generar
let muto simplementeletal transpilar variables.
- ¿Por qué?: Rust exige que las variables modificables se declaren explícitamente con
necesita_parentesis(expr: &Expresion, op_padre: &Operador) -> bool- ¿Por qué?: Preservar la precedencia aritmética correcta en Rust.
- ¿Cómo?: Mapea y compara la precedencia del operador del nodo hijo frente al operador padre. Si el hijo tiene menor precedencia, retorna
truepara envolver la expresión con paréntesis.
2. Métodos del Transpiler
pub fn new() -> Self: Constructor principal.pub fn transpilar(&mut self, programa: &Programa) -> Result<String, Vec<ErrorForja>>- ¿Por qué?: Ejecutar el pipeline de transpilación completo de un AST.
- ¿Cómo?:
- Guarda las declaraciones globales y ejecuta
recolectar_clases(). - Inyecta comentarios de cabecera y cabeceras de importación opcionales (ej:
std::threadystd::sync::mpscsi detecta el uso de concurrencia). - Genera bloques
extern "C"para firmas de FFI nulas. - Transpila clases del usuario convirtiéndolas en estructuras (
struct) con sus métodos encapsulados en bloquesimpl. - Recorre funciones globales y genera el
fn main()con el punto de entrada.
- Guarda las declaraciones globales y ejecuta
fn tipo_a_rust(&self, tipo: &Tipo) -> String- ¿Por qué?: Convertir las representaciones de tipo de Forja a sus homólogos en Rust.
- ¿Cómo?: Mapea
Enteroai64,Decimalaf64,TextoaString,Booleanoabool, yNuloa la tupla vacía unitaria(). Mapea arreglos y tipos opcionales aVecyOptionrespectivamente.
fn transpilar_declaracion(&mut self, decl: &Declaracion)- ¿Por qué?: Traducir una declaración individual del AST a sintaxis Rust.
- ¿Cómo?: Mapea las sentencias en sus equivalentes:
- Variables: Llama a
es_variable_mutablepara emitirlet mutolet. - Condicionales (
Si): Generaif { ... } else { ... }. - Bucles (
Mientras/Para): Escribe bloqueswhileoforclásicos en Rust. - Bucle
Repetir: Traduce a un iterador de rango en Rust (ej:for _ in 0..cantidad { ... }).
- Variables: Llama a
fn transpilar_expresion(&mut self, expr: &Expresion)- ¿Por qué?: Escribir una expresión de Forja como una expresión sintácticamente válida en Rust.
- ¿Cómo?: Traduce llamadas a FFI nativas, accesos a miembros, instanciaciones de clases (
nuevo Clase(...)mapea a una función constructora de Rust), y operaciones lógicas o aritméticas.
fn emit(&mut self, s: &str)yfn emit_line(&mut self, s: &str)- ¿Por qué?: Helpers para escribir en el búfer de salida formateado con sangrado y saltos de línea automáticos.