Formatter – Formateador de Código Forja

Archivo: src/formatter.rs795 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

CampoTipoDescripción
outputStringBuffer de salida donde se acumula el código formateado
indentusizeNivel de indentación actual (cada nivel = 4 espacios)

Métodos públicos

Formatter::new()

FirmaDescripción
pub fn new() -> SelfCrea un nuevo formatter vacío con indentación 0 y output vacío

Formatter::formatear()

FirmaDescripció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

FirmaDescripció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

FirmaDescripció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)

FirmaDescripció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)

FirmaDescripció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

FirmaDescripció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)

FirmaDescripció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

FirmaDescripció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

  1. Se recibe un Programa (AST raíz) ya construido por el parser
  2. formatear() itera sobre programa.declaraciones
  3. Para cada declaración, llama a formatear_declaracion()
  4. 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
  5. Las expresiones se convierten a texto mediante expresion_a_string()
  6. 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