move patterns, clauses into AST

This commit is contained in:
Scott Richmond 2024-12-10 22:26:52 -05:00
parent cab1b3f173
commit f5a6facb1c
5 changed files with 144 additions and 145 deletions

View File

@ -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)]

View File

@ -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<Ast>],
) -> 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 = &times.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

View File

@ -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 = &ast;
let mut ctx = prelude();
ctx.ast = &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::<value::Value>()

View File

@ -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;
}

View File

@ -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<MatchClause>,
pub body: &'src Vec<Spanned<Ast>>,
pub doc: Option<String>,
}
@ -29,7 +30,7 @@ pub enum Value<'src> {
Dict(HashMap<&'static str, Self>),
Box(&'static str, Rc<RefCell<Self>>),
Fn(Rc<Fn<'src>>),
Base(Base<'src>),
Base(BaseFn<'src>),
Recur(Vec<Self>),
// Set(HashSet<Self>),
// Sets are hard