use crate::formatter::ir::Ir;
use crate::formatter::printer::print;
use crate::formatter::rules::lower;
use crate::formatter::style::FormatStyle;
use crate::parser::parse;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FormatError {
Unsupported(String),
}
impl std::fmt::Display for FormatError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
FormatError::Unsupported(what) => write!(f, "unsupported construct: {what}"),
}
}
}
impl std::error::Error for FormatError {}
pub fn format(input: &str) -> Result<String, FormatError> {
format_with_style(input, FormatStyle::default())
}
pub fn format_with_style(input: &str, style: FormatStyle) -> Result<String, FormatError> {
let doc = lower(&parse(input).cst);
Ok(print(&doc, style))
}
pub fn print_document(doc: &Ir, style: FormatStyle) -> String {
print(doc, style)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalizes_operator_spacing() {
for (input, expected) in [
("x=1\n", "x = 1\n"),
("y= a+b\n", "y = a + b\n"),
(
"function g(x)\n x ^ 2\nend\n",
"function g(x)\n x^2\nend\n",
),
("# comment\ny = a + b\n", "# comment\ny = a + b\n"),
] {
assert_eq!(format(input).unwrap(), expected);
}
}
#[test]
fn format_is_idempotent() {
for input in ["x=1\n", "z = a*b + c\n", "if a\n b\nelse\n c\nend\n"] {
let once = format(input).unwrap();
assert_eq!(format(&once).unwrap(), once, "not idempotent for {input:?}");
}
}
}