78 lines
2.5 KiB
Rust
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|