Skip to main content

bock_fmt/
lib.rs

1//! Bock fmt — canonical source formatter for Bock programs.
2//!
3//! Zero-configuration, opinionated formatter that parses Bock source code
4//! and re-emits it in canonical style.
5//!
6//! # Formatting rules
7//! - 2-space indent, no tabs
8//! - 80 char soft limit, 100 hard limit
9//! - Opening brace same line
10//! - Trailing commas in multi-line constructs
11//! - Import sorting: core → std → external → local
12//! - Short signatures on one line, long signatures wrap per-param
13
14mod comments;
15mod emit;
16
17#[cfg(test)]
18mod tests;
19
20use bock_lexer::Lexer;
21use bock_parser::Parser;
22use bock_source::SourceFile;
23
24pub use emit::Formatter;
25
26/// Result of formatting a source file.
27#[derive(Debug)]
28pub struct FormatResult {
29    /// The formatted source text.
30    pub output: String,
31    /// Whether the output differs from the input.
32    pub changed: bool,
33}
34
35/// Format a Bock source string, returning the formatted output.
36///
37/// Parses the source, reformats the AST, and emits canonical source text.
38/// If parsing produces errors, the original source is returned unchanged.
39#[must_use]
40pub fn format_source(source: &str, filename: &str) -> FormatResult {
41    let file = SourceFile::new(
42        bock_errors::FileId(0),
43        std::path::PathBuf::from(filename),
44        source.to_string(),
45    );
46    let mut lexer = Lexer::new(&file);
47    let tokens = lexer.tokenize();
48
49    // If lexer had errors, return unchanged
50    if lexer.diagnostics().has_errors() {
51        return FormatResult {
52            output: source.to_string(),
53            changed: false,
54        };
55    }
56
57    let mut parser = Parser::new(tokens, &file);
58    let module = parser.parse_module();
59
60    // If parser had errors, return unchanged
61    if parser.diagnostics().has_errors() {
62        return FormatResult {
63            output: source.to_string(),
64            changed: false,
65        };
66    }
67
68    let comments = comments::extract_comments(source);
69    let mut formatter = Formatter::new(&comments, source);
70    formatter.format_module(&module);
71    let output = formatter.finish();
72
73    let changed = output != source;
74    FormatResult { output, changed }
75}