sunflower/src/statement.rs

78 lines
2.5 KiB
Rust

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<Statement>),
If(Vec<(Expression, Statement)>, Option<Box<Statement>>),
Body(Vec<Statement>),
Return(Option<Expression>),
}
impl Statement {
pub fn eval(&self, env: &Env, f: &FunctionMap) -> Option<Value> {
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)
}
}
}
}
}