2023-01-22 23:33:57 +01:00
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
use crate::misc::indent;
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
use super::Expr;
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
#[derive(Debug, Clone)]
|
2023-01-22 23:33:57 +01:00
|
|
|
pub enum Stmt {
|
2023-01-25 19:01:13 +01:00
|
|
|
Print {
|
|
|
|
|
expr: Box<Expr>,
|
|
|
|
|
},
|
|
|
|
|
IfStmt {
|
|
|
|
|
condition: Box<Expr>,
|
|
|
|
|
then_branch: Box<Stmt>,
|
|
|
|
|
else_branch: Option<Box<Stmt>>,
|
|
|
|
|
},
|
|
|
|
|
While {
|
|
|
|
|
condition: Box<Expr>,
|
|
|
|
|
body: Box<Stmt>,
|
|
|
|
|
},
|
|
|
|
|
VarDecl {
|
|
|
|
|
name: String,
|
|
|
|
|
initializer: Box<Expr>,
|
|
|
|
|
},
|
|
|
|
|
Block {
|
|
|
|
|
statements: Vec<Stmt>,
|
|
|
|
|
},
|
|
|
|
|
ExprStmt {
|
|
|
|
|
expr: Box<Expr>,
|
|
|
|
|
},
|
|
|
|
|
Break,
|
|
|
|
|
Return {
|
|
|
|
|
expr: Box<Expr>,
|
|
|
|
|
},
|
2023-01-22 23:33:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Stmt {
|
|
|
|
|
pub fn print_stmt(expr: Expr) -> Self {
|
|
|
|
|
let expr = Box::new(expr);
|
|
|
|
|
Stmt::Print { expr }
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
pub fn if_stmt(
|
|
|
|
|
condition: impl Into<Box<Expr>>,
|
|
|
|
|
then_branch: impl Into<Box<Stmt>>,
|
|
|
|
|
else_branch: Option<impl Into<Box<Stmt>>>,
|
|
|
|
|
) -> 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<Box<Expr>>, body: impl Into<Box<Stmt>>) -> Self {
|
|
|
|
|
let condition = condition.into();
|
|
|
|
|
let body = body.into();
|
|
|
|
|
|
|
|
|
|
Stmt::While { condition, body }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn var_decl(name: impl Into<String>, initializer: impl Into<Box<Expr>>) -> Self {
|
|
|
|
|
let name = name.into();
|
|
|
|
|
let initializer = initializer.into();
|
2023-01-22 23:33:57 +01:00
|
|
|
Stmt::VarDecl { name, initializer }
|
|
|
|
|
}
|
2023-01-25 19:01:13 +01:00
|
|
|
|
|
|
|
|
pub fn expr_stmt(expr: impl Into<Box<Expr>>) -> Self {
|
|
|
|
|
let expr = expr.into();
|
|
|
|
|
Stmt::ExprStmt { expr }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn return_stmt(expr: impl Into<Box<Expr>>) -> Self {
|
|
|
|
|
let expr = expr.into();
|
|
|
|
|
Stmt::Return { expr }
|
|
|
|
|
}
|
2023-01-22 23:33:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for Stmt {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
match self {
|
2023-01-25 19:01:13 +01:00
|
|
|
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};"),
|
2023-01-22 23:33:57 +01:00
|
|
|
Stmt::Block { statements } => {
|
|
|
|
|
writeln!(f, "{{")?;
|
|
|
|
|
for statement in statements {
|
2023-01-25 19:01:13 +01:00
|
|
|
write!(f, "{}", indent(format!("{statement}")))?;
|
2023-01-22 23:33:57 +01:00
|
|
|
}
|
|
|
|
|
write!(f, "}}")
|
|
|
|
|
}
|
2023-01-25 19:01:13 +01:00
|
|
|
Stmt::ExprStmt { expr } => write!(f, "{expr};"),
|
|
|
|
|
Stmt::Break => write!(f, "break;"),
|
|
|
|
|
Stmt::Return { expr } => {
|
|
|
|
|
write!(f, "return {expr};")
|
|
|
|
|
}
|
2023-01-22 23:33:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|