diff --git a/src/main.rs b/src/main.rs index dab6144..1bb9f81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,7 @@ mod vm; use crate::vm::*; pub fn main() { - let src = "let (x, 2) = (1, 2); x"; + let src = "when { false -> :false, true -> :true}"; 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 6c8f035..899b703 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,6 +3,12 @@ use crate::spans::*; use chumsky::{input::ValueInput, prelude::*, recursive::Recursive}; use std::fmt; +#[derive(Clone, Debug, PartialEq)] +pub struct WhenClause<'src> { + pub cond: Spanned>, + pub body: Spanned>, +} + #[derive(Clone, Debug, PartialEq)] pub enum Ast<'src> { Error, @@ -23,8 +29,7 @@ pub enum Ast<'src> { Let(Box>>, Box>), Box(&'src str, Box>), Synthetic(Box>, Box>, Vec>), - WhenClause(Box>, Box>), - When(Vec>), + When(Vec>>), MatchClause(Box>>, Box>), Match(Box>, Vec>), FnClause(Box>>, Box>), @@ -382,7 +387,7 @@ where .clone() .then_ignore(just(Token::Punctuation("->"))) .then(expr.clone()) - .map_with(|(cond, body), e| (Ast::WhenClause(Box::new(cond), Box::new(body)), e.span())); + .map_with(|(cond, body), e| (WhenClause { cond, body }, e.span())); let when = just(Token::Reserved("when")) .ignore_then( diff --git a/src/value.rs b/src/value.rs index 2deb170..539902c 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,6 +1,7 @@ use crate::parser::*; use crate::spans::*; use imbl::*; +use std::cell::RefCell; use std::fmt; use std::rc::Rc; @@ -31,6 +32,7 @@ pub enum Value<'src> { List(Rc>), // ref-counted, immutable, persistent Dict(Rc>), + Box(&'src str, Box), // Fn(Rc>), // Set(HashSet), // Sets are hard @@ -55,6 +57,7 @@ impl<'src> Clone for Value<'src> { Value::Tuple(t) => Value::Tuple(t.clone()), Value::List(l) => Value::List(l.clone()), Value::Dict(d) => Value::Dict(d.clone()), + Value::Box(name, b) => Value::Box(name, b.clone()), } } } @@ -85,6 +88,7 @@ impl<'src> fmt::Display for Value<'src> { .join(", ") ), Value::Dict(d) => write!(f, "#{{{:?}}}", d), + Value::Box(name, b) => write!(f, "box {} [ {} ]", name, b), } } } diff --git a/src/vm.rs b/src/vm.rs index d98705a..c5988ad 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -5,7 +5,7 @@ use std::rc::Rc; #[derive(Clone, Debug)] pub struct LudusError { - msg: &'static str, + msg: String, } // oy @@ -156,7 +156,9 @@ pub fn eval<'src, 'a>( let val = eval(&expr.0, ctx)?; match matchh(&patt.0, &val, ctx) { Some(_) => Ok(val), - None => Err(LudusError { msg: "No match" }), + None => Err(LudusError { + msg: "No match".to_string(), + }), } } Ast::Placeholder => todo!(), @@ -166,15 +168,45 @@ pub fn eval<'src, 'a>( Ast::Pair(_, _) => todo!(), Ast::Box(_, _) => todo!(), Ast::Synthetic(_, _, _) => todo!(), - Ast::When(_) => todo!(), - Ast::WhenClause(_, _) => todo!(), + Ast::When(clauses) => { + for clause in clauses.iter() { + let WhenClause { cond, body } = &clause.0; + if eval(&cond.0, ctx)?.bool() { + return eval(&body.0, ctx); + }; + } + return Err(LudusError { + msg: "no match".to_string(), + }); + } Ast::Match(_, _) => todo!(), Ast::MatchClause(_, _) => todo!(), Ast::Fn(_, _) => todo!(), Ast::FnDeclaration(_) => todo!(), Ast::FnClause(_, _) => todo!(), - Ast::Panic(_) => todo!(), - Ast::Repeat(_, _) => todo!(), + Ast::Panic(msg) => { + let msg = eval(&msg.0, ctx)?; + Err(LudusError { + msg: msg.to_string(), + }) + } + Ast::Repeat(times, body) => { + let mut times_num = 0; + match eval(×.0, ctx) { + Ok(Value::Number(n)) => { + times_num = n as usize; + } + _ => { + return Err(LudusError { + msg: "repeat may only take numbers".to_string(), + }) + } + } + for _ in 0..times_num { + let _ = eval(&body.0, ctx)?; + } + Ok(Value::Nil) + } Ast::Do(_) => todo!(), Ast::Loop(_, _) => todo!(), Ast::Recur(_) => todo!(),