/home/noah/src/ruchy/src/quality/formatter.rs
Line | Count | Source |
1 | | // Code formatter for Ruchy |
2 | | // Toyota Way: Consistent code style prevents defects |
3 | | |
4 | | use anyhow::Result; |
5 | | use crate::frontend::ast::{Expr, ExprKind}; |
6 | | |
7 | | pub struct Formatter { |
8 | | indent_width: usize, |
9 | | use_tabs: bool, |
10 | | _line_width: usize, |
11 | | } |
12 | | |
13 | | impl Formatter { |
14 | 0 | pub fn new() -> Self { |
15 | 0 | Self { |
16 | 0 | indent_width: 4, |
17 | 0 | use_tabs: false, |
18 | 0 | _line_width: 100, |
19 | 0 | } |
20 | 0 | } |
21 | | |
22 | 0 | pub fn format(&self, ast: &Expr) -> Result<String> { |
23 | | // Simple formatter that converts AST back to source |
24 | 0 | Ok(self.format_expr(ast, 0)) |
25 | 0 | } |
26 | | |
27 | 0 | fn format_type(&self, ty_kind: &crate::frontend::ast::TypeKind) -> String { |
28 | 0 | match ty_kind { |
29 | 0 | crate::frontend::ast::TypeKind::Named(name) => name.clone(), |
30 | 0 | _ => format!("{ty_kind:?}"), |
31 | | } |
32 | 0 | } |
33 | | |
34 | 0 | fn format_expr(&self, expr: &Expr, indent: usize) -> String { |
35 | 0 | let indent_str = if self.use_tabs { |
36 | 0 | "\t".repeat(indent) |
37 | | } else { |
38 | 0 | " ".repeat(indent * self.indent_width) |
39 | | }; |
40 | | |
41 | 0 | match &expr.kind { |
42 | 0 | ExprKind::Literal(lit) => match lit { |
43 | 0 | crate::frontend::ast::Literal::Integer(n) => n.to_string(), |
44 | 0 | crate::frontend::ast::Literal::Float(f) => f.to_string(), |
45 | 0 | crate::frontend::ast::Literal::String(s) => format!("\"{s}\""), |
46 | 0 | crate::frontend::ast::Literal::Bool(b) => b.to_string(), |
47 | 0 | crate::frontend::ast::Literal::Char(c) => format!("'{c}'"), |
48 | 0 | crate::frontend::ast::Literal::Unit => "()".to_string(), |
49 | | }, |
50 | 0 | ExprKind::Identifier(name) => name.clone(), |
51 | 0 | ExprKind::Let { name, value, body, .. } => { |
52 | 0 | format!( |
53 | 0 | "let {} = {} in {}", |
54 | | name, |
55 | 0 | self.format_expr(value, indent), |
56 | 0 | self.format_expr(body, indent) |
57 | | ) |
58 | | } |
59 | 0 | ExprKind::Binary { left, op, right } => { |
60 | 0 | format!( |
61 | 0 | "{} {} {}", |
62 | 0 | self.format_expr(left, indent), |
63 | | op, |
64 | 0 | self.format_expr(right, indent) |
65 | | ) |
66 | | } |
67 | 0 | ExprKind::Block(exprs) => { |
68 | 0 | let mut result = String::from("{\n"); |
69 | 0 | for expr in exprs { |
70 | 0 | result.push_str(&format!( |
71 | 0 | "{}{}\n", |
72 | 0 | indent_str, |
73 | 0 | self.format_expr(expr, indent + 1) |
74 | 0 | )); |
75 | 0 | } |
76 | 0 | result.push_str(&format!("{indent_str}}}")); |
77 | 0 | result |
78 | | } |
79 | 0 | ExprKind::Function { name, params, return_type, body, .. } => { |
80 | 0 | let mut result = format!("fun {name}"); |
81 | | |
82 | | // Parameters |
83 | 0 | result.push('('); |
84 | 0 | for (i, param) in params.iter().enumerate() { |
85 | 0 | if i > 0 { result.push_str(", "); } |
86 | 0 | if let crate::frontend::ast::Pattern::Identifier(param_name) = ¶m.pattern { |
87 | 0 | result.push_str(param_name); |
88 | 0 | result.push_str(": "); |
89 | 0 | result.push_str(&self.format_type(¶m.ty.kind)); |
90 | 0 | } |
91 | | } |
92 | 0 | result.push(')'); |
93 | | |
94 | | // Return type |
95 | 0 | if let Some(ret_ty) = return_type { |
96 | 0 | result.push_str(" -> "); |
97 | 0 | result.push_str(&self.format_type(&ret_ty.kind)); |
98 | 0 | } |
99 | | |
100 | 0 | result.push(' '); |
101 | 0 | result.push_str(&self.format_expr(body.as_ref(), indent)); |
102 | 0 | result |
103 | | } |
104 | 0 | ExprKind::If { condition, then_branch, else_branch } => { |
105 | 0 | let mut result = "if ".to_string(); |
106 | 0 | result.push_str(&self.format_expr(condition, indent)); |
107 | 0 | result.push(' '); |
108 | 0 | result.push_str(&self.format_expr(then_branch, indent)); |
109 | 0 | if let Some(else_expr) = else_branch { |
110 | 0 | result.push_str(" else "); |
111 | 0 | result.push_str(&self.format_expr(else_expr, indent)); |
112 | 0 | } |
113 | 0 | result |
114 | | } |
115 | | _ => { |
116 | 0 | format!("{:?}", expr.kind) // Fallback for unimplemented cases |
117 | | } |
118 | | } |
119 | 0 | } |
120 | | } |
121 | | |
122 | | impl Default for Formatter { |
123 | 0 | fn default() -> Self { |
124 | 0 | Self::new() |
125 | 0 | } |
126 | | } |