diff --git a/src/main.rs b/src/main.rs index 23abaa5..dab6144 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,7 @@ mod vm; use crate::vm::*; pub fn main() { - let src = "[1, 2, 3]"; + let src = "let (x, 2) = (1, 2); x"; let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); if lex_errs.len() > 0 { println!("{:?}", lex_errs); diff --git a/src/parser.rs b/src/parser.rs index e087a39..6c8f035 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -197,6 +197,8 @@ where Token::Boolean(b) => Pattern::Boolean(b), Token::Number(n) => Pattern::Number(n), Token::Keyword(k) => Pattern::Keyword(k), + // todo: actual string patterns + Token::String(s) => Pattern::String(s) } .map_with(|a, e| (a, e.span())); diff --git a/src/vm.rs b/src/vm.rs index 69d5cc4..6027412 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -5,7 +5,7 @@ use std::rc::Rc; #[derive(Clone, Debug)] pub struct LudusError { - msg: String, + msg: &'static str, } // oy @@ -19,6 +19,8 @@ pub struct LudusError { // 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> { @@ -35,6 +37,70 @@ impl<'src> Ctx<'src> { } } +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>)>, @@ -46,10 +112,14 @@ pub fn eval<'src, 'a>( 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) => { @@ -82,6 +152,13 @@ pub fn eval<'src, 'a>( }; 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" }), + } + } _ => todo!(), } }