rudus/src/process.rs

540 lines
20 KiB
Rust
Raw Normal View History

2024-12-09 04:33:46 +00:00
use crate::base::*;
use crate::parser::*;
2024-12-11 03:26:52 +00:00
use crate::spans::*;
2024-12-11 21:43:13 +00:00
use crate::validator::FnInfo;
2024-12-11 20:42:50 +00:00
use crate::value::Value;
use chumsky::prelude::SimpleSpan;
2024-12-09 04:33:46 +00:00
use imbl::HashMap;
use imbl::Vector;
use std::cell::RefCell;
use std::rc::Rc;
2024-12-11 21:43:13 +00:00
#[derive(Debug)]
2024-12-12 05:31:57 +00:00
pub struct LErr<'src> {
2024-12-09 04:33:46 +00:00
pub msg: String,
2024-12-12 05:31:57 +00:00
pub span: SimpleSpan,
pub trace: Vec<(Spanned<Ast>, Spanned<Ast>, Value<'src>, Value<'src>)>,
2024-12-09 04:33:46 +00:00
}
2024-12-12 05:31:57 +00:00
impl<'src> LErr<'src> {
pub fn new(msg: String, span: SimpleSpan) -> LErr<'src> {
2024-12-09 04:33:46 +00:00
LErr {
2024-12-12 05:31:57 +00:00
msg,
span,
2024-12-09 04:33:46 +00:00
trace: vec![],
}
}
}
2024-12-12 05:31:57 +00:00
type LResult<'src> = Result<Value<'src>, LErr<'src>>;
2024-12-09 04:33:46 +00:00
2024-12-11 21:43:13 +00:00
#[derive(Debug)]
2024-12-11 20:42:50 +00:00
pub struct Process<'src> {
2024-12-09 04:33:46 +00:00
pub locals: Vec<(String, Value<'src>)>,
pub prelude: Vec<(String, Value<'src>)>,
pub ast: &'src Ast,
pub span: SimpleSpan,
2024-12-11 21:43:13 +00:00
pub fn_info: std::collections::HashMap<*const Ast, FnInfo>,
2024-12-09 04:33:46 +00:00
}
2024-12-11 20:42:50 +00:00
impl<'src> Process<'src> {
2024-12-09 04:33:46 +00:00
pub fn resolve(&self, word: &String) -> LResult<'src> {
let resolved_local = self.locals.iter().rev().find(|(name, _)| word == name);
match resolved_local {
Some((_, value)) => Ok(value.clone()),
None => {
let resolved_prelude = self.prelude.iter().rev().find(|(name, _)| word == name);
match resolved_prelude {
Some((_, value)) => Ok(value.clone()),
2024-12-12 05:31:57 +00:00
None => Err(LErr::new(format!("unbound name `{word}`"), self.span)),
2024-12-09 04:33:46 +00:00
}
}
}
}
2024-12-12 05:31:57 +00:00
pub fn panic(&self, msg: String) -> LResult<'src> {
Err(LErr::new(msg, self.span))
}
2024-12-09 04:33:46 +00:00
pub fn bind(&mut self, word: String, value: &Value<'src>) {
self.locals.push((word, value.clone()));
}
2024-12-11 20:42:50 +00:00
pub fn match_eq<T>(&self, x: T, y: T) -> Option<&Process<'src>>
2024-12-09 04:33:46 +00:00
where
T: PartialEq,
{
if x == y {
Some(self)
2024-12-09 04:33:46 +00:00
} else {
None
}
}
2024-12-11 20:42:50 +00:00
pub fn match_pattern(&mut self, patt: &Ast, val: &Value<'src>) -> Option<&Process<'src>> {
2024-12-11 03:26:52 +00:00
use Ast::*;
2024-12-09 04:33:46 +00:00
match (patt, val) {
2024-12-11 03:26:52 +00:00
(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)) => {
2024-12-09 04:33:46 +00:00
match matcher(y.to_string()) {
Some(matches) => {
let mut matches = matches
.iter()
.map(|(word, string)| {
(
word.clone(),
Value::AllocatedString(Rc::new(string.clone())),
)
})
.collect::<Vec<_>>();
self.locals.append(&mut matches);
Some(self)
}
None => None,
}
}
2024-12-11 03:26:52 +00:00
(WordPattern(w), val) => {
2024-12-11 20:48:24 +00:00
self.bind(w.to_string(), val);
2024-12-09 04:33:46 +00:00
Some(self)
}
2024-12-11 03:26:52 +00:00
(AsPattern(word, type_str), value) => {
2024-12-09 04:33:46 +00:00
let ludus_type = r#type(value);
let type_kw = Value::Keyword(type_str);
if type_kw == ludus_type {
self.bind(word.to_string(), value);
Some(self)
} else {
None
}
}
2024-12-11 03:26:52 +00:00
(TuplePattern(x), Value::Tuple(y)) => {
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
2024-12-09 04:33:46 +00:00
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
return None;
};
let to = self.locals.len();
for i in 0..x.len() {
2024-12-11 03:26:52 +00:00
if let Splattern(patt) = &x[i].0 {
2024-12-09 04:33:46 +00:00
let mut list = Vector::new();
for i in i..y.len() {
list.push_back(y[i].clone())
}
let list = Value::List(list);
self.match_pattern(&patt.0, &list);
} else if self.match_pattern(&x[i].0, &y[i]).is_none() {
self.locals.truncate(to);
2024-12-09 04:33:46 +00:00
return None;
}
}
Some(self)
}
2024-12-11 03:26:52 +00:00
(ListPattern(x), Value::List(y)) => {
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
2024-12-09 04:33:46 +00:00
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() {
2024-12-11 03:26:52 +00:00
if let Splattern(patt) = &patt {
2024-12-09 04:33:46 +00:00
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() {
self.locals.truncate(to);
2024-12-09 04:33:46 +00:00
return None;
}
}
Some(self)
}
// TODO: optimize this on several levels
// - [ ] opportunistic mutation
// - [ ] get rid of all the pointer indirection in word splats
2024-12-11 03:26:52 +00:00
(DictPattern(x), Value::Dict(y)) => {
let has_splat = x.iter().any(|patt| matches!(patt, (Splattern(_), _)));
2024-12-09 04:33:46 +00:00
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
return None;
};
let to = self.locals.len();
let mut matched = vec![];
for (pattern, _) in x {
match pattern {
2024-12-11 03:26:52 +00:00
PairPattern(key, patt) => {
2024-12-09 04:33:46 +00:00
if let Some(val) = y.get(key) {
if self.match_pattern(&patt.0, val).is_none() {
self.locals.truncate(to);
2024-12-09 04:33:46 +00:00
return None;
} else {
matched.push(key);
}
} else {
return None;
};
}
2024-12-11 03:26:52 +00:00
Splattern(pattern) => match pattern.0 {
WordPattern(w) => {
2024-12-09 04:33:46 +00:00
// TODO: find a way to take ownership
// this will ALWAYS make structural changes, because of this clone
// we want opportunistic mutation if possible
let mut unmatched = y.clone();
for key in matched.iter() {
unmatched.remove(*key);
}
self.bind(w.to_string(), &Value::Dict(unmatched));
}
2024-12-11 03:26:52 +00:00
PlaceholderPattern => (),
2024-12-09 04:33:46 +00:00
_ => unreachable!(),
},
_ => unreachable!(),
}
}
Some(self)
}
_ => None,
}
}
pub fn match_clauses(
&mut self,
value: &Value<'src>,
2024-12-11 03:26:52 +00:00
clauses: &'src [Spanned<Ast>],
2024-12-09 04:33:46 +00:00
) -> LResult<'src> {
{
let root = self.ast;
2024-12-09 04:33:46 +00:00
let to = self.locals.len();
2024-12-11 03:26:52 +00:00
let mut clauses = clauses.iter();
while let Some((Ast::MatchClause(patt, guard, body), _)) = clauses.next() {
2024-12-11 20:48:24 +00:00
if self.match_pattern(&patt.0, value).is_some() {
2024-12-11 03:26:52 +00:00
let pass_guard = match guard.as_ref() {
2024-12-09 04:33:46 +00:00
None => true,
Some(guard_expr) => self.visit(guard_expr)?.bool(),
2024-12-09 04:33:46 +00:00
};
if !pass_guard {
self.locals.truncate(to);
2024-12-09 04:33:46 +00:00
continue;
}
let result = self.visit(body);
self.locals.truncate(to);
self.ast = root;
return result;
2024-12-09 04:33:46 +00:00
}
}
2024-12-12 05:31:57 +00:00
self.panic("no match".to_string())
2024-12-09 04:33:46 +00:00
}
}
pub fn apply(&mut self, callee: Value<'src>, caller: Value<'src>) -> LResult<'src> {
2024-12-11 03:26:52 +00:00
use Value::*;
2024-12-09 04:33:46 +00:00
match (callee, caller) {
2024-12-11 03:26:52 +00:00
(Keyword(kw), Dict(dict)) => {
2024-12-09 04:33:46 +00:00
if let Some(val) = dict.get(kw) {
Ok(val.clone())
} else {
2024-12-11 03:26:52 +00:00
Ok(Nil)
2024-12-09 04:33:46 +00:00
}
}
2024-12-11 03:26:52 +00:00
(Dict(dict), Keyword(kw)) => {
2024-12-09 04:33:46 +00:00
if let Some(val) = dict.get(kw) {
Ok(val.clone())
} else {
2024-12-11 03:26:52 +00:00
Ok(Nil)
2024-12-09 04:33:46 +00:00
}
}
2024-12-11 03:26:52 +00:00
(Fn(f), Tuple(args)) => {
2024-12-12 05:31:57 +00:00
// can't just use the `caller` value b/c borrow checker nonsense
2024-12-11 03:26:52 +00:00
let args = Tuple(args);
2024-12-11 21:43:13 +00:00
let to = self.locals.len();
let mut enclosing = f.enclosing.clone();
self.locals.append(&mut enclosing);
let result = self.match_clauses(&args, f.body);
self.locals.truncate(to);
2024-12-12 05:31:57 +00:00
// match result {
// Err(mut err) => {
// let r#fn = Fn(f);
// err.trace.push(r#fn);
// Err(err)
// }
// Ok(res) => Ok(res),
// }
2024-12-11 21:43:13 +00:00
result
2024-12-09 04:33:46 +00:00
}
2024-12-11 21:43:13 +00:00
// TODO: partially applied functions shnould work! In #15
2024-12-11 03:26:52 +00:00
(Fn(_f), Args(_args)) => todo!(),
(_, Keyword(_)) => Ok(Nil),
2024-12-12 05:31:57 +00:00
(_, Args(_)) => Err(LErr::new(
"you may only call a function".to_string(),
self.span,
)),
2024-12-11 03:26:52 +00:00
(Base(f), Tuple(args)) => match f {
BaseFn::Nullary(f) => {
2024-12-09 04:33:46 +00:00
let num_args = args.len();
if num_args != 0 {
2024-12-12 05:31:57 +00:00
self.panic(format!("wrong arity: expected 0 arguments, got {num_args}"))
2024-12-09 04:33:46 +00:00
} else {
Ok(f())
}
}
2024-12-11 03:26:52 +00:00
BaseFn::Unary(f) => {
2024-12-09 04:33:46 +00:00
let num_args = args.len();
if num_args != 1 {
2024-12-12 05:31:57 +00:00
self.panic(format!("wrong arity: expected 1 argument, got {num_args}"))
2024-12-09 04:33:46 +00:00
} else {
Ok(f(&args[0]))
}
}
2024-12-11 03:26:52 +00:00
BaseFn::Binary(r#fn) => {
2024-12-09 04:33:46 +00:00
let num_args = args.len();
if num_args != 2 {
2024-12-12 05:31:57 +00:00
self.panic(format!("wrong arity: expected 2 arguments, got {num_args}"))
2024-12-09 04:33:46 +00:00
} else {
Ok(r#fn(&args[0], &args[1]))
}
}
2024-12-11 03:26:52 +00:00
BaseFn::Ternary(f) => {
2024-12-09 04:33:46 +00:00
let num_args = args.len();
if num_args != 3 {
2024-12-12 05:31:57 +00:00
self.panic(format!("wrong arity: expected 3 arguments, got {num_args}"))
2024-12-09 04:33:46 +00:00
} else {
Ok(f(&args[0], &args[1], &args[2]))
}
}
},
_ => unreachable!(),
}
}
pub fn visit(&mut self, node: &'src Spanned<Ast>) -> LResult<'src> {
let (expr, span) = node;
self.ast = expr;
self.span = *span;
self.eval()
}
2024-12-09 04:33:46 +00:00
pub fn eval(&mut self) -> LResult<'src> {
2024-12-11 03:26:52 +00:00
use Ast::*;
2024-12-12 00:13:06 +00:00
let (root_node, root_span) = (self.ast, self.span);
let result = match root_node {
2024-12-11 03:26:52 +00:00
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();
2024-12-09 04:33:46 +00:00
for part in parts {
match &part.0 {
StringPart::Data(s) => interpolated.push_str(s.as_str()),
StringPart::Word(w) => {
let val = self.resolve(w)?;
interpolated.push_str(val.interpolate().as_str())
}
StringPart::Inline(_) => unreachable!(),
}
}
Ok(Value::AllocatedString(Rc::new(interpolated)))
}
2024-12-11 03:26:52 +00:00
Block(exprs) => {
2024-12-09 04:33:46 +00:00
let to = self.locals.len();
let mut result = Value::Nil;
for expr in exprs {
result = self.visit(expr)?;
2024-12-09 04:33:46 +00:00
}
self.locals.truncate(to);
2024-12-09 04:33:46 +00:00
Ok(result)
}
2024-12-11 03:26:52 +00:00
If(cond, if_true, if_false) => {
let truthy = self.visit(cond)?;
let to_visit = if truthy.bool() { if_true } else { if_false };
self.visit(to_visit)
2024-12-09 04:33:46 +00:00
}
2024-12-11 03:26:52 +00:00
List(members) => {
2024-12-09 04:33:46 +00:00
let mut vect = Vector::new();
for member in members {
let member_value = self.visit(member)?;
match member.0 {
Ast::Splat(_) => match member_value {
2024-12-09 04:33:46 +00:00
Value::List(list) => vect.append(list),
_ => {
2024-12-12 05:31:57 +00:00
return self
.panic("only lists may be splatted into lists".to_string())
2024-12-09 04:33:46 +00:00
}
},
_ => vect.push_back(member_value),
2024-12-09 04:33:46 +00:00
}
}
Ok(Value::List(vect))
}
2024-12-11 03:26:52 +00:00
Tuple(members) => {
2024-12-09 04:33:46 +00:00
let mut vect = Vec::new();
for member in members {
vect.push(self.visit(member)?);
2024-12-09 04:33:46 +00:00
}
Ok(Value::Tuple(Rc::new(vect)))
}
2024-12-11 03:26:52 +00:00
Word(w) | Ast::Splat(w) => {
2024-12-09 04:33:46 +00:00
let val = self.resolve(&w.to_string())?;
Ok(val)
}
2024-12-11 03:26:52 +00:00
Let(patt, expr) => {
let val = self.visit(expr)?;
2024-12-09 04:33:46 +00:00
let result = match self.match_pattern(&patt.0, &val) {
Some(_) => Ok(val),
2024-12-12 05:31:57 +00:00
None => self.panic("no match".to_string()),
2024-12-09 04:33:46 +00:00
};
result
}
2024-12-11 03:26:52 +00:00
Placeholder => Ok(Value::Placeholder),
Arguments(a) => {
2024-12-09 04:33:46 +00:00
let mut args = vec![];
for arg in a.iter() {
args.push(self.visit(arg)?)
2024-12-09 04:33:46 +00:00
}
let result = if args.iter().any(|arg| matches!(arg, Value::Placeholder)) {
Ok(Value::Args(Rc::new(args)))
} else {
Ok(Value::Tuple(Rc::new(args)))
};
result
}
2024-12-11 03:26:52 +00:00
Dict(terms) => {
2024-12-09 04:33:46 +00:00
let mut dict = HashMap::new();
for term in terms {
match term {
(Ast::Pair(key, value), _) => {
dict.insert(*key, self.visit(value)?);
2024-12-09 04:33:46 +00:00
}
(Ast::Splat(_), _) => {
let resolved = self.visit(term)?;
2024-12-09 04:33:46 +00:00
let Value::Dict(to_splat) = resolved else {
2024-12-12 05:31:57 +00:00
return self.panic("cannot splat non-dict into dict".to_string());
2024-12-09 04:33:46 +00:00
};
dict = to_splat.union(dict);
}
_ => unreachable!(),
}
}
Ok(Value::Dict(dict))
}
2024-12-11 03:26:52 +00:00
LBox(name, expr) => {
let val = self.visit(expr)?;
2024-12-09 04:33:46 +00:00
let boxed = Value::Box(name, Rc::new(RefCell::new(val)));
self.bind(name.to_string(), &boxed);
Ok(boxed)
}
2024-12-11 03:26:52 +00:00
Synthetic(root, first, rest) => {
let root_val = self.visit(root)?;
let first_val = self.visit(first)?;
2024-12-12 05:31:57 +00:00
let mut result = self.apply(root_val.clone(), first_val.clone());
if let Err(mut err) = result {
err.trace
.push((*root.clone(), *first.clone(), root_val, first_val));
return Err(err);
};
let mut prev_node;
let mut this_node = first.as_ref();
2024-12-09 04:33:46 +00:00
for term in rest.iter() {
2024-12-12 05:31:57 +00:00
prev_node = this_node;
this_node = term;
let caller = self.visit(term)?;
let callee = result.unwrap();
result = self.apply(callee.clone(), caller.clone());
if let Err(mut err) = result {
err.trace
.push((prev_node.clone(), this_node.clone(), caller, callee));
return Err(err);
}
2024-12-09 04:33:46 +00:00
}
2024-12-12 05:31:57 +00:00
result
2024-12-09 04:33:46 +00:00
}
2024-12-11 03:26:52 +00:00
When(clauses) => {
2024-12-09 04:33:46 +00:00
for clause in clauses.iter() {
2024-12-11 03:26:52 +00:00
let WhenClause(cond, body) = &clause.0 else {
unreachable!()
};
if self.visit(cond)?.bool() {
return self.visit(body);
2024-12-09 04:33:46 +00:00
};
}
2024-12-12 05:31:57 +00:00
self.panic("no match".to_string())
2024-12-09 04:33:46 +00:00
}
Match(scrutinee, clauses) => {
let value = self.visit(scrutinee)?;
self.match_clauses(&value, clauses)
2024-12-09 04:33:46 +00:00
}
2024-12-11 03:26:52 +00:00
Fn(name, clauses, doc) => {
2024-12-09 04:33:46 +00:00
let doc = doc.map(|s| s.to_string());
let ptr: *const Ast = root_node;
2024-12-11 21:43:13 +00:00
let info = self.fn_info.get(&ptr).unwrap();
let FnInfo::Defined(_, _, enclosing) = info else {
2024-12-11 21:43:13 +00:00
unreachable!()
};
let enclosing = enclosing
.iter()
.filter(|binding| binding != name)
.map(|binding| (binding.clone(), self.resolve(binding).unwrap().clone()))
2024-12-11 21:43:13 +00:00
.collect();
2024-12-11 03:26:52 +00:00
let the_fn = Value::Fn::<'src>(Rc::new(crate::value::Fn::<'src> {
2024-12-09 04:33:46 +00:00
name: name.to_string(),
body: clauses,
doc,
2024-12-11 21:43:13 +00:00
enclosing,
2024-12-09 04:33:46 +00:00
}));
self.bind(name.to_string(), &the_fn);
Ok(the_fn)
}
2024-12-11 03:26:52 +00:00
FnDeclaration(_name) => Ok(Value::Nil),
Panic(msg) => {
let msg = self.visit(msg)?;
2024-12-12 05:31:57 +00:00
self.panic(format!("{msg}"))
2024-12-09 04:33:46 +00:00
}
2024-12-11 03:26:52 +00:00
Repeat(times, body) => {
let times_num = match self.visit(times) {
2024-12-09 04:33:46 +00:00
Ok(Value::Number(n)) => n as usize,
2024-12-12 05:31:57 +00:00
_ => return self.panic("`repeat` may only take numbers".to_string()),
2024-12-09 04:33:46 +00:00
};
for _ in 0..times_num {
self.visit(body)?;
2024-12-09 04:33:46 +00:00
}
Ok(Value::Nil)
}
2024-12-11 03:26:52 +00:00
Do(terms) => {
let mut result = self.visit(&terms[0])?;
for term in terms.iter().skip(1) {
let next = self.visit(term)?;
2024-12-09 04:33:46 +00:00
let arg = Value::Tuple(Rc::new(vec![result]));
result = self.apply(next, arg)?;
}
Ok(result)
}
2024-12-11 03:26:52 +00:00
Loop(init, clauses) => {
let mut args = self.visit(init)?;
2024-12-09 04:33:46 +00:00
loop {
let result = self.match_clauses(&args, clauses)?;
if let Value::Recur(recur_args) = result {
args = Value::Tuple(Rc::new(recur_args));
} else {
return Ok(result);
}
}
}
2024-12-11 03:26:52 +00:00
Recur(args) => {
2024-12-09 04:33:46 +00:00
let mut vect = Vec::new();
for arg in args {
vect.push(self.visit(arg)?);
2024-12-09 04:33:46 +00:00
}
Ok(Value::Recur(vect))
}
2024-12-11 03:26:52 +00:00
_ => unreachable!(),
2024-12-09 04:33:46 +00:00
};
self.ast = root_node;
self.span = root_span;
2024-12-09 04:33:46 +00:00
result
}
}