ariadne hooked up to panic messages

This commit is contained in:
Scott Richmond 2024-12-12 00:31:57 -05:00
parent b2e08fe207
commit 5e73c5cb3b
2 changed files with 72 additions and 45 deletions

View File

@ -59,6 +59,9 @@ use crate::validator::*;
mod process; mod process;
use crate::process::*; use crate::process::*;
mod errors;
use crate::errors::*;
#[derive(Embed)] #[derive(Embed)]
#[folder = "assets/"] #[folder = "assets/"]
struct Asset; struct Asset;
@ -176,17 +179,23 @@ pub fn run(src: &'static str) {
match result { match result {
Ok(result) => println!("{}", result), Ok(result) => println!("{}", result),
Err(LErr { msg, .. }) => println!("Ludus panicked!\n{}", msg), Err(err) => report_panic(err, src),
} }
} }
pub fn main() { pub fn main() {
let src = " let src = "
let guard = :nil fn foo () -> {
match :foo with { let 12 = 34
:foo if guard -> :guarded
_ -> :unguarded
} }
let quux = foo
let fuzz = :asdf
fn bar () -> quux ()
fn baz (...) -> bar (fuzz)
baz (1, 2, 3)
"; ";
run(src); run(src);
// struct_scalpel::print_dissection_info::<value::Value>() // struct_scalpel::print_dissection_info::<value::Value>()

View File

@ -10,26 +10,23 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug)] #[derive(Debug)]
pub struct LErr { pub struct LErr<'src> {
pub msg: String, pub msg: String,
pub trace: Vec<String>, pub span: SimpleSpan,
pub trace: Vec<(Spanned<Ast>, Spanned<Ast>, Value<'src>, Value<'src>)>,
} }
impl LErr { impl<'src> LErr<'src> {
pub fn new(msg: String) -> LErr { pub fn new(msg: String, span: SimpleSpan) -> LErr<'src> {
LErr { LErr {
msg: msg.to_string(), msg,
span,
trace: vec![], trace: vec![],
} }
} }
pub fn add_trace(mut self, fn_name: String) -> LErr {
self.trace.push(fn_name);
self
}
} }
type LResult<'src> = Result<Value<'src>, LErr>; type LResult<'src> = Result<Value<'src>, LErr<'src>>;
#[derive(Debug)] #[derive(Debug)]
pub struct Process<'src> { pub struct Process<'src> {
@ -50,12 +47,16 @@ impl<'src> Process<'src> {
let resolved_prelude = self.prelude.iter().rev().find(|(name, _)| word == name); let resolved_prelude = self.prelude.iter().rev().find(|(name, _)| word == name);
match resolved_prelude { match resolved_prelude {
Some((_, value)) => Ok(value.clone()), 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>) { pub fn bind(&mut self, word: String, value: &Value<'src>) {
self.locals.push((word, value.clone())); self.locals.push((word, value.clone()));
} }
@ -223,7 +224,7 @@ impl<'src> Process<'src> {
return result; 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)) => { (Fn(f), Tuple(args)) => {
// can't just use the `caller` value b/c borrow checker nonsense
let args = Tuple(args); let args = Tuple(args);
let to = self.locals.len(); let to = self.locals.len();
let mut enclosing = f.enclosing.clone(); let mut enclosing = f.enclosing.clone();
self.locals.append(&mut enclosing); self.locals.append(&mut enclosing);
let result = self.match_clauses(&args, f.body); let result = self.match_clauses(&args, f.body);
self.locals.truncate(to); 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 result
} }
// TODO: partially applied functions shnould work! In #15 // TODO: partially applied functions shnould work! In #15
(Fn(_f), Args(_args)) => todo!(), (Fn(_f), Args(_args)) => todo!(),
(_, Keyword(_)) => Ok(Nil), (_, 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 { (Base(f), Tuple(args)) => match f {
BaseFn::Nullary(f) => { BaseFn::Nullary(f) => {
let num_args = args.len(); let num_args = args.len();
if num_args != 0 { if num_args != 0 {
Err(LErr::new(format!( self.panic(format!("wrong arity: expected 0 arguments, got {num_args}"))
"wrong arity: expected 0 arguments, got {num_args}"
)))
} else { } else {
Ok(f()) Ok(f())
} }
@ -271,9 +282,7 @@ impl<'src> Process<'src> {
BaseFn::Unary(f) => { BaseFn::Unary(f) => {
let num_args = args.len(); let num_args = args.len();
if num_args != 1 { if num_args != 1 {
Err(LErr::new(format!( self.panic(format!("wrong arity: expected 1 argument, got {num_args}"))
"wrong arity: expected 1 argument, got {num_args}"
)))
} else { } else {
Ok(f(&args[0])) Ok(f(&args[0]))
} }
@ -281,9 +290,7 @@ impl<'src> Process<'src> {
BaseFn::Binary(r#fn) => { BaseFn::Binary(r#fn) => {
let num_args = args.len(); let num_args = args.len();
if num_args != 2 { if num_args != 2 {
Err(LErr::new(format!( self.panic(format!("wrong arity: expected 2 arguments, got {num_args}"))
"wrong arity: expected 2 arguments, got {num_args}"
)))
} else { } else {
Ok(r#fn(&args[0], &args[1])) Ok(r#fn(&args[0], &args[1]))
} }
@ -291,9 +298,7 @@ impl<'src> Process<'src> {
BaseFn::Ternary(f) => { BaseFn::Ternary(f) => {
let num_args = args.len(); let num_args = args.len();
if num_args != 3 { if num_args != 3 {
Err(LErr::new(format!( self.panic(format!("wrong arity: expected 3 arguments, got {num_args}"))
"wrong arity: expected 3 arguments, got {num_args}"
)))
} else { } else {
Ok(f(&args[0], &args[1], &args[2])) Ok(f(&args[0], &args[1], &args[2]))
} }
@ -355,9 +360,8 @@ impl<'src> Process<'src> {
Ast::Splat(_) => match member_value { Ast::Splat(_) => match member_value {
Value::List(list) => vect.append(list), Value::List(list) => vect.append(list),
_ => { _ => {
return Err(LErr::new( return self
"only lists may be splatted into lists".to_string(), .panic("only lists may be splatted into lists".to_string())
))
} }
}, },
_ => vect.push_back(member_value), _ => vect.push_back(member_value),
@ -380,7 +384,7 @@ impl<'src> Process<'src> {
let val = self.visit(expr)?; let val = self.visit(expr)?;
let result = match self.match_pattern(&patt.0, &val) { let result = match self.match_pattern(&patt.0, &val) {
Some(_) => Ok(val), Some(_) => Ok(val),
None => Err(LErr::new("no match".to_string())), None => self.panic("no match".to_string()),
}; };
result result
} }
@ -407,9 +411,7 @@ impl<'src> Process<'src> {
(Ast::Splat(_), _) => { (Ast::Splat(_), _) => {
let resolved = self.visit(term)?; let resolved = self.visit(term)?;
let Value::Dict(to_splat) = resolved else { let Value::Dict(to_splat) = resolved else {
return Err(LErr::new( return self.panic("cannot splat non-dict into dict".to_string());
"cannot splat non-dict into dict".to_string(),
));
}; };
dict = to_splat.union(dict); dict = to_splat.union(dict);
} }
@ -427,12 +429,28 @@ impl<'src> Process<'src> {
Synthetic(root, first, rest) => { Synthetic(root, first, rest) => {
let root_val = self.visit(root)?; let root_val = self.visit(root)?;
let first_val = self.visit(first)?; 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() { for term in rest.iter() {
let next = self.visit(term)?; prev_node = this_node;
curr = self.apply(curr, next)?; 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) => { When(clauses) => {
for clause in clauses.iter() { for clause in clauses.iter() {
@ -443,7 +461,7 @@ impl<'src> Process<'src> {
return self.visit(body); return self.visit(body);
}; };
} }
Err(LErr::new("no match".to_string())) self.panic("no match".to_string())
} }
Match(scrutinee, clauses) => { Match(scrutinee, clauses) => {
let value = self.visit(scrutinee)?; let value = self.visit(scrutinee)?;
@ -473,12 +491,12 @@ impl<'src> Process<'src> {
FnDeclaration(_name) => Ok(Value::Nil), FnDeclaration(_name) => Ok(Value::Nil),
Panic(msg) => { Panic(msg) => {
let msg = self.visit(msg)?; let msg = self.visit(msg)?;
Err(LErr::new(format!("{msg}"))) self.panic(format!("{msg}"))
} }
Repeat(times, body) => { Repeat(times, body) => {
let times_num = match self.visit(times) { let times_num = match self.visit(times) {
Ok(Value::Number(n)) => n as usize, 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 { for _ in 0..times_num {
self.visit(body)?; self.visit(body)?;