1use crate::reader::SExpr;
7
8pub fn format_exprs(exprs: &[SExpr], indent: usize) -> String {
9 let mut out = String::new();
10 for (i, expr) in exprs.iter().enumerate() {
11 out.push_str(&format_expr(expr, indent));
12 if i + 1 < exprs.len() {
13 out.push('\n');
14 if indent == 0 {
16 out.push('\n');
17 }
18 }
19 }
20 out.push('\n');
21 out
22}
23
24fn format_expr(expr: &SExpr, indent: usize) -> String {
25 match expr {
26 SExpr::Atom(s) => s.clone(),
27 SExpr::Str(s) => format!("\"{}\"", escape_string(s)),
28 SExpr::Num(n) => {
29 if *n == (*n as i64) as f64 {
30 format!("{}", *n as i64)
31 } else {
32 format!("{}", n)
33 }
34 }
35 SExpr::List(values) => format_list(values, indent),
36 }
37}
38
39fn format_list(values: &[SExpr], indent: usize) -> String {
40 if values.is_empty() {
41 return "()".to_string();
42 }
43
44 let single = format_single_line(values);
46 if single.len() + indent <= 80 && !single.contains('\n') {
47 return format!("({})", single);
48 }
49
50 let head = format_expr(&values[0], 0);
52 let child_indent = indent + 2;
53 let child_prefix = " ".repeat(child_indent);
54
55 let mut out = format!("({}", head);
56 for val in &values[1..] {
57 let formatted = format_expr(val, child_indent);
58 out.push('\n');
59 out.push_str(&child_prefix);
60 out.push_str(&formatted);
61 }
62 out.push(')');
63 out
64}
65
66fn format_single_line(values: &[SExpr]) -> String {
67 values
68 .iter()
69 .map(|v| format_expr(v, 0))
70 .collect::<Vec<_>>()
71 .join(" ")
72}
73
74fn escape_string(s: &str) -> String {
75 s.replace('\\', "\\\\")
76 .replace('"', "\\\"")
77 .replace('\n', "\\n")
78 .replace('\t', "\\t")
79}