Skip to content

Instantly share code, notes, and snippets.

@clarkenciel
Last active April 4, 2018 16:24
Show Gist options
  • Save clarkenciel/3853fa3b1d662c1e38dfe511f8e22866 to your computer and use it in GitHub Desktop.
Save clarkenciel/3853fa3b1d662c1e38dfe511f8e22866 to your computer and use it in GitHub Desktop.
Interpreter implemented using the visitor pattern
use std::collections::HashMap;
enum Stmt {
Expr(Expr),
Let(Name, Expr),
}
struct Name(String);
enum Expr {
IntLit(i64),
Variable(String),
Add(Box<Expr>, Box<Expr>),
Sub(Box<Expr>, Box<Expr>),
}
trait Visitor<I, O> {
fn visit(&mut self, input: &I) -> O;
}
#[derive(Debug)]
struct Interpreter {
bindings: HashMap<String, i64>,
}
#[derive(Debug)]
enum Interpretation<O> {
Incomplete,
Complete(O),
}
impl Interpreter {
fn new() -> Self {
Interpreter { bindings: HashMap::new() }
}
}
impl Visitor<Stmt, Interpretation<i64>> for Interpreter {
fn visit(&mut self, input: &Stmt) -> Interpretation<i64> {
match *input {
Stmt::Expr(ref expr) => Interpretation::Complete(self.visit(expr)),
Stmt::Let(Name(ref name), ref binding) => {
let value = self.visit(binding);
self.bindings.insert(name.clone(), value);
Interpretation::Incomplete
},
}
}
}
impl Visitor<Expr, i64> for Interpreter {
fn visit(&mut self, input: &Expr) -> i64 {
match *input {
Expr::IntLit(n) => n,
Expr::Add(ref left, ref right) => self.visit(left) + self.visit(right),
Expr::Sub(ref left, ref right) => self.visit(left) - self.visit(right),
Expr::Variable(ref name) => *self.bindings.get(name).unwrap(),
}
}
}
impl Visitor<Box<Expr>, i64> for Interpreter {
fn visit(&mut self, input: &Box<Expr>) -> i64 {
self.visit(&**input)
}
}
fn main() {
let ast1 = Stmt::Let(Name("x".to_owned()), Expr::IntLit(20));
let ast2 = Expr::IntLit(10);
let ast3 = Expr::Add(
Box::new(Expr::IntLit(20)),
Box::new(
Expr::Sub(
Box::new(Expr::IntLit(30)),
Box::new(Expr::Variable("x".to_owned()))
)
)
);
let mut interpreter = Interpreter::new();
interpreter.visit(&ast1);
println!("{:?}", interpreter);
assert!(interpreter.visit(&ast2) == 10);
println!("{}", interpreter.visit(&ast2));
assert!(interpreter.visit(&ast3) == 30);
println!("{}", interpreter.visit(&ast3));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment