2022-09-06 13:52:29 +00:00
|
|
|
use std::{collections::HashMap, rc::Rc, cell::RefCell};
|
|
|
|
|
|
|
|
use num_complex::Complex64;
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
use crate::{value::Value, expr::{Stmt, Expr}, token::{TokenType, Token, OpType}, RuntimeError};
|
|
|
|
|
2022-09-06 13:52:29 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Environment {
|
2022-09-07 20:11:51 +00:00
|
|
|
parent: Option<EnvRef>,
|
2022-09-06 13:52:29 +00:00
|
|
|
map: HashMap<Rc<str>, Value>
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
type EnvRef = Rc<RefCell<Environment>>;
|
|
|
|
|
2022-09-06 13:52:29 +00:00
|
|
|
impl Environment {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self { parent: None, map: HashMap::new() }
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
pub fn wrap(self) -> EnvRef {
|
|
|
|
Rc::new(RefCell::new(self))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extend(parent: EnvRef) -> Self {
|
2022-09-06 13:52:29 +00:00
|
|
|
Self { parent: Some(parent), map: HashMap::new() }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get(&self, name: &str) -> Result<Value,()> {
|
2022-09-07 20:11:51 +00:00
|
|
|
let x = match self.map.get(name) {
|
2022-09-06 13:52:29 +00:00
|
|
|
Some(v) => Ok(v.clone()),
|
|
|
|
None => match self.parent {
|
|
|
|
Some(ref p) => p.borrow().get(name),
|
|
|
|
None => Err(())
|
|
|
|
}
|
2022-09-07 20:11:51 +00:00
|
|
|
};
|
|
|
|
println!("get {}: {:?}", name, x);
|
|
|
|
x
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn declare(&mut self, name: Rc<str>, value: Value) {
|
2022-09-07 20:11:51 +00:00
|
|
|
println!("declare {}: {:?}", name, value);
|
2022-09-06 13:52:29 +00:00
|
|
|
self.map.insert(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&mut self, name: Rc<str>, value: Value) -> Result<(),()> {
|
2022-09-07 20:11:51 +00:00
|
|
|
println!("set {}: {:?}", name, value);
|
2022-09-06 13:52:29 +00:00
|
|
|
match self.map.contains_key(&name) {
|
|
|
|
true => { self.map.insert(name, value); Ok(()) },
|
|
|
|
false => match self.parent {
|
|
|
|
Some(ref mut p) => p.borrow_mut().set(name, value),
|
|
|
|
None => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-07 22:10:43 +00:00
|
|
|
fn unwrap_ident_token<'a>(tok: &'a Token) -> &'a Rc<str> {
|
|
|
|
if let Token { ty: TokenType::Ident(s),.. } = tok {
|
|
|
|
s
|
|
|
|
} else {
|
|
|
|
unreachable!("precondition failed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
pub fn eval_stmt(stmt: &Stmt, env: EnvRef) -> Result<(), RuntimeError> {
|
2022-09-06 13:52:29 +00:00
|
|
|
match stmt {
|
|
|
|
Stmt::Expr{ expr }
|
|
|
|
=> drop(eval_expr(expr, env)),
|
2022-09-07 22:10:43 +00:00
|
|
|
Stmt::Let { lhs, rhs: None }
|
|
|
|
=> env.borrow_mut().declare(unwrap_ident_token(lhs).clone(), Value::Nil),
|
|
|
|
Stmt::Let { lhs, rhs: Some(rhs) } => {
|
2022-09-06 13:52:29 +00:00
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
2022-09-07 22:10:43 +00:00
|
|
|
env.borrow_mut().declare(unwrap_ident_token(lhs).clone(), r)
|
2022-09-06 13:52:29 +00:00
|
|
|
},
|
2022-09-07 20:11:51 +00:00
|
|
|
Stmt::Block { stmts } => {
|
|
|
|
let block_env = Environment::extend(env).wrap();
|
|
|
|
for stmt in stmts {
|
|
|
|
eval_stmt(stmt, block_env.clone())?
|
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
},
|
2022-09-07 20:11:51 +00:00
|
|
|
Stmt::If { if_clauses, else_clause } => {
|
|
|
|
for ic in if_clauses {
|
|
|
|
let cond = eval_expr(&ic.0, env.clone())?;
|
|
|
|
if cond.truthy() {
|
|
|
|
return eval_stmt(&ic.1, env.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ec) = else_clause {
|
|
|
|
return eval_stmt(&ec, env)
|
|
|
|
}
|
2022-09-07 22:10:43 +00:00
|
|
|
},
|
|
|
|
Stmt::For { var, expr, stmt } => {
|
|
|
|
let name = unwrap_ident_token(var);
|
|
|
|
let iter = eval_expr(expr, env.clone())?;
|
|
|
|
env.borrow_mut().declare(name.clone(), Value::Nil);
|
|
|
|
if let Ok(i) = iter.iter() {
|
|
|
|
for v in i {
|
|
|
|
let env = env.clone();
|
|
|
|
env.borrow_mut().set(name.clone(), v).expect("unreachable");
|
|
|
|
eval_stmt(&stmt, env)?;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(RuntimeError { message: "Cannot iterate this type".into(), pos: var.pos.clone() })
|
|
|
|
};
|
|
|
|
},
|
2022-09-06 13:52:29 +00:00
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-09-07 20:11:51 +00:00
|
|
|
pub fn eval_expr(expr: &Expr, env: EnvRef) -> Result<Value, RuntimeError> {
|
2022-09-06 13:52:29 +00:00
|
|
|
match expr {
|
2022-09-07 20:11:51 +00:00
|
|
|
Expr::Literal { value } => Ok(eval_literal(value)),
|
|
|
|
Expr::Ident { value } => eval_ident(value, env),
|
2022-09-06 13:52:29 +00:00
|
|
|
Expr::Binary { lhs, rhs, op } => match op.ty.get_op_type() {
|
2022-09-07 20:11:51 +00:00
|
|
|
Some(OpType::Assignment)
|
|
|
|
=> eval_assignment(lhs, rhs, op, env),
|
|
|
|
Some(OpType::Additive) | Some(OpType::Multiplicative)
|
|
|
|
=> eval_binary(lhs, rhs, op, env),
|
2022-09-06 13:52:29 +00:00
|
|
|
o => todo!("{:?}", o) // TODO other operations
|
|
|
|
},
|
|
|
|
e => todo!("{:?}", e) // TODO other expression types
|
|
|
|
}
|
2022-09-07 20:11:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_literal(token: &Token) -> Value {
|
|
|
|
match &token.ty {
|
|
|
|
TokenType::Nil => Value::Nil,
|
|
|
|
TokenType::True => Value::Bool(true),
|
|
|
|
TokenType::False => Value::Bool(false),
|
|
|
|
TokenType::Int(n) => Value::Int(*n),
|
|
|
|
TokenType::Float(f) => Value::Float(*f),
|
|
|
|
TokenType::ImFloat(f) => Value::Complex(Complex64::new(0.0, *f)),
|
|
|
|
TokenType::String(s) => Value::String(s.clone()),
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::Char(c) => Value::Char(*c),
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_ident(token: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
|
|
|
if let Token { ty: TokenType::Ident(name), ..} = token {
|
|
|
|
env.borrow_mut()
|
|
|
|
.get(name)
|
|
|
|
.map_err(|_| RuntimeError { message: "Variable not defined in scope".into(), pos: token.pos.clone() })
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_assignment(lhs: &Box<Expr>, rhs: &Box<Expr>, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
|
|
|
// lhs must be an identifier (checked in parser)
|
|
|
|
if let Expr::Ident{value: Token{ty: TokenType::Ident(name),..}} = &**lhs {
|
|
|
|
if op.ty == TokenType::Equal {
|
|
|
|
// plain assignment
|
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
|
|
|
env.borrow_mut()
|
|
|
|
.set(name.clone(), r)
|
|
|
|
.map_err(|_| RuntimeError { message: "Variable not declared before assignment".into(), pos: op.pos.clone() })?;
|
|
|
|
Ok(Value::Nil)
|
|
|
|
} else {
|
|
|
|
// compound assignment
|
|
|
|
let prev_value = env.borrow_mut()
|
|
|
|
.get(name)
|
|
|
|
.map_err(|_| RuntimeError { message: "Variable not defined in scope".into(), pos: op.pos.clone()})?;
|
|
|
|
let r = eval_expr(rhs, env.clone())?;
|
|
|
|
|
|
|
|
let result = match op.ty {
|
|
|
|
TokenType::PlusEqual => &prev_value + &r,
|
|
|
|
TokenType::MinusEqual => &prev_value - &r,
|
|
|
|
TokenType::StarEqual => &prev_value * &r,
|
|
|
|
TokenType::SlashEqual => &prev_value / &r,
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::PercentEqual => &prev_value % &r,
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!() // TODO more operations
|
|
|
|
}.map_err(|e| RuntimeError { message: e, pos: op.pos.clone() })?;
|
|
|
|
|
|
|
|
env.borrow_mut()
|
|
|
|
.set(name.clone(), result.clone()).expect("unreachable");
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval_binary(lhs: &Box<Expr>, rhs: &Box<Expr>, op: &Token, env: EnvRef) -> Result<Value, RuntimeError> {
|
|
|
|
let l = eval_expr(lhs, env.clone())?;
|
|
|
|
let r = eval_expr(rhs, env)?;
|
|
|
|
match op.ty {
|
|
|
|
TokenType::Plus => &l + &r,
|
|
|
|
TokenType::Minus => &l - &r,
|
|
|
|
TokenType::Star => &l * &r,
|
|
|
|
TokenType::Slash => &l / &r,
|
2022-09-07 22:10:43 +00:00
|
|
|
TokenType::Percent => &l % &r,
|
2022-09-07 20:11:51 +00:00
|
|
|
_ => todo!() // TODO other operations
|
|
|
|
}.map_err(|e| RuntimeError { message: e, pos: op.pos.clone() })
|
2022-09-06 13:52:29 +00:00
|
|
|
}
|