diff --git a/src/main.rs b/src/main.rs index 9f8b18d..6396abe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,9 @@ use crate::validator::*; mod process; use crate::process::*; +mod errors; +use crate::errors::*; + #[derive(Embed)] #[folder = "assets/"] struct Asset; @@ -176,17 +179,23 @@ pub fn run(src: &'static str) { match result { Ok(result) => println!("{}", result), - Err(LErr { msg, .. }) => println!("Ludus panicked!\n{}", msg), + Err(err) => report_panic(err, src), } } pub fn main() { let src = " -let guard = :nil -match :foo with { - :foo if guard -> :guarded - _ -> :unguarded +fn foo () -> { + let 12 = 34 } + +let quux = foo +let fuzz = :asdf + +fn bar () -> quux () +fn baz (...) -> bar (fuzz) + +baz (1, 2, 3) "; run(src); // struct_scalpel::print_dissection_info::() diff --git a/src/process.rs b/src/process.rs index 9a17888..069f162 100644 --- a/src/process.rs +++ b/src/process.rs @@ -10,26 +10,23 @@ use std::cell::RefCell; use std::rc::Rc; #[derive(Debug)] -pub struct LErr { +pub struct LErr<'src> { pub msg: String, - pub trace: Vec, + pub span: SimpleSpan, + pub trace: Vec<(Spanned, Spanned, Value<'src>, Value<'src>)>, } -impl LErr { - pub fn new(msg: String) -> LErr { +impl<'src> LErr<'src> { + pub fn new(msg: String, span: SimpleSpan) -> LErr<'src> { LErr { - msg: msg.to_string(), + msg, + span, trace: vec![], } } - - pub fn add_trace(mut self, fn_name: String) -> LErr { - self.trace.push(fn_name); - self - } } -type LResult<'src> = Result, LErr>; +type LResult<'src> = Result, LErr<'src>>; #[derive(Debug)] pub struct Process<'src> { @@ -50,12 +47,16 @@ impl<'src> Process<'src> { let resolved_prelude = self.prelude.iter().rev().find(|(name, _)| word == name); match resolved_prelude { Some((_, value)) => Ok(value.clone()), - None => Err(LErr::new(format!("unbound name {word}"))), + None => Err(LErr::new(format!("unbound name `{word}`"), self.span)), } } } } + pub fn panic(&self, msg: String) -> LResult<'src> { + Err(LErr::new(msg, self.span)) + } + pub fn bind(&mut self, word: String, value: &Value<'src>) { self.locals.push((word, value.clone())); } @@ -223,7 +224,7 @@ impl<'src> Process<'src> { return result; } } - Err(LErr::new("no match".to_string())) + self.panic("no match".to_string()) } } @@ -245,25 +246,35 @@ impl<'src> Process<'src> { } } (Fn(f), Tuple(args)) => { + // can't just use the `caller` value b/c borrow checker nonsense let args = Tuple(args); 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); + // match result { + // Err(mut err) => { + // let r#fn = Fn(f); + // err.trace.push(r#fn); + // Err(err) + // } + // Ok(res) => Ok(res), + // } result } // TODO: partially applied functions shnould work! In #15 (Fn(_f), Args(_args)) => todo!(), (_, Keyword(_)) => Ok(Nil), - (_, Args(_)) => Err(LErr::new("you may only call a function".to_string())), + (_, Args(_)) => Err(LErr::new( + "you may only call a function".to_string(), + self.span, + )), (Base(f), Tuple(args)) => match f { BaseFn::Nullary(f) => { let num_args = args.len(); if num_args != 0 { - Err(LErr::new(format!( - "wrong arity: expected 0 arguments, got {num_args}" - ))) + self.panic(format!("wrong arity: expected 0 arguments, got {num_args}")) } else { Ok(f()) } @@ -271,9 +282,7 @@ impl<'src> Process<'src> { BaseFn::Unary(f) => { let num_args = args.len(); if num_args != 1 { - Err(LErr::new(format!( - "wrong arity: expected 1 argument, got {num_args}" - ))) + self.panic(format!("wrong arity: expected 1 argument, got {num_args}")) } else { Ok(f(&args[0])) } @@ -281,9 +290,7 @@ impl<'src> Process<'src> { BaseFn::Binary(r#fn) => { let num_args = args.len(); if num_args != 2 { - Err(LErr::new(format!( - "wrong arity: expected 2 arguments, got {num_args}" - ))) + self.panic(format!("wrong arity: expected 2 arguments, got {num_args}")) } else { Ok(r#fn(&args[0], &args[1])) } @@ -291,9 +298,7 @@ impl<'src> Process<'src> { BaseFn::Ternary(f) => { let num_args = args.len(); if num_args != 3 { - Err(LErr::new(format!( - "wrong arity: expected 3 arguments, got {num_args}" - ))) + self.panic(format!("wrong arity: expected 3 arguments, got {num_args}")) } else { Ok(f(&args[0], &args[1], &args[2])) } @@ -355,9 +360,8 @@ impl<'src> Process<'src> { Ast::Splat(_) => match member_value { Value::List(list) => vect.append(list), _ => { - return Err(LErr::new( - "only lists may be splatted into lists".to_string(), - )) + return self + .panic("only lists may be splatted into lists".to_string()) } }, _ => vect.push_back(member_value), @@ -380,7 +384,7 @@ impl<'src> Process<'src> { let val = self.visit(expr)?; let result = match self.match_pattern(&patt.0, &val) { Some(_) => Ok(val), - None => Err(LErr::new("no match".to_string())), + None => self.panic("no match".to_string()), }; result } @@ -407,9 +411,7 @@ impl<'src> Process<'src> { (Ast::Splat(_), _) => { let resolved = self.visit(term)?; let Value::Dict(to_splat) = resolved else { - return Err(LErr::new( - "cannot splat non-dict into dict".to_string(), - )); + return self.panic("cannot splat non-dict into dict".to_string()); }; dict = to_splat.union(dict); } @@ -427,12 +429,28 @@ impl<'src> Process<'src> { Synthetic(root, first, rest) => { let root_val = self.visit(root)?; let first_val = self.visit(first)?; - let mut curr = self.apply(root_val, first_val)?; + 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(); for term in rest.iter() { - let next = self.visit(term)?; - curr = self.apply(curr, next)?; + 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); + } } - Ok(curr) + result } When(clauses) => { for clause in clauses.iter() { @@ -443,7 +461,7 @@ impl<'src> Process<'src> { return self.visit(body); }; } - Err(LErr::new("no match".to_string())) + self.panic("no match".to_string()) } Match(scrutinee, clauses) => { let value = self.visit(scrutinee)?; @@ -473,12 +491,12 @@ impl<'src> Process<'src> { FnDeclaration(_name) => Ok(Value::Nil), Panic(msg) => { let msg = self.visit(msg)?; - Err(LErr::new(format!("{msg}"))) + self.panic(format!("{msg}")) } Repeat(times, body) => { let times_num = match self.visit(times) { Ok(Value::Number(n)) => n as usize, - _ => return Err(LErr::new("`repeat` may only take numbers".to_string())), + _ => return self.panic("`repeat` may only take numbers".to_string()), }; for _ in 0..times_num { self.visit(body)?;