Finalize interpreter for now
This commit is contained in:
parent
f4b208dfde
commit
38dd3f523b
3 changed files with 146 additions and 104 deletions
|
@ -24,22 +24,20 @@ impl<'source> Interpreter<'source> {
|
||||||
BoolLiteral(_, val) => Value::Bool(*val),
|
BoolLiteral(_, val) => Value::Bool(*val),
|
||||||
Identifier(_, name) => *self.symbols.get(name),
|
Identifier(_, name) => *self.symbols.get(name),
|
||||||
UnaryOp(_, op, expr) => match *op {
|
UnaryOp(_, op, expr) => match *op {
|
||||||
"-" => -self.interpret(expr),
|
"-" => {
|
||||||
"not" => !self.interpret(expr),
|
let Value::Func(op_fn) = self.symbols.get("neg") else {
|
||||||
_ => panic!("Unrecognized unary op {}", op),
|
panic!("Operator {} does not correspond to a function!", op);
|
||||||
|
};
|
||||||
|
op_fn(&[self.interpret(expr)])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let Value::Func(op_fn) = self.symbols.get(op) else {
|
||||||
|
panic!("Operator {} does not correspond to a function!", op);
|
||||||
|
};
|
||||||
|
op_fn(&[self.interpret(expr)])
|
||||||
|
}
|
||||||
},
|
},
|
||||||
BinaryOp(_, left, op, right) => match *op {
|
BinaryOp(_, left, op, right) => match *op {
|
||||||
"+" => self.interpret(left) + self.interpret(right),
|
|
||||||
"*" => self.interpret(left) * self.interpret(right),
|
|
||||||
"-" => self.interpret(left) - self.interpret(right),
|
|
||||||
"/" => self.interpret(left) / self.interpret(right),
|
|
||||||
"%" => self.interpret(left) % self.interpret(right),
|
|
||||||
"==" => Value::Bool(self.interpret(left) == self.interpret(right)),
|
|
||||||
"!=" => Value::Bool(self.interpret(left) != self.interpret(right)),
|
|
||||||
"<" => Value::Bool(self.interpret(left) < self.interpret(right)),
|
|
||||||
"<=" => Value::Bool(self.interpret(left) <= self.interpret(right)),
|
|
||||||
">" => Value::Bool(self.interpret(left) > self.interpret(right)),
|
|
||||||
">=" => Value::Bool(self.interpret(left) >= self.interpret(right)),
|
|
||||||
"and" => {
|
"and" => {
|
||||||
let left_val = self.interpret(left);
|
let left_val = self.interpret(left);
|
||||||
if let Value::Bool(val_l) = left_val {
|
if let Value::Bool(val_l) = left_val {
|
||||||
|
@ -83,7 +81,12 @@ impl<'source> Interpreter<'source> {
|
||||||
panic!("Assignment must have identifier as left expr!");
|
panic!("Assignment must have identifier as left expr!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Unrecognized binary op {}", op),
|
_ => {
|
||||||
|
let Value::Func(op_fn) = self.symbols.get(op) else {
|
||||||
|
panic!("Operator {} does not correspond to a function!", op);
|
||||||
|
};
|
||||||
|
op_fn(&[self.interpret(left), self.interpret(right)])
|
||||||
|
}
|
||||||
},
|
},
|
||||||
VarDeclaration(_, name, expr) => {
|
VarDeclaration(_, name, expr) => {
|
||||||
let value = self.interpret(expr);
|
let value = self.interpret(expr);
|
||||||
|
@ -121,7 +124,18 @@ impl<'source> Interpreter<'source> {
|
||||||
}
|
}
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
FunCall(_, name, args) => todo!(), // Functions are TODO
|
FunCall(_, name, args) => {
|
||||||
|
let mut arg_values = Vec::new();
|
||||||
|
for arg in args {
|
||||||
|
arg_values.push(self.interpret(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let Value::Func(function) = self.symbols.get(name) else {
|
||||||
|
panic!("Identifier {} does not correspond to a function!", name);
|
||||||
|
};
|
||||||
|
|
||||||
|
function(&arg_values)
|
||||||
|
}
|
||||||
Block(_, expressions) => {
|
Block(_, expressions) => {
|
||||||
self.symbols = SymTab {
|
self.symbols = SymTab {
|
||||||
locals: HashMap::new(),
|
locals: HashMap::new(),
|
||||||
|
|
|
@ -19,8 +19,24 @@ impl<'source> SymTab<'source> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_global() -> SymTab<'source> {
|
pub fn new_global() -> SymTab<'source> {
|
||||||
|
let locals = HashMap::from([
|
||||||
|
("+", Value::Func(Value::add)),
|
||||||
|
("*", Value::Func(Value::mul)),
|
||||||
|
("-", Value::Func(Value::sub)),
|
||||||
|
("/", Value::Func(Value::div)),
|
||||||
|
("%", Value::Func(Value::rem)),
|
||||||
|
("==", Value::Func(Value::eq)),
|
||||||
|
("!=", Value::Func(Value::neq)),
|
||||||
|
("<", Value::Func(Value::lt)),
|
||||||
|
("<=", Value::Func(Value::le)),
|
||||||
|
(">", Value::Func(Value::gt)),
|
||||||
|
(">=", Value::Func(Value::ge)),
|
||||||
|
("not", Value::Func(Value::not)),
|
||||||
|
("neg", Value::Func(Value::neg)),
|
||||||
|
]);
|
||||||
|
|
||||||
SymTab {
|
SymTab {
|
||||||
locals: HashMap::new(),
|
locals,
|
||||||
parent: None,
|
parent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
use std::{
|
use std::fmt;
|
||||||
fmt,
|
|
||||||
ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)]
|
#[derive(PartialEq, PartialOrd, Debug, Copy, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
|
Func(fn(&[Value]) -> Value),
|
||||||
None(),
|
None(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,111 +13,125 @@ impl fmt::Display for Value {
|
||||||
match self {
|
match self {
|
||||||
Value::Int(val) => write!(f, "{}", val),
|
Value::Int(val) => write!(f, "{}", val),
|
||||||
Value::Bool(val) => write!(f, "{}", val),
|
Value::Bool(val) => write!(f, "{}", val),
|
||||||
|
Value::Func(_) => write!(f, "<FunctionCall>"),
|
||||||
Value::None() => write!(f, "<Unit>"),
|
Value::None() => write!(f, "<Unit>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Value {
|
impl Value {
|
||||||
type Output = Self;
|
pub fn add(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self::Output {
|
let Value::Int(lhs) = args[0] else {
|
||||||
if let Value::Int(val1) = self {
|
|
||||||
if let Value::Int(val2) = other {
|
|
||||||
Value::Int(val1 + val2)
|
|
||||||
} else {
|
|
||||||
panic!("Can't apply + to non-ints!")
|
panic!("Can't apply + to non-ints!")
|
||||||
}
|
};
|
||||||
} else {
|
let Value::Int(rhs) = args[1] else {
|
||||||
panic!("Can't apply + to non-ints!")
|
panic!("Can't apply + to non-ints!")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mul for Value {
|
Value::Int(lhs + rhs)
|
||||||
type Output = Self;
|
}
|
||||||
|
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
pub fn mul(args: &[Self]) -> Self {
|
||||||
if let Value::Int(val1) = self {
|
assert_eq!(args.len(), 2);
|
||||||
if let Value::Int(val2) = other {
|
|
||||||
Value::Int(val1 * val2)
|
let Value::Int(lhs) = args[0] else {
|
||||||
} else {
|
|
||||||
panic!("Can't apply * to non-ints!")
|
panic!("Can't apply * to non-ints!")
|
||||||
}
|
};
|
||||||
} else {
|
let Value::Int(rhs) = args[1] else {
|
||||||
panic!("Can't apply * to non-ints!")
|
panic!("Can't apply * to non-ints!")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sub for Value {
|
Value::Int(lhs * rhs)
|
||||||
type Output = Self;
|
}
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
pub fn sub(args: &[Self]) -> Self {
|
||||||
if let Value::Int(val1) = self {
|
assert_eq!(args.len(), 2);
|
||||||
if let Value::Int(val2) = other {
|
|
||||||
Value::Int(val1 - val2)
|
let Value::Int(lhs) = args[0] else {
|
||||||
} else {
|
|
||||||
panic!("Can't apply - to non-ints!")
|
panic!("Can't apply - to non-ints!")
|
||||||
}
|
};
|
||||||
} else {
|
let Value::Int(rhs) = args[1] else {
|
||||||
panic!("Can't apply - to non-ints!")
|
panic!("Can't apply - to non-ints!")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div for Value {
|
Value::Int(lhs - rhs)
|
||||||
type Output = Self;
|
}
|
||||||
|
|
||||||
fn div(self, other: Self) -> Self::Output {
|
pub fn div(args: &[Self]) -> Self {
|
||||||
if let Value::Int(val1) = self {
|
assert_eq!(args.len(), 2);
|
||||||
if let Value::Int(val2) = other {
|
|
||||||
Value::Int(val1 / val2)
|
let Value::Int(lhs) = args[0] else {
|
||||||
} else {
|
|
||||||
panic!("Can't apply / to non-ints!")
|
panic!("Can't apply / to non-ints!")
|
||||||
}
|
};
|
||||||
} else {
|
let Value::Int(rhs) = args[1] else {
|
||||||
panic!("Can't apply / to non-ints!")
|
panic!("Can't apply / to non-ints!")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Rem for Value {
|
Value::Int(lhs / rhs)
|
||||||
type Output = Self;
|
}
|
||||||
|
|
||||||
fn rem(self, other: Self) -> Self::Output {
|
pub fn rem(args: &[Self]) -> Self {
|
||||||
if let Value::Int(val1) = self {
|
assert_eq!(args.len(), 2);
|
||||||
if let Value::Int(val2) = other {
|
|
||||||
Value::Int(val1 % val2)
|
let Value::Int(lhs) = args[0] else {
|
||||||
} else {
|
|
||||||
panic!("Can't apply % to non-ints!")
|
panic!("Can't apply % to non-ints!")
|
||||||
}
|
};
|
||||||
} else {
|
let Value::Int(rhs) = args[1] else {
|
||||||
panic!("Can't apply % to non-ints!")
|
panic!("Can't apply % to non-ints!")
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Neg for Value {
|
Value::Int(lhs / rhs)
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
if let Value::Int(val) = self {
|
|
||||||
Value::Int(-val)
|
|
||||||
} else {
|
|
||||||
panic!("Can't apply - to non-ints!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eq(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] == args[1])
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Not for Value {
|
pub fn neq(args: &[Self]) -> Self {
|
||||||
type Output = Self;
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] != args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lt(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] < args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn le(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] <= args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gt(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] > args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ge(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
Value::Bool(args[0] >= args[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn not(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let Value::Bool(val) = args[0] else {
|
||||||
|
panic!("Can't apply 'not' to non-bools!")
|
||||||
|
};
|
||||||
|
|
||||||
fn not(self) -> Self::Output {
|
|
||||||
if let Value::Bool(val) = self {
|
|
||||||
Value::Bool(!val)
|
Value::Bool(!val)
|
||||||
} else {
|
|
||||||
panic!("Can't apply ! to non-bools!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn neg(args: &[Self]) -> Self {
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let Value::Int(val) = args[0] else {
|
||||||
|
panic!("Can't apply negation to non-ints!")
|
||||||
|
};
|
||||||
|
|
||||||
|
Value::Int(-val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue