rudus/src/vm.rs

85 lines
2.3 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> {
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!(),
}
}