97 lines
3.0 KiB
Rust
97 lines
3.0 KiB
Rust
use crate::parser::{Ast, BinOpType, UnOpType};
|
|
|
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
|
pub enum Value {
|
|
I64(i64),
|
|
}
|
|
|
|
pub struct Interpreter {
|
|
// Runtime storage, for example variables ...
|
|
}
|
|
|
|
impl Interpreter {
|
|
pub fn new() -> Self {
|
|
Self {}
|
|
}
|
|
|
|
pub fn run(&mut self, prog: Ast) {
|
|
let result = self.resolve_expr(prog);
|
|
|
|
println!("Result = {:?}", result);
|
|
}
|
|
|
|
fn resolve_expr(&mut self, expr: Ast) -> Value {
|
|
match expr {
|
|
Ast::I64(val) => Value::I64(val),
|
|
Ast::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, *lhs, *rhs),
|
|
Ast::UnOp(uo, val) => self.resolve_unop(uo, *val),
|
|
}
|
|
}
|
|
|
|
fn resolve_binop(&mut self, bo: BinOpType, lhs: Ast, rhs: Ast) -> Value {
|
|
let lhs = self.resolve_expr(lhs);
|
|
let rhs = self.resolve_expr(rhs);
|
|
|
|
match (lhs, rhs) {
|
|
(Value::I64(lhs), Value::I64(rhs)) => match bo {
|
|
BinOpType::Add => Value::I64(lhs + rhs),
|
|
BinOpType::Mul => Value::I64(lhs * rhs),
|
|
BinOpType::Sub => Value::I64(lhs - rhs),
|
|
BinOpType::Div => Value::I64(lhs / rhs),
|
|
BinOpType::Mod => Value::I64(lhs % rhs),
|
|
BinOpType::BOr => Value::I64(lhs | rhs),
|
|
BinOpType::BAnd => Value::I64(lhs & rhs),
|
|
BinOpType::BXor => Value::I64(lhs ^ rhs),
|
|
BinOpType::Shr => Value::I64(lhs >> rhs),
|
|
BinOpType::Shl => Value::I64(lhs << rhs),
|
|
BinOpType::Equ => Value::I64(if lhs == rhs { 1 } else { 0 }),
|
|
BinOpType::Neq => Value::I64(if lhs != rhs { 1 } else { 0 }),
|
|
BinOpType::Gt => Value::I64(if lhs > rhs { 1 } else { 0 }),
|
|
BinOpType::Ge => Value::I64(if lhs >= rhs { 1 } else { 0 }),
|
|
BinOpType::Lt => Value::I64(if lhs < rhs { 1 } else { 0 }),
|
|
BinOpType::Le => Value::I64(if lhs <= rhs { 1 } else { 0 }),
|
|
},
|
|
// _ => panic!("Value types are not compatible"),
|
|
}
|
|
}
|
|
|
|
fn resolve_unop(&mut self, uo: UnOpType, val: Ast) -> Value {
|
|
let val = self.resolve_expr(val);
|
|
match val {
|
|
Value::I64(val) => match uo {
|
|
UnOpType::Neg => Value::I64(-val),
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::{Interpreter, Value};
|
|
use crate::parser::{Ast, BinOpType};
|
|
|
|
#[test]
|
|
fn test_interpreter_expr() {
|
|
// Expression: 1 + 2 * 3 + 4
|
|
// With precedence: (1 + (2 * 3)) + 4
|
|
let ast = Ast::BinOp(
|
|
BinOpType::Add,
|
|
Ast::BinOp(
|
|
BinOpType::Add,
|
|
Ast::I64(1).into(),
|
|
Ast::BinOp(BinOpType::Mul, Ast::I64(2).into(), Ast::I64(3).into()).into(),
|
|
)
|
|
.into(),
|
|
Ast::I64(4).into(),
|
|
);
|
|
|
|
let expected = Value::I64(11);
|
|
|
|
let mut interpreter = Interpreter::new();
|
|
let actual = interpreter.resolve_expr(ast);
|
|
|
|
assert_eq!(expected, actual);
|
|
}
|
|
}
|