ariadne hooked up to panic messages
This commit is contained in:
parent
b2e08fe207
commit
5e73c5cb3b
19
src/main.rs
19
src/main.rs
|
@ -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>()
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user