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> {
|
|
|
|
locals: Vec<(&'src str, Value)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ctx {
|
|
|
|
pub fn resolve(&self, name: &str) -> Value {
|
|
|
|
let len = self.local_names.len();
|
|
|
|
let mut value = Value::Nil;
|
|
|
|
for i in (0..len).rev() {
|
|
|
|
if self.local_names[i] == name {
|
|
|
|
value = self.local_values[i].clone();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
value
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn store(&mut self, name: &'static str, value: Value) {
|
|
|
|
self.local_names.push(name);
|
|
|
|
self.local_values.push(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn eval<'src>(ast: Ast<'src>, ctx: &mut Ctx) -> Result<Value, LudusError> {
|
|
|
|
match ast {
|
|
|
|
Ast::Nil => Ok(Value::Nil),
|
|
|
|
Ast::Boolean(b) => Ok(Value::Boolean(b)),
|
|
|
|
Ast::Number(n) => Ok(Value::Number(n)),
|
|
|
|
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) => {
|
|
|
|
let truthy = eval((*cond).0, ctx)?.bool();
|
|
|
|
if truthy {
|
|
|
|
let (if_true, _) = *if_true;
|
|
|
|
eval(if_true, ctx)
|
|
|
|
} else {
|
|
|
|
let (if_false, _) = *if_false;
|
|
|
|
eval(if_false, ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ast::List(members) => {
|
|
|
|
let mut vect = Vector::new();
|
|
|
|
for member in members {
|
|
|
|
vect.push_back(eval(member.0, ctx)?)
|
|
|
|
}
|
|
|
|
Ok(Value::List(Rc::new(vect)))
|
|
|
|
}
|
|
|
|
Ast::Tuple(members) => {
|
|
|
|
let mut vect = Vec::new();
|
|
|
|
for member in members {
|
|
|
|
vect.push(eval(member.0, ctx)?);
|
|
|
|
}
|
|
|
|
Ok(Value::Tuple(Rc::new(vect)))
|
|
|
|
}
|
|
|
|
Ast::Word(w) => Ok(ctx.resolve(w)),
|
|
|
|
_ => todo!(),
|
|
|
|
}
|
|
|
|
}
|