Error Messaging Redesign

This commit contains the following:

* New data types to support full tracebacks
* New traceback data type used across stl and ast
* Updates to tests
* fixes for error messaging in sym and some stl functions
This commit is contained in:
Ava Apples Affine 2023-05-23 22:06:11 +00:00
parent 91ad4eed12
commit 789349df48
24 changed files with 837 additions and 374 deletions

View file

@ -81,7 +81,8 @@ mod eval_tests {
let doc_tree = lex(&test_doc).unwrap();
match eval(&doc_tree, &mut syms) {
Err(e) => {
assert_eq!(e, "error in call to undefined: undefined symbol: undefined")
assert_eq!(e.0.first().unwrap().message,
"(is an undefined symbol)")
}
Ok(reduced) => {

View file

@ -1,7 +1,7 @@
mod func_tests {
use relish::ast::lex;
use relish::ast::{Args, Ctr, Seg, Symbol, ValueType};
use relish::ast::{SymTable, Type, UserFn};
use relish::ast::{Args, Ctr, Seg, Symbol, ValueType, Traceback};
use relish::ast::{SymTable, Type, UserFn, start_trace};
use std::rc::Rc;
#[test]
@ -13,7 +13,7 @@ mod func_tests {
docs: String::new(),
args: Args::Strict(vec![Type::Bool]),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
|a: &Seg, _: &mut SymTable| -> Result<Ctr, Traceback> {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
@ -104,7 +104,7 @@ mod func_tests {
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
|a: &Seg, _: &mut SymTable| -> Result<Ctr, Traceback> {
let inner = a;
if let Ctr::Bool(b) = *inner.car {
if b {
@ -113,7 +113,7 @@ mod func_tests {
Ok(Ctr::None)
}
} else {
Err("not a bool".to_string())
Err(start_trace(("", "not a bool".to_string()).into()))
}
},
)),
@ -153,7 +153,7 @@ mod func_tests {
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
|a: &Seg, _: &mut SymTable| -> Result<Ctr, Traceback> {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
@ -170,7 +170,11 @@ mod func_tests {
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
.unwrap()
.0
.first()
.unwrap()
.message,
"arg 1 expected to be bool".to_string(),
);
}
@ -200,7 +204,11 @@ mod func_tests {
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
.unwrap()
.0
.first()
.unwrap()
.message,
"expected 1 args. Got 2.".to_string(),
);
}
@ -226,7 +234,11 @@ mod func_tests {
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
.unwrap()
.0
.first()
.unwrap()
.message,
"expected 1 args. Got 0.".to_string(),
);
}
@ -240,7 +252,7 @@ mod func_tests {
args: Args::Strict(vec![Type::Bool]),
docs: String::new(),
value: ValueType::Internal(Rc::new(
|a: &Seg, _: &mut SymTable| -> Result<Ctr, String> {
|a: &Seg, _: &mut SymTable| -> Result<Ctr, Traceback> {
let inner = a;
let mut is_bool = false;
if let Ctr::Bool(_) = *inner.car {
@ -260,8 +272,12 @@ mod func_tests {
assert_eq!(
syms.call_symbol(&"test_func_in".to_string(), &args, true)
.err()
.unwrap(),
"error evaluating args: undefined symbol: undefined-symbol".to_string(),
.unwrap()
.0
.first()
.unwrap()
.message,
"(is an undefined symbol)".to_string(),
);
}
}

View file

@ -17,7 +17,7 @@ mod lex_tests {
fn test_bad_symbol() {
let document = String::from("(as@dd)");
let output: &str = "Problem lexing document: \"Unparsable token: as@dd\"";
assert_eq!(lex(&document).err().unwrap(), output.to_string(),);
assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),);
}
#[test]
@ -42,14 +42,14 @@ mod lex_tests {
fn test_unmatched_list_delim_flat() {
let document = String::from("(one two");
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
assert_eq!(lex(&document).err().unwrap(), output.to_string(),);
assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),);
}
#[test]
fn test_unmatched_list_delim_complex() {
let document = String::from("(one two (three)");
let output: &str = "Problem lexing document: \"Unmatched list delimiter in input\"";
assert_eq!(lex(&document).err().unwrap(), output.to_string(),);
assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),);
}
#[test]
@ -100,6 +100,6 @@ mod lex_tests {
fn test_bad_token_list() {
let document = String::from("(one t(wo)");
let output: &str = "Problem lexing document: \"list started in middle of another token\"";
assert_eq!(lex(&document).err().unwrap(), output.to_string(),);
assert_eq!(lex(&document).err().unwrap().0.first().unwrap().message, output.to_string(),);
}
}

View file

@ -132,8 +132,11 @@ mod append_lib_tests {
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
.err()
.unwrap()
.to_string(),
"error in call to car: argument is empty".to_string(),
.0
.first()
.unwrap()
.message,
"input is empty".to_string(),
);
}
@ -166,8 +169,11 @@ mod append_lib_tests {
*eval(&lex(&document.to_string()).unwrap(), &mut syms)
.err()
.unwrap()
.to_string(),
"error in call to cdr: argument is empty".to_string(),
.0
.first()
.unwrap()
.message,
"input is empty".to_string(),
);
}

View file

@ -163,8 +163,8 @@ mod bool_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to toggle: can only toggle a boolean".to_string()
s.0.first().unwrap().message,
"can only toggle a boolean".to_string()
);
let intermediate = *eval(&check_tree, &mut syms).unwrap();
if let Ctr::Seg(ref s) = intermediate {
@ -196,8 +196,8 @@ mod bool_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to toggle: cannot toggle a function".to_string()
s.0.first().unwrap().message,
"cannot toggle a function".to_string()
);
if let Ctr::String(ref s) = *eval(&check_tree, &mut syms).unwrap() {
assert_eq!(*s, "1".to_string());

View file

@ -233,8 +233,8 @@ mod control_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
assert_eq!(
eval(&test_tree, &mut syms).err().unwrap(),
"error in call to result: undefined symbol: result".to_string()
eval(&test_tree, &mut syms).err().unwrap().0.first().unwrap().message,
"(is an undefined symbol)".to_string()
);
}
}

View file

@ -80,8 +80,8 @@ mod decl_lib_tests {
let eval_result = eval(&lex(&doc3.to_string()).unwrap(), &mut syms);
if let Err(s) = eval_result {
assert_eq!(
s.to_string(),
"error in call to test: undefined symbol: test".to_string()
s.0.first().unwrap().message,
"(is an undefined symbol)".to_string()
);
} else {
assert!(false);

View file

@ -665,8 +665,8 @@ mod math_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to inc: can only increment an integer".to_string()
s.0.first().unwrap().message,
"expected tester to be an integer".to_string()
);
let intermediate = *eval(&check_tree, &mut syms).unwrap();
if let Ctr::Seg(ref s) = intermediate {
@ -698,8 +698,8 @@ mod math_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to inc: cannot increment a function".to_string()
s.0.first().unwrap().message,
"expected tester to be an integer".to_string()
);
if let Ctr::String(ref s) = *eval(&check_tree, &mut syms).unwrap() {
assert_eq!(*s, "1".to_string());
@ -768,8 +768,8 @@ mod math_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to dec: can only decrement an integer".to_string()
s.0.first().unwrap().message,
"expected tester to be an integer".to_string()
);
let intermediate = *eval(&check_tree, &mut syms).unwrap();
if let Ctr::Seg(ref s) = intermediate {
@ -801,8 +801,8 @@ mod math_lib_tests {
eval(&doc_tree, &mut syms).unwrap();
if let Err(s) = eval(&change_tree, &mut syms) {
assert_eq!(
s,
"error in call to dec: cannot decrement a function".to_string()
s.0.first().unwrap().message,
"expected tester to be an integer".to_string()
);
if let Ctr::String(ref s) = *eval(&check_tree, &mut syms).unwrap() {
assert_eq!(*s, "1".to_string());