Formatter – Formateador de Código Forja
Archivo: src/formatter.rs — 795 líneas
¿Por qué existe?
El formatter recorre el AST de Forja y produce código fuente formateado de manera
consistente: indentación uniforme (4 espacios), espaciado alrededor de operadores,
saltos de línea predecibles y estilo homogéneo para declaraciones, expresiones,
clases, funciones, rasgos, enums, contratos y patrones de matching. Esto garantiza
que todo el código Forja se vea igual independientemente de quién lo escriba,
facilita las revisiones de código (diffs más limpios) y elimina discusiones de estilo.
Estructura principal
Formatter
| Campo | Tipo | Descripción |
output | String | Buffer de salida donde se acumula el código formateado |
indent | usize | Nivel de indentación actual (cada nivel = 4 espacios) |
Métodos públicos
Formatter::new()
| Firma | Descripción |
pub fn new() -> Self | Crea un nuevo formatter vacío con indentación 0 y output vacío |
Formatter::formatear()
| Firma | Descripción |
pub fn formatear(&mut self, programa: &Programa) -> String |
Punto de entrada principal. Recorre todas las declaraciones del programa llamando
a formatear_declaracion() para cada una y retorna el texto formateado completo.
|
Métodos privados de formato por tipo de AST
Conversión de tipos
| Firma | Descripción |
fn tipo_a_string(&self, t: &Tipo) -> String |
Convierte un Tipo a su representación textual Forja.
Maneja las 12 variantes: Entero, Decimal, Texto, Booleano, Nulo, Exacto,
Clase(nombre), Arreglo<T>, Funcion<params; retorno>,
Resultado<Ok, Err>, Opcion<T>, RasgoObjeto(nombre), Parametro(nombre).
|
Parámetros y genéricos
| Firma | Descripción |
fn formatear_parametro(&self, p: &Parametro) -> String |
Formatea un parámetro incluyendo prefijos prestado/mut
y tipo opcional: prestado mut nombre: Tipo.
|
fn formatear_parametros_tipo(&self, params: &[ParametroTipo]) -> String |
Formatea parámetros de tipo genérico: <T, U>.
Retorna cadena vacía si no hay parámetros.
|
fn formatear_atributo(&self, attr: &Atributo) -> String |
Formatea un atributo/anotación: @nombre o @nombre(args).
|
fn formatear_variante(&self, v: &Variante) -> String |
Formatea una variante de enum: Nombre o Nombre(Tipo1, Tipo2).
|
Patrones (matching)
| Firma | Descripción |
fn patron_a_string(&mut self, patron: &Patron) -> String |
Convierte un Patron a texto. Cubre las 4 variantes:
Variable(nombre) → nombre Literal(expr) → expresión literal Constructor(nombre, subpatrones) → Nombre(sub1, sub2) Ignorar → _ |
Declaraciones (20 variantes)
| Firma | Descripción |
fn formatear_declaracion(&mut self, decl: &Declaracion) | Método central (~374 líneas). Recibe cualquier variante de Declaracion
y la formatea. Maneja un match exhaustivo de 20 variantes:
- Variable:
variable nombre = expr o constante nombre: Tipo = expr - Asignacion:
nombre = expr - AsignacionMiembro:
objeto.miembro = valor - AsignacionIndex:
nombre[indice] = valor - Si:
si (cond) { ... } con sino { ... } opcional - Mientras:
mientras (cond) { ... } - Para:
para (init; cond; inc) { ... } - Repetir:
repetir (cant) { ... } - Cuando:
cuando (cond) { ... } - Funcion: formato completo con doc comments, atributos, genéricos, parámetros, retorno, pre/postcondiciones, cuerpo
- LlamadaFuncion:
nombre(args) - AccesoMiembro:
obj.miembro - Retornar:
retornar expr - Romper / Continuar
- Importar:
importar ruta (con comillas si es ruta absoluta) - Enum:
tipo Nombre = Var1 | Var2(Tipo) - AsignacionMultiple:
variable a, b = expr - Rasgo:
rasgo Nombre { funcion metodo(...) -> Tipo ... } - Implementacion:
implementa Rasgo para Clase { ... } - Clase: formato completo con atributos, genéricos, invariantes, campos, métodos
- Expresion(expr): expresión usada como statement
|
Métodos específicos para funciones, clases y rasgos
| Firma | Descripción |
fn formatear_metodo_struct(&mut self, metodo: &Metodo) |
Formatea un método completo dentro de una clase. Si el nombre es "nuevo",
usa la palabra clave constructor en lugar de funcion.
Maneja parámetros, tipo de retorno, precondiciones (requiere),
postcondiciones (asegura) y cuerpo indentado.
|
Expresiones (32 variantes)
| Firma | Descripción |
fn expresion_a_string(&mut self, expr: &Expresion) -> String | ~226 líneas. Convierte cualquier expresión a su representación textual.
Match exhaustivo de las 32 variantes de Expresion:
- Literales: números, decimales, texto con comillas, booleanos (
verdadero/falso), nulo, exacto - Identificador (retorna el nombre)
- Binaria: operadores Forja (
+ - * / % > < >= <= == != y o) - Unaria:
-expr, !expr - Ternario:
cond ? verdadero : falso - LlamadaFuncion:
nombre(args) - LlamadaMetodo:
objeto.metodo(args) - AccesoMiembro:
objeto.miembro - Instanciacion:
nuevo Clase(args) - Referencia:
&expr, &mut expr - Arreglo:
[elem1, elem2] - Mapa:
{clave: valor} - Coincidir:
coincidir (expr) { caso ... } con indentación - Index:
obj[indice] - Closure:
func(params) { ... } - Grupo:
(expr) - Hilo:
hilo { ... } - CanalNuevo:
canal() - Try:
expr? - Seleccionar:
seleccionar { caso var = canal { ... } } - Asignacion:
var = expr - AsignacionCampo:
obj.campo = val - ArraySet:
arr = val - Constructores:
Ok(expr), Error(expr), Algo(expr) - Contract:
resultado, anterior(expr) |
Declaraciones inline
| Firma | Descripción |
fn declaracion_a_string(&mut self, decl: &Declaracion) -> String |
Captura temporalmente el buffer de output, formatea la declaración,
y retorna el resultado como String sin modificar el output principal.
Útil para formatear declaraciones dentro de expresiones.
|
fn declaracion_inline(&mut self, decl: &Declaracion) -> String |
Similar a declaracion_a_string pero además elimina
saltos de línea iniciales y finales. Usado en bucles para
para las partes de inicialización e incremento.
|
Pipeline de formateo
- Se recibe un
Programa (AST raíz) ya construido por el parser formatear() itera sobre programa.declaraciones - Para cada declaración, llama a
formatear_declaracion() formatear_declaracion() hace match de la variante y produce el texto:
- Para variables:
variable nombre = valor o constante nombre: Tipo = valor - Para funciones: incluye doc comments, atributos, firma, pre/postcondiciones, cuerpo
- Para clases: atributos, invariantes, campos, métodos
- Para control de flujo: bloques indentados con llaves
- Para enums, rasgos, implementaciones: formato específico
- Las expresiones se convierten a texto mediante
expresion_a_string() - Se retorna el String completo con el código formateado
Ejemplo de salida formateada
importar math
clase Persona {
nombre: Texto
edad: Entero
constructor(nombre: Texto, edad: Entero)
requiere edad >= 0, "La edad no puede ser negativa"
{
este.nombre = nombre
este.edad = edad
}
funcion es_mayor_de_edad() -> Booleano {
retornar este.edad >= 18
}
}
funcion main() {
variable p = nuevo Persona("Ana", 25)
escribir(p.es_mayor_de_edad())
}
Relación con el resto del compilador
- Consume el
Programa del AST generado por parser.rs - Se utiliza desde la CLI y potencialmente desde editores (LSP)
- Complementa al transpilador y al generador de bytecode como salida de código Forja formateado
- No modifica el AST — solo lo recorre para producir texto