use crate::{env::Env, expression::Expression, function::FunctionMap, value::Value}; #[derive(Debug, Clone, PartialEq)] pub enum Statement { Assignment(String, Expression, bool), Expression(Expression), While(Expression, Box), If(Vec<(Expression, Statement)>, Option>), Body(Vec), Return(Option), } impl Statement { pub fn eval(&self, env: &Env, f: &FunctionMap) -> Option { match self { Statement::Assignment(name, expr, explicit_let) => { let value = expr.eval(env, f); if *explicit_let { env.set_here(name, value); } else { env.set(name, value); } None } Statement::Expression(expr) => { expr.eval(env, f); None } Statement::While(expr, body) => { while expr.eval(env, f).is_truthy() { let body_env = Env::new_with_parent(env); if let Some(value) = body.eval(&body_env, f) { return Some(value); } } None } Statement::If(if_side, else_side) => { let mut did_if = false; for (expr, body) in if_side { if expr.eval(env, f).is_truthy() { if let Some(value) = body.eval(env, f) { return Some(value); } did_if = true; break; } } if !did_if { if let Some(else_side) = else_side { if let Some(value) = else_side.eval(env, f) { return Some(value); } } } None } Statement::Body(body) => { let body_env = Env::new_with_parent(env); for stmt in body.iter() { if let Some(value) = stmt.eval(&body_env, f) { return Some(value); } } None } Statement::Return(expr) => { if let Some(expr) = expr { Some(expr.eval(env, f)) } else { Some(Value::Nothing) } } } } }