1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
mod error;
mod value;
pub use self::error::{Error, Result};
pub use self::value::Value;
use crate::ast::{BinaryOperator, Expr, Ident, Literal, UnaryOperator};
use crate::common::env::Env;
#[derive(Debug, Default)]
pub struct Interpreter<'a> {
env: Env<'a, Value>,
}
impl<'a> Interpreter<'a> {
pub fn new() -> Self {
Self::default()
}
fn resolve(&self, var: &'a Ident<'a>) -> Result<Value> {
self.env
.resolve(var)
.cloned()
.ok_or_else(|| Error::UndefinedVariable(var.to_owned()))
}
pub fn eval(&mut self, expr: &'a Expr<'a>) -> Result<Value> {
match expr {
Expr::Ident(id) => self.resolve(id),
Expr::Literal(Literal::Int(i)) => Ok((*i).into()),
Expr::UnaryOp { op, rhs } => {
let rhs = self.eval(rhs)?;
match op {
UnaryOperator::Neg => -rhs,
_ => unimplemented!(),
}
}
Expr::BinaryOp { lhs, op, rhs } => {
let lhs = self.eval(lhs)?;
let rhs = self.eval(rhs)?;
match op {
BinaryOperator::Add => lhs + rhs,
BinaryOperator::Sub => lhs - rhs,
BinaryOperator::Mul => lhs * rhs,
BinaryOperator::Div => lhs / rhs,
BinaryOperator::Pow => todo!(),
BinaryOperator::Equ => Ok(lhs.eq(&rhs).into()),
BinaryOperator::Neq => todo!(),
}
}
Expr::Let { bindings, body } => {
self.env.push();
for (id, val) in bindings {
let val = self.eval(val)?;
self.env.set(id, val);
}
let res = self.eval(body)?;
self.env.pop();
Ok(res)
}
Expr::If {
condition,
then,
else_,
} => {
let condition = self.eval(condition)?;
if *(condition.into_type::<bool>()?) {
self.eval(then)
} else {
self.eval(else_)
}
}
}
}
}
pub fn eval<'a>(expr: &'a Expr<'a>) -> Result<Value> {
let mut interpreter = Interpreter::new();
interpreter.eval(expr)
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use super::value::{TypeOf, Val};
use super::*;
use BinaryOperator::*;
fn int_lit(i: u64) -> Box<Expr<'static>> {
Box::new(Expr::Literal(Literal::Int(i)))
}
fn parse_eval<T>(src: &str) -> T
where
for<'a> &'a T: TryFrom<&'a Val>,
T: Clone + TypeOf,
{
let expr = crate::parser::expr(src).unwrap().1;
let res = eval(&expr).unwrap();
res.into_type::<T>().unwrap().clone()
}
#[test]
fn simple_addition() {
let expr = Expr::BinaryOp {
lhs: int_lit(1),
op: Mul,
rhs: int_lit(2),
};
let res = eval(&expr).unwrap();
assert_eq!(*res.into_type::<i64>().unwrap(), 2);
}
#[test]
fn variable_shadowing() {
let res = parse_eval::<i64>("let x = 1 in (let x = 2 in x) + x");
assert_eq!(res, 3);
}
#[test]
fn conditional_with_equals() {
let res = parse_eval::<i64>("let x = 1 in if x == 1 then 2 else 4");
assert_eq!(res, 2);
}
}
|