rudus/src/vm.rs

90 lines
2.5 KiB
Rust
Raw Normal View History

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-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-06 22:37:57 +00:00
pub fn store(&mut self, name: &'src str, value: Value<'src>) {
self.locals.push((name, value));
}
}
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> {
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)),
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();
if truthy {
let (if_true, _) = *if_true;
2024-11-06 22:37:57 +00:00
eval(&if_true, ctx)
} else {
2024-11-06 22:37:57 +00:00
let (if_false, _) = **if_false;
eval(&if_false, ctx)
}
}
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)?)
}
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)?);
}
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)
}
_ => todo!(),
}
}