use typeset::*;
#[derive(Debug, Clone)]
enum SExpr {
Atom(String),
List(Vec<SExpr>),
}
fn format_sexpr(expr: &SExpr) -> Box<Layout> {
match expr {
SExpr::Atom(s) => text(s.clone()),
SExpr::List(exprs) => {
if exprs.is_empty() {
text("()".to_string())
} else {
let open_paren = text("(".to_string());
let close_paren = text(")".to_string());
let first = format_sexpr(&exprs[0]);
if exprs.len() == 1 {
comp(
open_paren,
comp(first, close_paren, false, false),
false,
false,
)
} else {
let mut rest = null();
for expr in &exprs[1..] {
let formatted = format_sexpr(expr);
rest = match rest.as_ref() {
Layout::Null => formatted,
_ => comp(rest, formatted, true, false),
};
}
let args = pack(comp(first, rest, true, false));
comp(
open_paren,
comp(args, close_paren, false, false),
false,
false,
)
}
}
}
}
}
fn format_sexpr_sequence(expr: &SExpr) -> Box<Layout> {
match expr {
SExpr::Atom(s) => text(s.clone()),
SExpr::List(exprs) => {
if exprs.is_empty() {
text("()".to_string())
} else {
let open_paren = text("(".to_string());
let close_paren = text(")".to_string());
let mut items = null();
for (i, expr) in exprs.iter().enumerate() {
let formatted = format_sexpr_sequence(expr);
items = if i == 0 {
formatted
} else {
comp(items, formatted, true, false)
};
}
let content = seq(items);
let indented = nest(content);
comp(
open_paren,
comp(indented, close_paren, false, false),
false,
false,
)
}
}
}
}
fn main() {
println!("=== Lisp S-Expression Pretty Printer ===\n");
let atom = SExpr::Atom("hello".to_string());
let simple_list = SExpr::List(vec![
SExpr::Atom("+".to_string()),
SExpr::Atom("1".to_string()),
SExpr::Atom("2".to_string()),
SExpr::Atom("3".to_string()),
]);
println!("Atom: {}", render(compile(format_sexpr(&atom)), 2, 40));
println!(
"Simple list (wide): {}",
render(compile(format_sexpr(&simple_list)), 2, 40)
);
println!(
"Simple list (narrow): {}",
render(compile(format_sexpr(&simple_list)), 2, 10)
);
let nested = SExpr::List(vec![
SExpr::Atom("defun".to_string()),
SExpr::Atom("factorial".to_string()),
SExpr::List(vec![SExpr::Atom("n".to_string())]),
SExpr::List(vec![
SExpr::Atom("if".to_string()),
SExpr::List(vec![
SExpr::Atom("<=".to_string()),
SExpr::Atom("n".to_string()),
SExpr::Atom("1".to_string()),
]),
SExpr::Atom("1".to_string()),
SExpr::List(vec![
SExpr::Atom("*".to_string()),
SExpr::Atom("n".to_string()),
SExpr::List(vec![
SExpr::Atom("factorial".to_string()),
SExpr::List(vec![
SExpr::Atom("-".to_string()),
SExpr::Atom("n".to_string()),
SExpr::Atom("1".to_string()),
]),
]),
]),
]),
]);
println!("\n=== Nested Function Definition ===");
println!("\nPack-aligned style (wide):");
println!("{}", render(compile(format_sexpr(&nested)), 2, 80));
println!("\nPack-aligned style (medium):");
println!("{}", render(compile(format_sexpr(&nested)), 2, 40));
println!("\nPack-aligned style (narrow):");
println!("{}", render(compile(format_sexpr(&nested)), 2, 20));
println!("\n=== Sequence-aligned style (alternative) ===");
println!("\nSequence style (wide):");
println!("{}", render(compile(format_sexpr_sequence(&nested)), 2, 80));
println!("\nSequence style (narrow):");
println!("{}", render(compile(format_sexpr_sequence(&nested)), 2, 30));
let complex = SExpr::List(vec![
SExpr::Atom("let".to_string()),
SExpr::List(vec![
SExpr::List(vec![
SExpr::Atom("x".to_string()),
SExpr::List(vec![
SExpr::Atom("+".to_string()),
SExpr::Atom("a".to_string()),
SExpr::Atom("very-long-variable-name".to_string()),
]),
]),
SExpr::List(vec![
SExpr::Atom("y".to_string()),
SExpr::List(vec![
SExpr::Atom("*".to_string()),
SExpr::Atom("b".to_string()),
SExpr::Atom("another-long-name".to_string()),
]),
]),
]),
SExpr::List(vec![
SExpr::Atom("format".to_string()),
SExpr::Atom("t".to_string()),
SExpr::Atom("\"Result: ~A~%\"".to_string()),
SExpr::List(vec![
SExpr::Atom("+".to_string()),
SExpr::Atom("x".to_string()),
SExpr::Atom("y".to_string()),
]),
]),
]);
println!("\n=== Complex Let Expression ===");
println!("\nComplex (pack style, 50 chars):");
println!("{}", render(compile(format_sexpr(&complex)), 2, 50));
println!("\nComplex (sequence style, 50 chars):");
println!(
"{}",
render(compile(format_sexpr_sequence(&complex)), 2, 50)
);
}