Last active
April 4, 2018 16:24
-
-
Save clarkenciel/3853fa3b1d662c1e38dfe511f8e22866 to your computer and use it in GitHub Desktop.
Interpreter implemented using the visitor pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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