Skip to main content

gruel_fmt/
lib.rs

1//! Source formatter for Gruel (ADR-0093).
2//!
3//! Parses source with the existing chumsky frontend, walks the AST, and emits
4//! canonical text. Comment weaving is delegated to a side trivia scan
5//! (ADR-0093 Phase 4).
6
7use std::fmt;
8
9use gruel_lexer::Lexer;
10use gruel_parser::Parser;
11use gruel_util::CompileErrors;
12
13pub mod emit;
14pub mod printer;
15pub mod trivia;
16pub use printer::Printer;
17
18/// Top-level error returned from [`format_source`].
19#[derive(Debug)]
20pub enum FmtError {
21    /// Source failed to lex or parse.
22    Parse(CompileErrors),
23}
24
25impl fmt::Display for FmtError {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        match self {
28            FmtError::Parse(errs) => write!(f, "{}", errs),
29        }
30    }
31}
32
33impl std::error::Error for FmtError {}
34
35/// Format `src` to canonical Gruel form. Returns `Err` if the source does not
36/// lex or parse.
37pub fn format_source(src: &str) -> Result<String, FmtError> {
38    let (tokens, interner) = Lexer::new(src)
39        .tokenize()
40        .map_err(|e| FmtError::Parse(e.into()))?;
41    let (ast, interner) = Parser::new(tokens, interner)
42        .with_source(src.to_string())
43        .parse()
44        .map_err(FmtError::Parse)?;
45
46    let mut printer = Printer::new(&interner, src);
47    emit::emit_ast(&mut printer, &ast);
48    Ok(printer.finish())
49}