diff --git a/src/base.rs b/src/base.rs index 0bf0993..687401a 100644 --- a/src/base.rs +++ b/src/base.rs @@ -4,7 +4,7 @@ use ran::ran_f64; use std::rc::Rc; #[derive(Clone, Debug)] -pub enum Base<'src> { +pub enum BaseFn<'src> { Nullary(fn() -> Value<'src>), Unary(fn(&Value<'src>) -> Value<'src>), Binary(fn(&Value<'src>, &Value<'src>) -> Value<'src>), @@ -572,59 +572,59 @@ pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> { pub fn base<'src>() -> Vec<(String, Value<'src>)> { let members = vec![ - ("add", Value::Base(Base::Binary(add))), - ("and", Value::Base(Base::Binary(and))), - ("append", Value::Base(Base::Binary(append))), - ("assoc", Value::Base(Base::Ternary(assoc))), - ("at", Value::Base(Base::Binary(at))), - ("atan_2", Value::Base(Base::Binary(atan_2))), - ("bool", Value::Base(Base::Unary(r#bool))), - ("ceil", Value::Base(Base::Unary(ceil))), - ("chars", Value::Base(Base::Unary(chars))), - ("concat", Value::Base(Base::Binary(concat))), - ("cos", Value::Base(Base::Unary(cos))), - ("count", Value::Base(Base::Unary(count))), - ("dec", Value::Base(Base::Unary(dec))), - ("dissoc", Value::Base(Base::Binary(dissoc))), - ("div", Value::Base(Base::Binary(div))), - ("doc!", Value::Base(Base::Unary(doc))), - ("downcase", Value::Base(Base::Unary(downcase))), - ("eq?", Value::Base(Base::Binary(eq))), - ("first", Value::Base(Base::Unary(first))), - ("floor", Value::Base(Base::Unary(floor))), - ("get", Value::Base(Base::Binary(get))), - ("gt?", Value::Base(Base::Binary(gt))), - ("gte?", Value::Base(Base::Binary(gte))), - ("inc", Value::Base(Base::Unary(inc))), - ("last", Value::Base(Base::Unary(last))), - ("list", Value::Base(Base::Unary(list))), - ("lt?", Value::Base(Base::Binary(lt))), - ("lte?", Value::Base(Base::Binary(lte))), - ("mod", Value::Base(Base::Binary(r#mod))), - ("mult", Value::Base(Base::Binary(mult))), - ("number", Value::Base(Base::Unary(number))), - ("or", Value::Base(Base::Binary(or))), + ("add", Value::Base(BaseFn::Binary(add))), + ("and", Value::Base(BaseFn::Binary(and))), + ("append", Value::Base(BaseFn::Binary(append))), + ("assoc", Value::Base(BaseFn::Ternary(assoc))), + ("at", Value::Base(BaseFn::Binary(at))), + ("atan_2", Value::Base(BaseFn::Binary(atan_2))), + ("bool", Value::Base(BaseFn::Unary(r#bool))), + ("ceil", Value::Base(BaseFn::Unary(ceil))), + ("chars", Value::Base(BaseFn::Unary(chars))), + ("concat", Value::Base(BaseFn::Binary(concat))), + ("cos", Value::Base(BaseFn::Unary(cos))), + ("count", Value::Base(BaseFn::Unary(count))), + ("dec", Value::Base(BaseFn::Unary(dec))), + ("dissoc", Value::Base(BaseFn::Binary(dissoc))), + ("div", Value::Base(BaseFn::Binary(div))), + ("doc!", Value::Base(BaseFn::Unary(doc))), + ("downcase", Value::Base(BaseFn::Unary(downcase))), + ("eq?", Value::Base(BaseFn::Binary(eq))), + ("first", Value::Base(BaseFn::Unary(first))), + ("floor", Value::Base(BaseFn::Unary(floor))), + ("get", Value::Base(BaseFn::Binary(get))), + ("gt?", Value::Base(BaseFn::Binary(gt))), + ("gte?", Value::Base(BaseFn::Binary(gte))), + ("inc", Value::Base(BaseFn::Unary(inc))), + ("last", Value::Base(BaseFn::Unary(last))), + ("list", Value::Base(BaseFn::Unary(list))), + ("lt?", Value::Base(BaseFn::Binary(lt))), + ("lte?", Value::Base(BaseFn::Binary(lte))), + ("mod", Value::Base(BaseFn::Binary(r#mod))), + ("mult", Value::Base(BaseFn::Binary(mult))), + ("number", Value::Base(BaseFn::Unary(number))), + ("or", Value::Base(BaseFn::Binary(or))), ("pi", Value::Number(std::f64::consts::PI)), - ("print!", Value::Base(Base::Unary(print))), - ("random", Value::Base(Base::Nullary(random))), - ("range", Value::Base(Base::Binary(range))), - ("rest", Value::Base(Base::Unary(rest))), - ("round", Value::Base(Base::Unary(round))), - ("show", Value::Base(Base::Unary(show))), - ("sin", Value::Base(Base::Unary(sin))), - ("slice", Value::Base(Base::Ternary(slice))), - ("split", Value::Base(Base::Binary(split))), - ("sqrt", Value::Base(Base::Unary(sqrt))), + ("print!", Value::Base(BaseFn::Unary(print))), + ("random", Value::Base(BaseFn::Nullary(random))), + ("range", Value::Base(BaseFn::Binary(range))), + ("rest", Value::Base(BaseFn::Unary(rest))), + ("round", Value::Base(BaseFn::Unary(round))), + ("show", Value::Base(BaseFn::Unary(show))), + ("sin", Value::Base(BaseFn::Unary(sin))), + ("slice", Value::Base(BaseFn::Ternary(slice))), + ("split", Value::Base(BaseFn::Binary(split))), + ("sqrt", Value::Base(BaseFn::Unary(sqrt))), ("sqrt_2", Value::Number(std::f64::consts::SQRT_2)), - ("store!", Value::Base(Base::Binary(store))), - ("sub", Value::Base(Base::Binary(sub))), - ("tan", Value::Base(Base::Unary(tan))), - ("trim", Value::Base(Base::Unary(trim))), - ("triml", Value::Base(Base::Unary(triml))), - ("trimr", Value::Base(Base::Unary(trimr))), - ("type", Value::Base(Base::Unary(r#type))), - ("unbox", Value::Base(Base::Unary(unbox))), - ("upcase", Value::Base(Base::Unary(upcase))), + ("store!", Value::Base(BaseFn::Binary(store))), + ("sub", Value::Base(BaseFn::Binary(sub))), + ("tan", Value::Base(BaseFn::Unary(tan))), + ("trim", Value::Base(BaseFn::Unary(trim))), + ("triml", Value::Base(BaseFn::Unary(triml))), + ("trimr", Value::Base(BaseFn::Unary(trimr))), + ("type", Value::Base(BaseFn::Unary(r#type))), + ("unbox", Value::Base(BaseFn::Unary(unbox))), + ("upcase", Value::Base(BaseFn::Unary(upcase))), ]; let pkg = Value::Dict(HashMap::from(members)); vec![("base".to_string(), pkg)] diff --git a/src/context.rs b/src/context.rs index f798ea4..90ad3bf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,5 +1,6 @@ use crate::base::*; use crate::parser::*; +use crate::spans::*; use crate::value::{Fn, Value}; use imbl::HashMap; use imbl::Vector; @@ -71,16 +72,17 @@ impl<'src> Context<'src> { } } - pub fn match_pattern(&mut self, patt: &Pattern, val: &Value<'src>) -> Option<&Context<'src>> { + pub fn match_pattern(&mut self, patt: &Ast, val: &Value<'src>) -> Option<&Context<'src>> { + use Ast::*; match (patt, val) { - (Pattern::Nil, Value::Nil) => Some(self), - (Pattern::Placeholder, _) => Some(self), - (Pattern::Number(x), Value::Number(y)) => self.match_eq(x, y), - (Pattern::Boolean(x), Value::Boolean(y)) => self.match_eq(x, y), - (Pattern::Keyword(x), Value::Keyword(y)) => self.match_eq(x, y), - (Pattern::String(x), Value::InternedString(y)) => self.match_eq(x, y), - (Pattern::String(x), Value::AllocatedString(y)) => self.match_eq(&x.to_string(), y), - (Pattern::Interpolated(_, StringMatcher(matcher)), Value::InternedString(y)) => { + (NilPattern, Value::Nil) => Some(self), + (PlaceholderPattern, _) => Some(self), + (NumberPattern(x), Value::Number(y)) => self.match_eq(x, y), + (BooleanPattern(x), Value::Boolean(y)) => self.match_eq(x, y), + (KeywordPattern(x), Value::Keyword(y)) => self.match_eq(x, y), + (StringPattern(x), Value::InternedString(y)) => self.match_eq(x, y), + (StringPattern(x), Value::AllocatedString(y)) => self.match_eq(&x.to_string(), y), + (InterpolatedPattern(_, StringMatcher(matcher)), Value::InternedString(y)) => { match matcher(y.to_string()) { Some(matches) => { let mut matches = matches @@ -98,11 +100,11 @@ impl<'src> Context<'src> { None => None, } } - (Pattern::Word(w), val) => { + (WordPattern(w), val) => { self.bind(w.to_string(), &val); Some(self) } - (Pattern::As(word, type_str), value) => { + (AsPattern(word, type_str), value) => { let ludus_type = r#type(value); let type_kw = Value::Keyword(type_str); if type_kw == ludus_type { @@ -112,16 +114,14 @@ impl<'src> Context<'src> { None } } - (Pattern::Tuple(x), Value::Tuple(y)) => { - let has_splat = x - .iter() - .any(|patt| matches!(patt, (Pattern::Splattern(_), _))); + (TuplePattern(x), Value::Tuple(y)) => { + let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _))); if x.len() > y.len() || (!has_splat && x.len() != y.len()) { return None; }; let to = self.locals.len(); for i in 0..x.len() { - if let Pattern::Splattern(patt) = &x[i].0 { + if let Splattern(patt) = &x[i].0 { let mut list = Vector::new(); for i in i..y.len() { list.push_back(y[i].clone()) @@ -135,16 +135,14 @@ impl<'src> Context<'src> { } Some(self) } - (Pattern::List(x), Value::List(y)) => { - let has_splat = x - .iter() - .any(|patt| matches!(patt, (Pattern::Splattern(_), _))); + (ListPattern(x), Value::List(y)) => { + let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _))); if x.len() > y.len() || (!has_splat && x.len() != y.len()) { return None; }; let to = self.locals.len(); for (i, (patt, _)) in x.iter().enumerate() { - if let Pattern::Splattern(patt) = &patt { + if let Splattern(patt) = &patt { let list = Value::List(y.skip(i)); self.match_pattern(&patt.0, &list); } else if self.match_pattern(patt, y.get(i).unwrap()).is_none() { @@ -157,10 +155,8 @@ impl<'src> Context<'src> { // TODO: optimize this on several levels // - [ ] opportunistic mutation // - [ ] get rid of all the pointer indirection in word splats - (Pattern::Dict(x), Value::Dict(y)) => { - let has_splat = x - .iter() - .any(|patt| matches!(patt, (Pattern::Splattern(_), _))); + (DictPattern(x), Value::Dict(y)) => { + let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _))); if x.len() > y.len() || (!has_splat && x.len() != y.len()) { return None; }; @@ -168,7 +164,7 @@ impl<'src> Context<'src> { let mut matched = vec![]; for (pattern, _) in x { match pattern { - Pattern::Pair(key, patt) => { + PairPattern(key, patt) => { if let Some(val) = y.get(key) { if self.match_pattern(&patt.0, val).is_none() { self.pop_to(to); @@ -180,8 +176,8 @@ impl<'src> Context<'src> { return None; }; } - Pattern::Splattern(pattern) => match pattern.0 { - Pattern::Word(w) => { + Splattern(pattern) => match pattern.0 { + WordPattern(w) => { // TODO: find a way to take ownership // this will ALWAYS make structural changes, because of this clone // we want opportunistic mutation if possible @@ -191,7 +187,7 @@ impl<'src> Context<'src> { } self.bind(w.to_string(), &Value::Dict(unmatched)); } - Pattern::Placeholder => (), + PlaceholderPattern => (), _ => unreachable!(), }, _ => unreachable!(), @@ -206,14 +202,15 @@ impl<'src> Context<'src> { pub fn match_clauses( &mut self, value: &Value<'src>, - clauses: &'src [MatchClause], + clauses: &'src [Spanned], ) -> LResult<'src> { { let parent = self.ast; let to = self.locals.len(); - for MatchClause { patt, body, guard } in clauses.iter() { + let mut clauses = clauses.iter(); + while let Some((Ast::MatchClause(patt, guard, body), _)) = clauses.next() { if let Some(_) = self.match_pattern(&patt.0, value) { - let pass_guard = match guard { + let pass_guard = match guard.as_ref() { None => true, Some((ast, _)) => { self.ast = ast; @@ -240,30 +237,31 @@ impl<'src> Context<'src> { } pub fn apply(&mut self, callee: Value<'src>, caller: Value<'src>) -> LResult<'src> { + use Value::*; match (callee, caller) { - (Value::Keyword(kw), Value::Dict(dict)) => { + (Keyword(kw), Dict(dict)) => { if let Some(val) = dict.get(kw) { Ok(val.clone()) } else { - Ok(Value::Nil) + Ok(Nil) } } - (Value::Dict(dict), Value::Keyword(kw)) => { + (Dict(dict), Keyword(kw)) => { if let Some(val) = dict.get(kw) { Ok(val.clone()) } else { - Ok(Value::Nil) + Ok(Nil) } } - (Value::Fn(f), Value::Tuple(args)) => { - let args = Value::Tuple(args); + (Fn(f), Tuple(args)) => { + let args = Tuple(args); self.match_clauses(&args, f.body) } - (Value::Fn(_f), Value::Args(_args)) => todo!(), - (_, Value::Keyword(_)) => Ok(Value::Nil), - (_, Value::Args(_)) => Err(LErr::new(format!("you may only call a function"))), - (Value::Base(f), Value::Tuple(args)) => match f { - Base::Nullary(f) => { + (Fn(_f), Args(_args)) => todo!(), + (_, Keyword(_)) => Ok(Nil), + (_, Args(_)) => Err(LErr::new(format!("you may only call a function"))), + (Base(f), Tuple(args)) => match f { + BaseFn::Nullary(f) => { let num_args = args.len(); if num_args != 0 { Err(LErr::new(format!( @@ -273,7 +271,7 @@ impl<'src> Context<'src> { Ok(f()) } } - Base::Unary(f) => { + BaseFn::Unary(f) => { let num_args = args.len(); if num_args != 1 { Err(LErr::new(format!( @@ -283,7 +281,7 @@ impl<'src> Context<'src> { Ok(f(&args[0])) } } - Base::Binary(r#fn) => { + BaseFn::Binary(r#fn) => { let num_args = args.len(); if num_args != 2 { Err(LErr::new(format!( @@ -293,7 +291,7 @@ impl<'src> Context<'src> { Ok(r#fn(&args[0], &args[1])) } } - Base::Ternary(f) => { + BaseFn::Ternary(f) => { let num_args = args.len(); if num_args != 3 { Err(LErr::new(format!( @@ -309,15 +307,16 @@ impl<'src> Context<'src> { } pub fn eval(&mut self) -> LResult<'src> { + use Ast::*; let root = self.ast; let result = match self.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::InternedString(s)), - Ast::Interpolated(parts) => { - let mut interpolated = String::new(); + Nil => Ok(Value::Nil), + Boolean(b) => Ok(Value::Boolean(*b)), + Number(n) => Ok(Value::Number(*n)), + Keyword(k) => Ok(Value::Keyword(k)), + String(s) => Ok(Value::InternedString(s)), + Interpolated(parts) => { + let mut interpolated = std::string::String::new(); for part in parts { match &part.0 { StringPart::Data(s) => interpolated.push_str(s.as_str()), @@ -330,7 +329,7 @@ impl<'src> Context<'src> { } Ok(Value::AllocatedString(Rc::new(interpolated))) } - Ast::Block(exprs) => { + Block(exprs) => { let parent = self.ast; let to = self.locals.len(); let mut result = Value::Nil; @@ -342,7 +341,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(result) } - Ast::If(cond, if_true, if_false) => { + If(cond, if_true, if_false) => { let parent = self.ast; self.ast = &cond.0; let truthy = self.eval()?.bool(); @@ -351,7 +350,7 @@ impl<'src> Context<'src> { self.ast = parent; result } - Ast::List(members) => { + List(members) => { let parent = self.ast; let mut vect = Vector::new(); for member in members { @@ -373,7 +372,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(Value::List(vect)) } - Ast::Tuple(members) => { + Tuple(members) => { let parent = self.ast; let mut vect = Vec::new(); for member in members { @@ -383,11 +382,11 @@ impl<'src> Context<'src> { self.ast = parent; Ok(Value::Tuple(Rc::new(vect))) } - Ast::Word(w) | Ast::Splat(w) => { + Word(w) | Ast::Splat(w) => { let val = self.resolve(&w.to_string())?; Ok(val) } - Ast::Let(patt, expr) => { + Let(patt, expr) => { let parent = self.ast; self.ast = &expr.0; let val = self.eval()?; @@ -398,9 +397,8 @@ impl<'src> Context<'src> { self.ast = parent; result } - Ast::Placeholder => Ok(Value::Placeholder), - Ast::Error => unreachable!(), - Ast::Arguments(a) => { + Placeholder => Ok(Value::Placeholder), + Arguments(a) => { let parent = self.ast; let mut args = vec![]; for (arg, _) in a.iter() { @@ -416,7 +414,7 @@ impl<'src> Context<'src> { self.ast = parent; result } - Ast::Dict(terms) => { + Dict(terms) => { let parent = self.ast; let mut dict = HashMap::new(); for term in terms { @@ -441,7 +439,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(Value::Dict(dict)) } - Ast::LBox(name, expr) => { + LBox(name, expr) => { let parent = self.ast; self.ast = &expr.0; let val = self.eval()?; @@ -450,7 +448,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(boxed) } - Ast::Synthetic(root, first, rest) => { + Synthetic(root, first, rest) => { let parent = self.ast; self.ast = &root.0; let root = self.eval()?; @@ -465,10 +463,12 @@ impl<'src> Context<'src> { self.ast = parent; Ok(curr) } - Ast::When(clauses) => { + When(clauses) => { let parent = self.ast; for clause in clauses.iter() { - let WhenClause { cond, body } = &clause.0; + let WhenClause(cond, body) = &clause.0 else { + unreachable!() + }; self.ast = &cond.0; if self.eval()?.bool() { self.ast = &body.0; @@ -479,7 +479,7 @@ impl<'src> Context<'src> { } Err(LErr::new(format!("no match"))) } - Ast::Match(value, clauses) => { + Match(value, clauses) => { let parent = self.ast; self.ast = &value.0; let value = self.eval()?; @@ -487,9 +487,9 @@ impl<'src> Context<'src> { self.ast = parent; result } - Ast::Fn(name, clauses, doc) => { + Fn(name, clauses, doc) => { let doc = doc.map(|s| s.to_string()); - let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> { + let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> { name: name.to_string(), body: clauses, doc, @@ -497,13 +497,13 @@ impl<'src> Context<'src> { self.bind(name.to_string(), &the_fn); Ok(the_fn) } - Ast::FnDeclaration(_name) => Ok(Value::Nil), - Ast::Panic(msg) => { + FnDeclaration(_name) => Ok(Value::Nil), + Panic(msg) => { self.ast = &msg.0; let msg = self.eval()?; Err(LErr::new(format!("{msg}"))) } - Ast::Repeat(times, body) => { + Repeat(times, body) => { let parent = self.ast; self.ast = ×.0; let times_num = match self.eval() { @@ -517,7 +517,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(Value::Nil) } - Ast::Do(terms) => { + Do(terms) => { let parent = self.ast; self.ast = &terms[0].0; let mut result = self.eval()?; @@ -530,10 +530,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(result) } - Ast::Pair(..) => { - unreachable!() - } - Ast::Loop(init, clauses) => { + Loop(init, clauses) => { let parent = self.ast; self.ast = &init.0; let mut args = self.eval()?; @@ -547,7 +544,7 @@ impl<'src> Context<'src> { } } } - Ast::Recur(args) => { + Recur(args) => { let parent = self.ast; let mut vect = Vec::new(); for arg in args { @@ -557,6 +554,7 @@ impl<'src> Context<'src> { self.ast = parent; Ok(Value::Recur(vect)) } + _ => unreachable!(), }; self.ast = root; result diff --git a/src/main.rs b/src/main.rs index 85a51d6..98a02a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -150,26 +150,25 @@ pub fn run(src: &'static str) { let mut valxor = validator::Validator::new(&ast, span, &dummy_prelude); - valxor.validate(); + // valxor.validate(); - dbg!(valxor); + // dbg!(valxor); - // let mut ctx = prelude(); - // ctx.ast = * + let mut ctx = prelude(); + ctx.ast = * - // let result = ctx.eval(); + let result = ctx.eval(); - // match result { - // Ok(result) => println!("{}", result), - // Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), - // } + match result { + Ok(result) => println!("{}", result), + Err(LErr { msg, .. }) => println!("Errors!\n{}", msg), + } } pub fn main() { let src = " -loop () with { - () -> :baz -} +let #{:a (x, y), :b [1, 2, (a, b)]} = #{:a (1, 2), :b [1, 2, (7, 8)]} +(x, y, a, b) "; run(src); // struct_scalpel::print_dissection_info::() diff --git a/src/validator.rs b/src/validator.rs index bd279db..b9bd39e 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -470,6 +470,7 @@ impl<'a> Validator<'a> { } // terminals can never be invalid Ast::Nil | Ast::Boolean(_) | Ast::Number(_) | Ast::Keyword(_) | Ast::String(_) => (), + _ => todo!(), }; self.ast = root; } diff --git a/src/value.rs b/src/value.rs index 89a0d5f..fa3456a 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,5 +1,6 @@ use crate::base::*; use crate::parser::*; +use crate::spans::*; use imbl::*; use std::cell::RefCell; use std::fmt; @@ -9,7 +10,7 @@ use struct_scalpel::Dissectible; #[derive(Clone, Debug)] pub struct Fn<'src> { pub name: String, - pub body: &'src Vec, + pub body: &'src Vec>, pub doc: Option, } @@ -29,7 +30,7 @@ pub enum Value<'src> { Dict(HashMap<&'static str, Self>), Box(&'static str, Rc>), Fn(Rc>), - Base(Base<'src>), + Base(BaseFn<'src>), Recur(Vec), // Set(HashSet), // Sets are hard