use crate::parser::*; use crate::value::*; use imbl::Vector; use std::rc::Rc; #[derive(Clone, Debug)] pub struct LudusError { msg: &'static str, } // 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> { pub locals: Vec<(&'src str, Value<'src>)>, // pub names: Vec<&'src str>, // pub values: Vec>, } 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!() } } pub fn store(&mut self, name: &'src str, value: Value<'src>) { self.locals.push((name, value)); } } pub fn match_eq(x: T, y: T, z: U) -> Option where T: PartialEq, { if x == y { Some(z) } else { None } } pub fn matchh<'src, 'a>( patt: &Pattern<'src>, val: &Value<'src>, ctx: &'a mut Vec<(&'src str, Value<'src>)>, ) -> Option<&'a mut Vec<(&'src str, Value<'src>)>> { match (patt, val) { (Pattern::Nil, Value::Nil) => Some(ctx), (Pattern::Placeholder, _) => Some(ctx), (Pattern::Number(x), Value::Number(y)) => match_eq(x, y, ctx), (Pattern::Boolean(x), Value::Boolean(y)) => match_eq(x, y, ctx), (Pattern::Keyword(x), Value::Keyword(y)) => match_eq(x, y, ctx), (Pattern::String(x), Value::String(y)) => match_eq(x, y, ctx), (Pattern::Word(w), val) => { ctx.push((w, val.clone())); Some(ctx) } // todo: add splats to these match clauses (Pattern::Tuple(x), Value::Tuple(y)) => { if x.len() != y.len() { return None; }; let to = ctx.len(); for i in 0..x.len() { if let None = matchh(&x[i].0, &y[i], ctx) { while ctx.len() > to { ctx.pop(); } return None; } } Some(ctx) } (Pattern::List(x), Value::List(y)) => { if x.len() != y.len() { return None; }; let to = ctx.len(); for i in 0..x.len() { if let None = matchh(&x[i].0, y.get(i).unwrap(), ctx) { while ctx.len() > to { ctx.pop(); } return None; } } Some(ctx) } (Pattern::Pair(_, _), _) => todo!("dictionary patterns still to do"), (Pattern::Dict(_), _) => todo!("dictionary patterns still to do"), _ => None, } } pub fn eval<'src, 'a>( ast: &Ast<'src>, ctx: &'a mut Vec<(&'src str, Value<'src>)>, ) -> Result, 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)), Ast::String(s) => Ok(Value::String(s)), Ast::Block(exprs) => { let to = ctx.len(); let mut result = Value::Nil; for (expr, _) in exprs { result = eval(expr, ctx)?; } while ctx.len() > to { ctx.pop(); } Ok(result) } Ast::If(cond, if_true, if_false) => { let truthy = eval(&cond.0, ctx)?.bool(); if truthy { eval(&if_true.0, ctx) } else { eval(&if_false.0, 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) => { let val = if let Some((_, value)) = ctx.iter().rev().find(|(name, _)| w == name) { value.clone() } else { unreachable!() }; Ok(val) } Ast::Let(patt, expr) => { let val = eval(&expr.0, ctx)?; match matchh(&patt.0, &val, ctx) { Some(_) => Ok(val), None => Err(LudusError { msg: "No match" }), } } Ast::Error => todo!(), Ast::Dict(_) => todo!(), Ast::Arguments(_) => todo!(), Ast::Pair(_, _) => todo!(), Ast::Box(_, _) => todo!(), Ast::Synthetic(_, _, _) => todo!(), Ast::When(_) => todo!(), Ast::WhenClause(_, _) => todo!(), Ast::Match(_, _) => todo!(), Ast::MatchClause(_, _) => todo!(), Ast::Fn(_, _) => todo!(), Ast::FnDeclaration(_) => todo!(), Ast::FnClause(_, _) => todo!(), Ast::Panic(_) => todo!(), Ast::Repeat(_, _) => todo!(), Ast::Do(_) => todo!(), Ast::Loop(_, _) => todo!(), Ast::Recur(_) => todo!(), } }