use std::fmt::Display; use crate::misc::indent; use super::Expr; #[derive(Debug, Clone)] pub enum Stmt { Print { expr: Box, }, IfStmt { condition: Box, then_branch: Box, else_branch: Option>, }, While { condition: Box, body: Box, }, VarDecl { name: String, initializer: Box, }, Block { statements: Vec, }, ExprStmt { expr: Box, }, Break, Return { expr: Box, }, } impl Stmt { pub fn print_stmt(expr: Expr) -> Self { let expr = Box::new(expr); Stmt::Print { expr } } pub fn if_stmt( condition: impl Into>, then_branch: impl Into>, else_branch: Option>>, ) -> Self { let condition = condition.into(); let then_branch = then_branch.into(); let else_branch = else_branch.map(|stmt| stmt.into()); Stmt::IfStmt { condition, then_branch, else_branch, } } pub fn while_stmt(condition: impl Into>, body: impl Into>) -> Self { let condition = condition.into(); let body = body.into(); Stmt::While { condition, body } } pub fn var_decl(name: impl Into, initializer: impl Into>) -> Self { let name = name.into(); let initializer = initializer.into(); Stmt::VarDecl { name, initializer } } pub fn expr_stmt(expr: impl Into>) -> Self { let expr = expr.into(); Stmt::ExprStmt { expr } } pub fn return_stmt(expr: impl Into>) -> Self { let expr = expr.into(); Stmt::Return { expr } } } impl Display for Stmt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Stmt::Print { expr } => write!(f, "print {expr};"), Stmt::IfStmt { condition, then_branch, else_branch, } => { writeln!(f, "if {condition}")?; match then_branch.as_ref() { Stmt::Block { .. } => write!(f, "{then_branch}")?, _ => write!(f, "{}", indent(format!("{then_branch}")))?, } if let Some(else_branch) = else_branch { writeln!(f, "\nelse")?; match else_branch.as_ref() { Stmt::Block { .. } => write!(f, "{else_branch}")?, _ => write!(f, "{}", indent(format!("{else_branch}")))?, } } Ok(()) } Stmt::While { condition, body } => { writeln!(f, "{condition}")?; match body.as_ref() { Stmt::Block { .. } => write!(f, "{body}")?, _ => write!(f, "{}", indent(format!("{body}")))?, } Ok(()) } Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer};"), Stmt::Block { statements } => { writeln!(f, "{{")?; for statement in statements { write!(f, "{}", indent(format!("{statement}")))?; } write!(f, "}}") } Stmt::ExprStmt { expr } => write!(f, "{expr};"), Stmt::Break => write!(f, "break;"), Stmt::Return { expr } => { write!(f, "return {expr};") } } } }