2024-11-01 03:53:48 +00:00
|
|
|
use crate::parser::*;
|
|
|
|
use crate::value::*;
|
|
|
|
use imbl::Vector;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct LudusError {
|
|
|
|
msg: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
// oy
|
|
|
|
// lifetimes are a mess
|
|
|
|
// I need 'src kind of everywhere
|
|
|
|
// But (maybe) using 'src in eval
|
|
|
|
// for ctx
|
|
|
|
// means I can't borrow it mutably
|
|
|
|
// I guess the question is how to get
|
|
|
|
// the branches for Ast::Block and Ast::If
|
|
|
|
// to work with a mutable borrow of ctx
|
|
|
|
pub struct Ctx<'src> {
|
2024-11-06 22:37:57 +00:00
|
|
|
pub locals: Vec<(&'src str, Value<'src>)>,
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
|
2024-11-06 22:37:57 +00:00
|
|
|
impl<'src> Ctx<'src> {
|
|
|
|
pub fn resolve(&self, name: &'src str) -> Value {
|
|
|
|
if let Some((_, val)) = self.locals.iter().rev().find(|(bound, _)| *bound == name) {
|
|
|
|
val.clone()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-06 22:37:57 +00:00
|
|
|
pub fn store(&mut self, name: &'src str, value: Value<'src>) {
|
|
|
|
self.locals.push((name, value));
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-06 22:37:57 +00:00
|
|
|
pub fn eval<'src, 'a>(
|
|
|
|
ast: &Ast<'src>,
|
|
|
|
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
|
|
|
|
) -> Result<Value<'src>, LudusError> {
|
2024-11-01 03:53:48 +00:00
|
|
|
match ast {
|
|
|
|
Ast::Nil => Ok(Value::Nil),
|
2024-11-06 22:37:57 +00:00
|
|
|
Ast::Boolean(b) => Ok(Value::Boolean(*b)),
|
|
|
|
Ast::Number(n) => Ok(Value::Number(*n)),
|
2024-11-01 03:53:48 +00:00
|
|
|
Ast::Keyword(k) => Ok(Value::Keyword(k.clone())),
|
|
|
|
Ast::String(s) => Ok(Value::String(s.clone())),
|
|
|
|
Ast::Block(exprs) => {
|
|
|
|
let mut result = Value::Nil;
|
|
|
|
for (expr, _) in exprs {
|
|
|
|
result = eval(expr, ctx)?;
|
|
|
|
}
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
Ast::If(cond, if_true, if_false) => {
|
2024-11-06 22:37:57 +00:00
|
|
|
let truthy = eval(&cond.0, ctx)?.bool();
|
2024-11-01 03:53:48 +00:00
|
|
|
if truthy {
|
|
|
|
let (if_true, _) = *if_true;
|
2024-11-06 22:37:57 +00:00
|
|
|
eval(&if_true, ctx)
|
2024-11-01 03:53:48 +00:00
|
|
|
} else {
|
2024-11-06 22:37:57 +00:00
|
|
|
let (if_false, _) = **if_false;
|
|
|
|
eval(&if_false, ctx)
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ast::List(members) => {
|
|
|
|
let mut vect = Vector::new();
|
|
|
|
for member in members {
|
2024-11-06 22:37:57 +00:00
|
|
|
vect.push_back(eval(&member.0, ctx)?)
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
Ok(Value::List(Rc::new(vect)))
|
|
|
|
}
|
|
|
|
Ast::Tuple(members) => {
|
|
|
|
let mut vect = Vec::new();
|
|
|
|
for member in members {
|
2024-11-06 22:37:57 +00:00
|
|
|
vect.push(eval(&member.0, ctx)?);
|
2024-11-01 03:53:48 +00:00
|
|
|
}
|
|
|
|
Ok(Value::Tuple(Rc::new(vect)))
|
|
|
|
}
|
2024-11-06 22:37:57 +00:00
|
|
|
Ast::Word(w) => {
|
|
|
|
let val = if let Some((_, value)) = ctx.iter().rev().find(|(name, _)| w == name) {
|
|
|
|
value.clone()
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
Ok(val)
|
|
|
|
}
|
2024-11-01 03:53:48 +00:00
|
|
|
_ => todo!(),
|
|
|
|
}
|
|
|
|
}
|