use typeset::*;
#[derive(Debug, Clone)]
enum Statement {
Assignment {
var: String,
expr: Expression,
},
If {
condition: Expression,
then_block: Vec<Statement>,
else_block: Option<Vec<Statement>>,
},
While {
condition: Expression,
body: Vec<Statement>,
},
FunctionCall {
name: String,
args: Vec<Expression>,
},
#[allow(dead_code)]
Return(Option<Expression>),
}
#[derive(Debug, Clone)]
enum Expression {
Variable(String),
Number(i64),
String(String),
BinaryOp {
left: Box<Expression>,
op: String,
right: Box<Expression>,
},
FunctionCall {
name: String,
args: Vec<Expression>,
},
}
fn format_expression(expr: &Expression) -> Box<Layout> {
match expr {
Expression::Variable(name) => text(name.clone()),
Expression::Number(n) => text(n.to_string()),
Expression::String(s) => text(format!("\"{}\"", s)),
Expression::BinaryOp { left, op, right } => {
let left_layout = format_expression(left);
let op_layout = text(format!(" {} ", op));
let right_layout = format_expression(right);
grp(comp(
left_layout,
comp(op_layout, right_layout, false, false),
false,
false,
))
}
Expression::FunctionCall { name, args } => {
let name_layout = text(name.clone());
let open_paren = text("(".to_string());
let close_paren = text(")".to_string());
if args.is_empty() {
comp(
name_layout,
comp(open_paren, close_paren, false, false),
false,
false,
)
} else {
let args_layout = format_argument_list(args);
comp(
name_layout,
comp(
open_paren,
comp(args_layout, close_paren, false, false),
false,
false,
),
false,
false,
)
}
}
}
}
fn format_argument_list(args: &[Expression]) -> Box<Layout> {
if args.is_empty() {
return null();
}
let formatted_args = args.iter().enumerate().fold(null(), |acc, (i, arg)| {
let formatted_arg = format_expression(arg);
if i == 0 {
formatted_arg
} else {
comp(
acc,
comp(text(",".to_string()), formatted_arg, true, false),
false,
false,
)
}
});
pack(seq(formatted_args))
}
fn format_statement(stmt: &Statement) -> Box<Layout> {
match stmt {
Statement::Assignment { var, expr } => {
let var_layout = text(var.clone());
let assign_op = text(" = ".to_string());
let expr_layout = format_expression(expr);
let semicolon = text(";".to_string());
comp(
var_layout,
comp(
assign_op,
comp(expr_layout, semicolon, false, false),
false,
false,
),
false,
false,
)
}
Statement::FunctionCall { name, args } => {
let call_expr = Expression::FunctionCall {
name: name.clone(),
args: args.clone(),
};
comp(
format_expression(&call_expr),
text(";".to_string()),
false,
false,
)
}
Statement::Return(maybe_expr) => {
let return_kw = text("return".to_string());
match maybe_expr {
None => comp(return_kw, text(";".to_string()), false, false),
Some(expr) => {
let expr_layout = format_expression(expr);
comp(
return_kw,
comp(expr_layout, text(";".to_string()), true, false),
false,
false,
)
}
}
}
Statement::If {
condition,
then_block,
else_block,
} => {
let if_kw = text("if".to_string());
let open_paren = text(" (".to_string());
let close_paren = text(") ".to_string());
let condition_layout = format_expression(condition);
let condition_part = comp(
if_kw,
comp(
open_paren,
comp(condition_layout, close_paren, false, false),
false,
false,
),
false,
false,
);
let then_part = format_block(then_block);
match else_block {
None => comp(condition_part, then_part, false, false),
Some(else_stmts) => {
let else_kw = text(" else ".to_string());
let else_part = format_block(else_stmts);
comp(
condition_part,
comp(
then_part,
comp(else_kw, else_part, false, false),
false,
false,
),
false,
false,
)
}
}
}
Statement::While { condition, body } => {
let while_kw = text("while".to_string());
let open_paren = text(" (".to_string());
let close_paren = text(") ".to_string());
let condition_layout = format_expression(condition);
let condition_part = comp(
while_kw,
comp(
open_paren,
comp(condition_layout, close_paren, false, false),
false,
false,
),
false,
false,
);
let body_part = format_block(body);
comp(condition_part, body_part, false, false)
}
}
}
fn format_block(statements: &[Statement]) -> Box<Layout> {
let open_brace = text("{".to_string());
let close_brace = text("}".to_string());
if statements.is_empty() {
comp(open_brace, close_brace, false, false)
} else {
let mut formatted_stmts = null();
for stmt in statements {
let formatted_stmt = format_statement(stmt);
formatted_stmts = match formatted_stmts.as_ref() {
Layout::Null => formatted_stmt,
_ => line(formatted_stmts, formatted_stmt),
};
}
let indented_stmts = nest(formatted_stmts);
comp(
open_brace,
comp(
line(null(), indented_stmts),
line(null(), close_brace),
false,
false,
),
false,
false,
)
}
}
fn main() {
println!("=== Source Code Formatter Example ===\n");
let assignment = Statement::Assignment {
var: "x".to_string(),
expr: Expression::BinaryOp {
left: Box::new(Expression::Number(10)),
op: "+".to_string(),
right: Box::new(Expression::Variable("y".to_string())),
},
};
println!("Simple assignment:");
println!("{}", render(compile(format_statement(&assignment)), 2, 40));
let func_call = Statement::FunctionCall {
name: "printf".to_string(),
args: vec![
Expression::String("Hello, %s! You are %d years old.".to_string()),
Expression::Variable("name".to_string()),
Expression::Variable("age".to_string()),
],
};
println!("\nFunction call (wide):");
println!("{}", render(compile(format_statement(&func_call)), 2, 80));
println!("\nFunction call (narrow):");
println!("{}", render(compile(format_statement(&func_call)), 2, 30));
let if_stmt = Statement::If {
condition: Expression::BinaryOp {
left: Box::new(Expression::Variable("x".to_string())),
op: ">".to_string(),
right: Box::new(Expression::Number(0)),
},
then_block: vec![
Statement::Assignment {
var: "result".to_string(),
expr: Expression::FunctionCall {
name: "calculate".to_string(),
args: vec![
Expression::Variable("x".to_string()),
Expression::Number(42),
],
},
},
Statement::FunctionCall {
name: "print".to_string(),
args: vec![Expression::Variable("result".to_string())],
},
],
else_block: Some(vec![Statement::FunctionCall {
name: "print".to_string(),
args: vec![Expression::String("x is not positive".to_string())],
}]),
};
println!("\n=== Complex If Statement ===");
println!("\nWide format (80 chars):");
println!("{}", render(compile(format_statement(&if_stmt)), 2, 80));
println!("\nNarrow format (40 chars):");
println!("{}", render(compile(format_statement(&if_stmt)), 2, 40));
let nested_stmt = Statement::While {
condition: Expression::BinaryOp {
left: Box::new(Expression::Variable("i".to_string())),
op: "<".to_string(),
right: Box::new(Expression::Variable("max_iterations".to_string())),
},
body: vec![
Statement::If {
condition: Expression::BinaryOp {
left: Box::new(Expression::FunctionCall {
name: "is_prime".to_string(),
args: vec![Expression::Variable("i".to_string())],
}),
op: "==".to_string(),
right: Box::new(Expression::Number(1)),
},
then_block: vec![Statement::FunctionCall {
name: "add_to_list".to_string(),
args: vec![
Expression::Variable("primes".to_string()),
Expression::Variable("i".to_string()),
],
}],
else_block: None,
},
Statement::Assignment {
var: "i".to_string(),
expr: Expression::BinaryOp {
left: Box::new(Expression::Variable("i".to_string())),
op: "+".to_string(),
right: Box::new(Expression::Number(1)),
},
},
],
};
println!("\n=== Nested Control Flow ===");
println!("\nWide format (100 chars):");
println!(
"{}",
render(compile(format_statement(&nested_stmt)), 2, 100)
);
println!("\nMedium format (60 chars):");
println!("{}", render(compile(format_statement(&nested_stmt)), 2, 60));
println!("\nNarrow format (30 chars):");
println!("{}", render(compile(format_statement(&nested_stmt)), 2, 30));
}