use std::collections::HashMap;
use stutter::{Output, StepFn};
enum Expr {
IntLiteral(i64),
BoolLiteral(bool),
Variable(String),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
Value(Value),
}
#[derive(Copy, Clone, PartialEq, Debug)]
enum Value {
Int(i64),
Bool(bool),
Stuck,
}
struct Environment {
bindings: HashMap<String, Value>,
}
impl Environment {
pub fn new() -> Environment {
Self {
bindings: HashMap::new(),
}
}
pub fn set(&mut self, var: String, value: Value) {
self.bindings.insert(var, value);
}
}
impl StepFn<Expr, Value> for Environment {
fn step(&self, expr: Expr) -> Output<Expr, Value> {
match expr {
Expr::IntLiteral(i) => {
let v = Value::Int(i);
Output::More(Expr::Value(v))
}
Expr::BoolLiteral(b) => {
let v = Value::Bool(b);
Output::More(Expr::Value(v))
}
Expr::Variable(n) => {
let r = self.bindings.get(&n);
match r {
Some(v) => Output::Done(*v),
None => Output::Done(Value::Stuck),
}
}
Expr::Value(v) => Output::Done(v),
_ => {
Output::Done(Value::Stuck)
}
}
}
}
#[test]
fn test_step_01() {
let e = Expr::IntLiteral(1);
eval(e, 1, Value::Int(1));
}
fn eval(mut expr: Expr, n: u64, expecting: Value) {
let env = Environment::new();
for i in 0..n {
expr = env.step(expr).more();
}
let v = env.step(expr).done();
assert_eq!(v, expecting);
}