2022-02-14 16:32:07 -06:00
|
|
|
use std::ops;
|
2022-06-01 14:48:31 -05:00
|
|
|
use std::collections::HashMap;
|
2022-02-14 16:32:07 -06:00
|
|
|
|
|
|
|
use crate::parser;
|
|
|
|
use parser::Atom;
|
|
|
|
|
2022-06-01 14:48:31 -05:00
|
|
|
pub struct Env<'a> {
|
|
|
|
pub parent: Option<&'a Env<'a>>,
|
|
|
|
pub values: HashMap<String, Atom>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Env<'a> {
|
|
|
|
pub fn global() -> Self {
|
|
|
|
Env {
|
|
|
|
parent: None,
|
|
|
|
values: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn child(parent: &'a Env<'a>) -> Self {
|
|
|
|
Env {
|
|
|
|
parent: Some(parent),
|
|
|
|
values: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
2022-06-01 16:30:29 -05:00
|
|
|
pub fn lookup(&self, id: &str) -> Atom {
|
|
|
|
if let Some(a) = self.values.get(id) {
|
|
|
|
a.clone()
|
|
|
|
} else if let Some(parent) = self.parent {
|
|
|
|
parent.lookup(id)
|
|
|
|
} else {
|
|
|
|
panic!("Variable {} not in scope.", id)
|
|
|
|
}
|
|
|
|
}
|
2022-06-01 16:35:35 -05:00
|
|
|
pub fn set(&mut self, id: String, atom: Atom) {
|
|
|
|
self.values.insert(id, atom);
|
|
|
|
}
|
2022-06-01 16:30:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval(ast: &parser::Stmt, env: &mut Env) {
|
|
|
|
match &ast {
|
|
|
|
parser::Stmt::ReplPrint(expr) =>
|
|
|
|
println!("{}", eval_expr(expr, env)),
|
2022-06-01 16:35:35 -05:00
|
|
|
parser::Stmt::Assignment(id, expr) =>
|
|
|
|
env.set(id.clone(), eval_expr(expr, env)),
|
2022-06-01 16:30:29 -05:00
|
|
|
_ => todo!(),
|
|
|
|
}
|
2022-06-01 14:48:31 -05:00
|
|
|
}
|
|
|
|
|
2022-06-01 16:30:29 -05:00
|
|
|
pub fn eval_expr(ast: &parser::Expr, env: &Env) -> Atom {
|
2022-02-14 16:32:07 -06:00
|
|
|
match ast {
|
2022-06-01 16:30:29 -05:00
|
|
|
parser::Expr::Id(a) => env.lookup(a),
|
2022-02-14 16:32:07 -06:00
|
|
|
parser::Expr::Atom(a) => a.clone(),
|
2022-06-01 16:30:29 -05:00
|
|
|
parser::Expr::UnaryMinus(a) => -eval_expr(a, env),
|
|
|
|
parser::Expr::Plus(a, b) => eval_expr(a, env) + eval_expr(b, env),
|
|
|
|
parser::Expr::Minus(a, b) => eval_expr(a, env) - eval_expr(b, env),
|
|
|
|
parser::Expr::Mult(a, b) => eval_expr(a, env) * eval_expr(b, env),
|
|
|
|
parser::Expr::Div(a, b) => eval_expr(a, env) / eval_expr(b, env),
|
2022-02-14 16:32:07 -06:00
|
|
|
_ => panic!("Couldn't evalute expression {{ {:?} }}", ast),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Neg for Atom {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn neg(self) -> Self {
|
|
|
|
match self {
|
|
|
|
Atom::Num(a) => Atom::Num(-a),
|
|
|
|
_ => panic!("Can't negate non-numeral type!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Add for Atom {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, other: Self) -> Self {
|
|
|
|
match (self, other) {
|
|
|
|
(Atom::Num(a), Atom::Num(b)) => Atom::Num(a + b),
|
|
|
|
_ => panic!("Can't add non-numeral types!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Sub for Atom {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, other: Self) -> Self {
|
|
|
|
match (self, other) {
|
|
|
|
(Atom::Num(a), Atom::Num(b)) => Atom::Num(a - b),
|
|
|
|
_ => panic!("Can't subtract non-numeral types!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Mul for Atom {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn mul(self, other: Self) -> Self {
|
|
|
|
match (self, other) {
|
|
|
|
(Atom::Num(a), Atom::Num(b)) => Atom::Num(a * b),
|
|
|
|
_ => panic!("Can't multiply non-numeral types!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Div for Atom {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn div(self, other: Self) -> Self {
|
|
|
|
match (self, other) {
|
|
|
|
(Atom::Num(a), Atom::Num(b)) => Atom::Num(a / b),
|
|
|
|
_ => panic!("Can't divide non-numeral types!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|